Exemple #1
0
//|time|height |len(txs)|len(tx)|tx bytes|len(tx)|tx bytes|
func (pack *TxPack) Deserialize(data []byte) error {
	buff := bytes.NewBuffer(data)

	var err error
	err = binary.Read(buff, binary.LittleEndian, &pack.Time)

	if err != nil {
		return err
	}

	err = binary.Read(buff, binary.LittleEndian, &pack.Height)

	if err != nil {
		return err
	}

	var txSize uint32
	err = binary.Read(buff, binary.LittleEndian, &txSize)
	if err != nil {
		return err
	}

	pack.Txs = make([]*btcutil.Tx, txSize)

	// Loop for each transaction
	for i := uint32(0); i < txSize; i++ {
		// Get the length of the transaction in bytes
		var byteLength uint32
		err = binary.Read(buff, binary.LittleEndian, &byteLength)
		if err != nil {
			return err
		}
		// Make the buffer equal to the amount written (= len(tx)
		txBuff := make([]byte, byteLength)
		// Read the tx
		err = binary.Read(buff, binary.LittleEndian, &txBuff)
		if err != nil {
			return err
		}
		// Create a new transaction
		pack.Txs[i], err = btcutil.NewTxFromBytes(txBuff)
		if err != nil {
			return err
		}
	}

	return nil
}
Exemple #2
0
// TestTxErrors tests the error paths for the Tx API.
func TestTxErrors(t *testing.T) {
	// Serialize the test transaction.
	testTx := Block100000.Transactions[0]
	var testTxBuf bytes.Buffer
	err := testTx.Serialize(&testTxBuf)
	if err != nil {
		t.Errorf("Serialize: %v", err)
	}
	testTxBytes := testTxBuf.Bytes()

	// Truncate the transaction byte buffer to force errors.
	shortBytes := testTxBytes[:4]
	_, err = btcutil.NewTxFromBytes(shortBytes)
	if err != io.EOF {
		t.Errorf("NewTxFromBytes: did not get expected error - "+
			"got %v, want %v", err, io.EOF)
	}
}
Exemple #3
0
func (pack *TxPack) UnmarshalBinary(data []byte) error {
	buff := bytes.NewBuffer(data)

	var length int
	_, err := fmt.Fscanln(buff, &pack.time, &pack.height, &length)

	pack.txs = make([]*btcutil.Tx, length)
	for i := 0; i < length; i++ {
		var b []byte
		_, err = fmt.Fscanln(buff, &b)
		if err == nil {
			pack.txs[i], err = btcutil.NewTxFromBytes(b)
			fmt.Println("err from btc")
		}
	}

	return err
}
Exemple #4
0
// GetRawTransactionAsyncResult waits for the pending command in request -
// the reqsult of a previous GetRawTransactionAsync() call - and returns either
// the requested transaction, or an error.
func GetRawTransactionAsyncResult(request chan RawRPCResponse) (*btcutil.Tx,
	*btcjson.Error) {
	response := <-request

	var resultData string
	_, jsonErr := response.FinishUnmarshal(&resultData)
	if jsonErr != nil {
		return nil, jsonErr
	}
	serializedTx, err := hex.DecodeString(resultData)
	if err != nil {
		return nil, &btcjson.ErrDecodeHexString
	}
	utx, err := btcutil.NewTxFromBytes(serializedTx)
	if err != nil {
		return nil, &btcjson.ErrDeserialization
	}
	return utx, nil
}
Exemple #5
0
// NtfnRedeemingTx handles btcd redeemingtx notifications resulting from a
// transaction spending a watched outpoint.
func NtfnRedeemingTx(n btcjson.Cmd) error {
	cn, ok := n.(*btcws.RedeemingTxNtfn)
	if !ok {
		return fmt.Errorf("%v handler: unexpected type", n.Method())
	}

	rawTx, err := hex.DecodeString(cn.HexTx)
	if err != nil {
		return fmt.Errorf("%v handler: bad hexstring: %v", n.Method(), err)
	}
	tx, err := btcutil.NewTxFromBytes(rawTx)
	if err != nil {
		return fmt.Errorf("%v handler: bad transaction bytes: %v", n.Method(), err)
	}

	block, txIdx, err := parseBlock(cn.Block)
	if err != nil {
		return fmt.Errorf("%v handler: bad block: %v", n.Method(), err)
	}
	tx.SetIndex(txIdx)
	return AcctMgr.RecordSpendingTx(tx, block)
}
Exemple #6
0
// TestNewTxFromBytes tests creation of a Tx from serialized bytes.
func TestNewTxFromBytes(t *testing.T) {
	// Serialize the test transaction.
	testTx := Block100000.Transactions[0]
	var testTxBuf bytes.Buffer
	err := testTx.Serialize(&testTxBuf)
	if err != nil {
		t.Errorf("Serialize: %v", err)
	}
	testTxBytes := testTxBuf.Bytes()

	// Create a new transaction from the serialized bytes.
	tx, err := btcutil.NewTxFromBytes(testTxBytes)
	if err != nil {
		t.Errorf("NewTxFromBytes: %v", err)
		return
	}

	// Ensure the generated MsgTx is correct.
	if msgTx := tx.MsgTx(); !reflect.DeepEqual(msgTx, testTx) {
		t.Errorf("MsgTx: mismatched MsgTx - got %v, want %v",
			spew.Sdump(msgTx), spew.Sdump(testTx))
	}
}
Exemple #7
0
// NtfnRecvTx handles the btcws.RecvTxNtfn notification.
func NtfnRecvTx(n btcjson.Cmd) error {
	rtx, ok := n.(*btcws.RecvTxNtfn)
	if !ok {
		return fmt.Errorf("%v handler: unexpected type", n.Method())
	}

	bs, err := GetCurBlock()
	if err != nil {
		return fmt.Errorf("%v handler: cannot get current block: %v", n.Method(), err)
	}

	rawTx, err := hex.DecodeString(rtx.HexTx)
	if err != nil {
		return fmt.Errorf("%v handler: bad hexstring: %v", n.Method(), err)
	}
	tx, err := btcutil.NewTxFromBytes(rawTx)
	if err != nil {
		return fmt.Errorf("%v handler: bad transaction bytes: %v", n.Method(), err)
	}

	block, txIdx, err := parseBlock(rtx.Block)
	if err != nil {
		return fmt.Errorf("%v handler: bad block: %v", n.Method(), err)
	}
	tx.SetIndex(txIdx)

	// For transactions originating from this wallet, the sent tx history should
	// be recorded before the received history.  If wallet created this tx, wait
	// for the sent history to finish being recorded before continuing.
	//
	// TODO(jrick) this is wrong due to tx malleability.  Cannot safely use the
	// txsha as an identifier.
	req := SendTxHistSyncRequest{
		txsha:    *tx.Sha(),
		response: make(chan SendTxHistSyncResponse),
	}
	SendTxHistSyncChans.access <- req
	resp := <-req.response
	if resp.ok {
		// Wait until send history has been recorded.
		<-resp.c
		SendTxHistSyncChans.remove <- *tx.Sha()
	}

	// For every output, find all accounts handling that output address (if any)
	// and record the received txout.
	for outIdx, txout := range tx.MsgTx().TxOut {
		var accounts []*Account
		_, addrs, _, _ := btcscript.ExtractPkScriptAddrs(txout.PkScript, cfg.Net())
		for _, addr := range addrs {
			a, err := AcctMgr.AccountByAddress(addr)
			if err != nil {
				continue
			}
			accounts = append(accounts, a)
		}

		for _, a := range accounts {
			txr, err := a.TxStore.InsertTx(tx, block)
			if err != nil {
				return err
			}
			cred, err := txr.AddCredit(uint32(outIdx), false)
			if err != nil {
				return err
			}
			AcctMgr.ds.ScheduleTxStoreWrite(a)

			// Notify frontends of tx.  If the tx is unconfirmed, it is always
			// notified and the outpoint is marked as notified.  If the outpoint
			// has already been notified and is now in a block, a txmined notifiction
			// should be sent once to let frontends that all previous send/recvs
			// for this unconfirmed tx are now confirmed.
			op := *cred.OutPoint()
			previouslyNotifiedReq := NotifiedRecvTxRequest{
				op:       op,
				response: make(chan NotifiedRecvTxResponse),
			}
			NotifiedRecvTxChans.access <- previouslyNotifiedReq
			if <-previouslyNotifiedReq.response {
				NotifiedRecvTxChans.remove <- op
			} else {
				// Notify frontends of new recv tx and mark as notified.
				NotifiedRecvTxChans.add <- op

				ltr, err := cred.ToJSON(a.Name(), bs.Height, a.Wallet.Net())
				if err != nil {
					return err
				}
				NotifyNewTxDetails(allClients, a.Name(), ltr)
			}

			// Notify frontends of new account balance.
			confirmed := a.CalculateBalance(1)
			unconfirmed := a.CalculateBalance(0) - confirmed
			NotifyWalletBalance(allClients, a.name, confirmed)
			NotifyWalletBalanceUnconfirmed(allClients, a.name, unconfirmed)
		}
	}

	return nil
}
Exemple #8
0
func TestMinPrioritySelector(t *testing.T) {
	testCoinSelector(minPriorityTests, t)
}

var (
	// should be two outpoints, with 1st one having 0.035BTC value.
	testSimpleCoinNumConfs            = int64(1)
	testSimpleCoinTxHash              = "9b5965c86de51d5dc824e179a05cf232db78c80ae86ca9d7cb2a655b5e19c1e2"
	testSimpleCoinTxHex               = "0100000001a214a110f79e4abe073865ea5b3745c6e82c913bad44be70652804a5e4003b0a010000008c493046022100edd18a69664efa57264be207100c203e6cade1888cbb88a0ad748548256bb2f0022100f1027dc2e6c7f248d78af1dd90027b5b7d8ec563bb62aa85d4e74d6376f3868c0141048f3757b65ed301abd1b0e8942d1ab5b50594d3314cff0299f300c696376a0a9bf72e74710a8af7a5372d4af4bb519e2701a094ef48c8e48e3b65b28502452dceffffffff02e0673500000000001976a914686dd149a79b4a559d561fbc396d3e3c6628b98d88ace86ef102000000001976a914ac3f995655e81b875b38b64351d6f896ddbfc68588ac00000000"
	testSimpleCoinTxValue0            = btcutil.Amount(3500000)
	testSimpleCoinTxValueAge0         = int64(testSimpleCoinTxValue0) * testSimpleCoinNumConfs
	testSimpleCoinTxPkScript0Hex      = "76a914686dd149a79b4a559d561fbc396d3e3c6628b98d88ac"
	testSimpleCoinTxPkScript0Bytes, _ = hex.DecodeString(testSimpleCoinTxPkScript0Hex)
	testSimpleCoinTxBytes, _          = hex.DecodeString(testSimpleCoinTxHex)
	testSimpleCoinTx, _               = btcutil.NewTxFromBytes(testSimpleCoinTxBytes)
	testSimpleCoin                    = &coinset.SimpleCoin{
		Tx:         testSimpleCoinTx,
		TxIndex:    0,
		TxNumConfs: testSimpleCoinNumConfs,
	}
)

func TestSimpleCoin(t *testing.T) {
	if testSimpleCoin.Hash().String() != testSimpleCoinTxHash {
		t.Error("Different value for tx hash than expected")
	}
	if testSimpleCoin.Index() != 0 {
		t.Error("Different value for index of outpoint than expected")
	}
	if testSimpleCoin.Value() != testSimpleCoinTxValue0 {
Exemple #9
0
func TestInsertsCreditsDebitsRollbacks(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)
	var _ = TstSpendingTx

	tests := []struct {
		name     string
		f        func(*Store) (*Store, error)
		bal, unc btcutil.Amount
		unspents map[btcwire.OutPoint]struct{}
		unmined  map[btcwire.ShaHash]struct{}
	}{
		{
			name: "new store",
			f: func(_ *Store) (*Store, error) {
				return New(), nil
			},
			bal:      0,
			unc:      0,
			unspents: map[btcwire.OutPoint]struct{}{},
			unmined:  map[btcwire.ShaHash]struct{}{},
		},
		{
			name: "txout insert",
			f: func(s *Store) (*Store, error) {
				r, err := s.InsertTx(TstRecvTx, nil)
				if err != nil {
					return nil, err
				}

				_, err = r.AddCredit(0, false)
				if err != nil {
					return nil, err
				}
				// Verify that we can create the JSON output without any
				// errors.
				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: 0,
			unc: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{},
		},
		{
			name: "insert duplicate unconfirmed",
			f: func(s *Store) (*Store, error) {
				r, err := s.InsertTx(TstRecvTx, nil)
				if err != nil {
					return nil, err
				}

				_, err = r.AddCredit(0, false)
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: 0,
			unc: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{},
		},
		{
			name: "confirmed txout insert",
			f: func(s *Store) (*Store, error) {
				TstRecvTx.SetIndex(TstRecvIndex)
				r, err := s.InsertTx(TstRecvTx, TstRecvTxBlockDetails)
				if err != nil {
					return nil, err
				}

				_, err = r.AddCredit(0, false)
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
			unc: 0,
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{},
		},
		{
			name: "insert duplicate confirmed",
			f: func(s *Store) (*Store, error) {
				TstRecvTx.SetIndex(TstRecvIndex)
				r, err := s.InsertTx(TstRecvTx, TstRecvTxBlockDetails)
				if err != nil {
					return nil, err
				}

				_, err = r.AddCredit(0, false)
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
			unc: 0,
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{},
		},
		{
			name: "rollback confirmed credit",
			f: func(s *Store) (*Store, error) {
				err := s.Rollback(TstRecvTxBlockDetails.Height)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: 0,
			unc: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{},
		},
		{
			name: "insert confirmed double spend",
			f: func(s *Store) (*Store, error) {
				TstDoubleSpendTx.SetIndex(TstRecvIndex)
				r, err := s.InsertTx(TstDoubleSpendTx, TstRecvTxBlockDetails)
				if err != nil {
					return nil, err
				}

				_, err = r.AddCredit(0, false)
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)

				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: btcutil.Amount(TstDoubleSpendTx.MsgTx().TxOut[0].Value),
			unc: 0,
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstDoubleSpendTx.Sha(), 0): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{},
		},
		{
			name: "insert unconfirmed debit",
			f: func(s *Store) (*Store, error) {
				prev, err := s.InsertTx(TstDoubleSpendTx, TstRecvTxBlockDetails)
				if err != nil {
					return nil, err
				}

				r, err := s.InsertTx(TstSpendingTx, nil)
				if err != nil {
					return nil, err
				}

				_, err = r.AddDebits(prev.Credits())
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal:      0,
			unc:      0,
			unspents: map[btcwire.OutPoint]struct{}{},
			unmined: map[btcwire.ShaHash]struct{}{
				*TstSpendingTx.Sha(): {},
			},
		},
		{
			name: "insert unconfirmed debit again",
			f: func(s *Store) (*Store, error) {
				prev, err := s.InsertTx(TstDoubleSpendTx, TstRecvTxBlockDetails)
				if err != nil {
					return nil, err
				}

				r, err := s.InsertTx(TstSpendingTx, nil)
				if err != nil {
					return nil, err
				}

				_, err = r.AddDebits(prev.Credits())
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal:      0,
			unc:      0,
			unspents: map[btcwire.OutPoint]struct{}{},
			unmined: map[btcwire.ShaHash]struct{}{
				*TstSpendingTx.Sha(): {},
			},
		},
		{
			name: "insert change (index 0)",
			f: func(s *Store) (*Store, error) {
				r, err := s.InsertTx(TstSpendingTx, nil)
				if err != nil {
					return nil, err
				}

				_, err = r.AddCredit(0, true)
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: 0,
			unc: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value),
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{
				*TstSpendingTx.Sha(): {},
			},
		},
		{
			name: "insert output back to this own wallet (index 1)",
			f: func(s *Store) (*Store, error) {
				r, err := s.InsertTx(TstSpendingTx, nil)
				if err != nil {
					return nil, err
				}

				_, err = r.AddCredit(1, true)
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: 0,
			unc: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value),
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): {},
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{
				*TstSpendingTx.Sha(): {},
			},
		},
		{
			name: "confirm signed tx",
			f: func(s *Store) (*Store, error) {
				TstSpendingTx.SetIndex(TstSignedTxIndex)
				r, err := s.InsertTx(TstSpendingTx, TstSignedTxBlockDetails)
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value),
			unc: 0,
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): {},
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{},
		},
		{
			name: "rollback after spending tx",
			f: func(s *Store) (*Store, error) {
				err := s.Rollback(TstSignedTxBlockDetails.Height + 1)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value),
			unc: 0,
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): {},
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{},
		},
		{
			name: "rollback spending tx block",
			f: func(s *Store) (*Store, error) {
				err := s.Rollback(TstSignedTxBlockDetails.Height)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: 0,
			unc: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value),
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): {},
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{
				*TstSpendingTx.Sha(): {},
			},
		},
		{
			name: "rollback double spend tx block",
			f: func(s *Store) (*Store, error) {
				err := s.Rollback(TstRecvTxBlockDetails.Height)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: 0,
			unc: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value),
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): {},
				*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{
				*TstSpendingTx.Sha(): {},
			},
		},
		{
			name: "insert original recv txout",
			f: func(s *Store) (*Store, error) {
				TstRecvTx.SetIndex(TstRecvIndex)
				r, err := s.InsertTx(TstRecvTx, TstRecvTxBlockDetails)
				if err != nil {
					return nil, err
				}

				_, err = r.AddCredit(0, false)
				if err != nil {
					return nil, err
				}

				_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
				if err != nil {
					return nil, err
				}
				return s, nil
			},
			bal: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
			unc: 0,
			unspents: map[btcwire.OutPoint]struct{}{
				*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): {},
			},
			unmined: map[btcwire.ShaHash]struct{}{},
		},
	}

	var s *Store
	for _, test := range tests {
		tmpStore, err := test.f(s)
		if err != nil {
			t.Fatalf("%s: got error: %v", test.name, err)
		}
		s = tmpStore
		bal, err := s.Balance(1, TstRecvCurrentHeight)
		if err != nil {
			t.Fatalf("%s: Confirmed Balance() failed: %v", test.name, err)
		}
		if bal != test.bal {
			t.Fatalf("%s: balance mismatch: expected: %d, got: %d", test.name, test.bal, bal)
		}
		unc, err := s.Balance(0, TstRecvCurrentHeight)
		if err != nil {
			t.Fatalf("%s: Unconfirmed Balance() failed: %v", test.name, err)
		}
		unc -= bal
		if unc != test.unc {
			t.Errorf("%s: unconfirmed balance mismatch: expected %d, got %d", test.name, test.unc, unc)
		}

		// Check that unspent outputs match expected.
		unspent, err := s.UnspentOutputs()
		if err != nil {
			t.Fatal(err)
		}
		for _, r := range unspent {
			if r.Spent() {
				t.Errorf("%s: unspent record marked as spent", test.name)
			}

			op := *r.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)
		}

		// Check that unmined sent txs match expected.
		for _, tx := range s.UnminedDebitTxs() {
			if _, ok := test.unmined[*tx.Sha()]; !ok {
				t.Fatalf("%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)
		}

		// 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)
		}
	}
}
Exemple #10
0
	"bytes"
	"encoding/hex"
	"testing"
	"time"

	"github.com/conformal/btcnet"
	"github.com/conformal/btcutil"
	. "github.com/conformal/btcwallet/txstore"
	"github.com/conformal/btcwire"
)

// Received transaction output for mainnet outpoint
// 61d3696de4c888730cbe06b0ad8ecb6d72d6108e893895aa9bc067bd7eba3fad:0
var (
	TstRecvSerializedTx, _          = hex.DecodeString("010000000114d9ff358894c486b4ae11c2a8cf7851b1df64c53d2e511278eff17c22fb7373000000008c493046022100995447baec31ee9f6d4ec0e05cb2a44f6b817a99d5f6de167d1c75354a946410022100c9ffc23b64d770b0e01e7ff4d25fbc2f1ca8091053078a247905c39fce3760b601410458b8e267add3c1e374cf40f1de02b59213a82e1d84c2b94096e22e2f09387009c96debe1d0bcb2356ffdcf65d2a83d4b34e72c62eccd8490dbf2110167783b2bffffffff0280969800000000001976a914479ed307831d0ac19ebc5f63de7d5f1a430ddb9d88ac38bfaa00000000001976a914dadf9e3484f28b385ddeaa6c575c0c0d18e9788a88ac00000000")
	TstRecvTx, _                    = btcutil.NewTxFromBytes(TstRecvSerializedTx)
	TstRecvTxSpendingTxBlockHash, _ = btcwire.NewShaHashFromStr("00000000000000017188b968a371bab95aa43522665353b646e41865abae02a4")
	TstRecvAmt                      = int64(10000000)
	TstRecvIndex                    = 684
	TstRecvTxBlockDetails           = &Block{
		Height: 276425,
		Hash:   *TstRecvTxSpendingTxBlockHash,
		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

	TstSpendingSerializedTx, _ = hex.DecodeString("0100000003ad3fba7ebd67c09baa9538898e10d6726dcb8eadb006be0c7388c8e46d69d361000000006b4830450220702c4fbde5532575fed44f8d6e8c3432a2a9bd8cff2f966c3a79b2245a7c88db02210095d6505a57e350720cb52b89a9b56243c15ddfcea0596aedc1ba55d9fb7d5aa0012103cccb5c48a699d3efcca6dae277fee6b82e0229ed754b742659c3acdfed2651f9ffffffffdbd36173f5610e34de5c00ed092174603761595d90190f790e79cda3e5b45bc2010000006b483045022000fa20735e5875e64d05bed43d81b867f3bd8745008d3ff4331ef1617eac7c44022100ad82261fc57faac67fc482a37b6bf18158da0971e300abf5fe2f9fd39e107f58012102d4e1caf3e022757512c204bf09ff56a9981df483aba3c74bb60d3612077c9206ffffffff65536c9d964b6f89b8ef17e83c6666641bc495cb27bab60052f76cd4556ccd0d040000006a473044022068e3886e0299ffa69a1c3ee40f8b6700f5f6d463a9cf9dbf22c055a131fc4abc02202b58957fe19ff1be7a84c458d08016c53fbddec7184ac5e633f2b282ae3420ae012103b4e411b81d32a69fb81178a8ea1abaa12f613336923ee920ffbb1b313af1f4d2ffffffff02ab233200000000001976a91418808b2fbd8d2c6d022aed5cd61f0ce6c0a4cbb688ac4741f011000000001976a914f081088a300c80ce36b717a9914ab5ec8a7d283988ac00000000")
	TstSpendingTx, _           = btcutil.NewTxFromBytes(TstSpendingSerializedTx)
	TstSpendingTxBlockHeight   = int32(279143)
Exemple #11
0
func TestFilterBloomMatch(t *testing.T) {
	str := "01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e" +
		"88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7" +
		"c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d2" +
		"7d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee" +
		"51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5e" +
		"eef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c33" +
		"9ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3" +
		"bc6e2754dbcff1988ac2f15de00000000001976a914a266436d296554760" +
		"8b9e15d9032a7b9d64fa43188ac00000000"
	strBytes, err := hex.DecodeString(str)
	if err != nil {
		t.Errorf("TestFilterBloomMatch DecodeString failure: %v", err)
		return
	}
	tx, err := btcutil.NewTxFromBytes(strBytes)
	if err != nil {
		t.Errorf("TestFilterBloomMatch NewTxFromBytes failure: %v", err)
		return
	}
	spendingTxBytes := []byte{0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f,
		0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6,
		0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27,
		0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f,
		0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30,
		0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce,
		0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57,
		0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0,
		0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c,
		0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00,
		0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e,
		0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27,
		0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01,
		0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10,
		0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9,
		0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5,
		0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff,
		0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf,
		0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9,
		0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb,
		0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b,
		0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76,
		0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07,
		0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0,
		0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8,
		0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14,
		0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51,
		0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70,
		0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}

	spendingTx, err := btcutil.NewTxFromBytes(spendingTxBytes)
	if err != nil {
		t.Errorf("TestFilterBloomMatch NewTxFromBytes failure: %v", err)
		return
	}

	f := bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr := "b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"
	sha, err := btcwire.NewShaHashFromStr(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch NewShaHashFromStr failed: %v\n", err)
		return
	}
	f.AddShaHash(sha)
	if !f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch didn't match sha %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4"
	shaBytes, err := hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch DecodeString failed: %v\n", err)
		return
	}
	f.Add(shaBytes)
	if !f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch didn't match sha %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065" +
		"f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643" +
		"ac4cb7cb3c462aced7f14711a01"
	shaBytes, err = hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch DecodeString failed: %v\n", err)
		return
	}
	f.Add(shaBytes)
	if !f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch didn't match input signature %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95" +
		"c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe" +
		"76036c339"
	shaBytes, err = hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch DecodeString failed: %v\n", err)
		return
	}
	f.Add(shaBytes)
	if !f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch didn't match input pubkey %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "04943fdd508053c75000106d3bc6e2754dbcff19"
	shaBytes, err = hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch DecodeString failed: %v\n", err)
		return
	}
	f.Add(shaBytes)
	if !f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch didn't match output address %s", inputStr)
	}
	if !f.MatchTxAndUpdate(spendingTx) {
		t.Errorf("TestFilterBloomMatch spendingTx didn't match output address %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "a266436d2965547608b9e15d9032a7b9d64fa431"
	shaBytes, err = hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch DecodeString failed: %v\n", err)
		return
	}
	f.Add(shaBytes)
	if !f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch didn't match output address %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"
	sha, err = btcwire.NewShaHashFromStr(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch NewShaHashFromStr failed: %v\n", err)
		return
	}
	outpoint := btcwire.NewOutPoint(sha, 0)
	f.AddOutPoint(outpoint)
	if !f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch didn't match outpoint %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436"
	sha, err = btcwire.NewShaHashFromStr(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch NewShaHashFromStr failed: %v\n", err)
		return
	}
	f.AddShaHash(sha)
	if f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch matched sha %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "0000006d2965547608b9e15d9032a7b9d64fa431"
	shaBytes, err = hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch DecodeString failed: %v\n", err)
		return
	}
	f.Add(shaBytes)
	if f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch matched address %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"
	sha, err = btcwire.NewShaHashFromStr(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch NewShaHashFromStr failed: %v\n", err)
		return
	}
	outpoint = btcwire.NewOutPoint(sha, 1)
	f.AddOutPoint(outpoint)
	if f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch matched outpoint %s", inputStr)
	}

	f = bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateAll)
	inputStr = "000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"
	sha, err = btcwire.NewShaHashFromStr(inputStr)
	if err != nil {
		t.Errorf("TestFilterBloomMatch NewShaHashFromStr failed: %v\n", err)
		return
	}
	outpoint = btcwire.NewOutPoint(sha, 0)
	f.AddOutPoint(outpoint)
	if f.MatchTxAndUpdate(tx) {
		t.Errorf("TestFilterBloomMatch matched outpoint %s", inputStr)
	}
}