Example #1
0
// maybeAddOutpoint potentially adds the passed outpoint to the bloom filter
// depending on the bloom update flags and the type of the passed public key
// script.
//
// This function MUST be called with the filter lock held.
func (bf *Filter) maybeAddOutpoint(pkScript []byte, outHash *btcwire.ShaHash, outIdx uint32) {
	switch bf.msgFilterLoad.Flags {
	case btcwire.BloomUpdateAll:
		outpoint := btcwire.NewOutPoint(outHash, outIdx)
		bf.addOutPoint(outpoint)
	case btcwire.BloomUpdateP2PubkeyOnly:
		class := btcscript.GetScriptClass(pkScript)
		if class == btcscript.PubKeyTy || class == btcscript.MultiSigTy {
			outpoint := btcwire.NewOutPoint(outHash, outIdx)
			bf.addOutPoint(outpoint)
		}
	}
}
Example #2
0
func TestFilterInsertUpdateNone(t *testing.T) {
	f := bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateNone)

	// Add the generation pubkey
	inputStr := "04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c" +
		"876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a" +
		"2252247d97a46a91"
	inputBytes, err := hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterInsertUpdateNone DecodeString failed: %v", err)
		return
	}
	f.Add(inputBytes)

	// Add the output address for the 4th transaction
	inputStr = "b6efd80d99179f4f4ff6f4dd0a007d018c385d21"
	inputBytes, err = hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterInsertUpdateNone DecodeString failed: %v", err)
		return
	}
	f.Add(inputBytes)

	inputStr = "147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"
	sha, err := btcwire.NewShaHashFromStr(inputStr)
	if err != nil {
		t.Errorf("TestFilterInsertUpdateNone NewShaHashFromStr failed: %v", err)
		return
	}
	outpoint := btcwire.NewOutPoint(sha, 0)

	if f.MatchesOutPoint(outpoint) {
		t.Errorf("TestFilterInsertUpdateNone matched outpoint %s", inputStr)
		return
	}

	inputStr = "02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"
	sha, err = btcwire.NewShaHashFromStr(inputStr)
	if err != nil {
		t.Errorf("TestFilterInsertUpdateNone NewShaHashFromStr failed: %v", err)
		return
	}
	outpoint = btcwire.NewOutPoint(sha, 0)

	if f.MatchesOutPoint(outpoint) {
		t.Errorf("TestFilterInsertUpdateNone matched outpoint %s", inputStr)
		return
	}
}
Example #3
0
func makeTx(outputs []output, amount, value int64, toAddr, changeAddr string) (*btcwire.MsgTx, error) {
	msgTx := btcwire.NewMsgTx()

	for _, op := range outputs {
		hash, err := btcwire.NewShaHashFromStr(op.TxHash)
		if err != nil {
			return nil, err
		}
		b, err := hex.DecodeString(op.Script)
		if err != nil {
			return nil, err
		}
		txIn := btcwire.NewTxIn(btcwire.NewOutPoint(hash, op.TxN), b)
		msgTx.AddTxIn(txIn)
	}

	script, err := makeScriptPubKey(toAddr)
	if err != nil {
		return nil, err
	}
	txOut := btcwire.NewTxOut(value, script)
	msgTx.AddTxOut(txOut)

	if amount > value {
		script, err = makeScriptPubKey(changeAddr)
		if err != nil {
			return nil, err
		}
		txOut := btcwire.NewTxOut(amount-value, script)
		msgTx.AddTxOut(txOut)
	}
	return msgTx, nil
}
Example #4
0
File: cmds.go Project: hsk81/btcws
// parseNotifySpentCmd parses a NotifySpentCmd into a concrete type
// satisifying the btcjson.Cmd interface.  This is used when registering
// the custom command with the btcjson parser.
func parseNotifySpentCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) {
	if len(r.Params) != 2 {
		return nil, btcjson.ErrWrongNumberOfParams
	}

	hashStr, ok := r.Params[0].(string)
	if !ok {
		return nil, errors.New("first parameter must be a string")
	}
	hash, err := btcwire.NewShaHashFromStr(hashStr)
	if err != nil {
		return nil, errors.New("first parameter is not a valid " +
			"hash string")
	}
	idx, ok := r.Params[1].(float64)
	if !ok {
		return nil, errors.New("second parameter is not a number")
	}
	if idx < 0 {
		return nil, errors.New("second parameter cannot be negative")
	}

	cmd := NewNotifySpentCmd(r.Id, btcwire.NewOutPoint(hash, uint32(idx)))
	return cmd, nil
}
Example #5
0
// removeTransaction removes the passed transaction from the memory pool.
func (mp *txMemPool) removeTransaction(tx *btcwire.MsgTx) {
	mp.lock.Lock()
	defer mp.lock.Unlock()

	// Remove any transactions which rely on this one.
	txHash, _ := tx.TxSha()
	for i := uint32(0); i < uint32(len(tx.TxOut)); i++ {
		outpoint := btcwire.NewOutPoint(&txHash, i)
		if txRedeemer, exists := mp.outpoints[*outpoint]; exists {
			mp.lock.Unlock()
			mp.removeTransaction(txRedeemer)
			mp.lock.Lock()
		}
	}

	// Remove the transaction and mark the referenced outpoints as unspent
	// by the pool.
	if tx, exists := mp.pool[txHash]; exists {
		for _, txIn := range tx.TxIn {
			delete(mp.outpoints, txIn.PreviousOutpoint)
		}
		delete(mp.pool, txHash)
	}

}
Example #6
0
// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
// based on the passed block height to the provided address.  When the address
// is nil, the coinbase transaction will instead be redeemable by anyone.
//
// See the comment for NewBlockTemplate for more information about why the nil
// address handling is useful.
func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int64, addr btcutil.Address) (*btcutil.Tx, error) {
	// Create the script to pay to the provided payment address if one was
	// specified.  Otherwise create a script that allows the coinbase to be
	// redeemable by anyone.
	var pkScript []byte
	if addr != nil {
		var err error
		pkScript, err = btcscript.PayToAddrScript(addr)
		if err != nil {
			return nil, err
		}
	} else {
		scriptBuilder := btcscript.NewScriptBuilder()
		pkScript = scriptBuilder.AddOp(btcscript.OP_TRUE).Script()
	}

	tx := btcwire.NewMsgTx()
	tx.AddTxIn(&btcwire.TxIn{
		// Coinbase transactions have no inputs, so previous outpoint is
		// zero hash and max index.
		PreviousOutPoint: *btcwire.NewOutPoint(&btcwire.ShaHash{},
			btcwire.MaxPrevOutIndex),
		SignatureScript: coinbaseScript,
		Sequence:        btcwire.MaxTxInSequenceNum,
	})
	tx.AddTxOut(&btcwire.TxOut{
		Value: btcchain.CalcBlockSubsidy(nextBlockHeight,
			activeNetParams.Params),
		PkScript: pkScript,
	})
	return btcutil.NewTx(tx), nil
}
Example #7
0
// removeConflict removes an unconfirmed transaction record and all spend chains
// deriving from it from the store.  This is designed to remove transactions
// that would otherwise result in double spend conflicts if left in the store.
// All not-removed credits spent by removed transactions are set unspent.
func (s *Store) removeConflict(r *txRecord) error {
	u := &s.unconfirmed

	// If this transaction contains any spent credits (which must be spent by
	// other unconfirmed transactions), recursively remove each spender.
	for i, credit := range r.credits {
		if credit == nil || credit.spentBy == nil {
			continue
		}
		op := btcwire.NewOutPoint(r.Tx().Sha(), uint32(i))
		nextSpender, ok := u.spentUnconfirmed[*op]
		if !ok {
			return ErrInconsistentStore
		}
		log.Debugf("Transaction %v is part of a removed double spend "+
			"chain -- removing as well", nextSpender.tx.Sha())
		if err := s.removeConflict(nextSpender); err != nil {
			return err
		}
	}

	// If this tx spends any previous credits, set each unspent.
	for _, input := range r.Tx().MsgTx().TxIn {
		delete(u.previousOutpoints, input.PreviousOutpoint)

		// For all mined transactions with credits spent by this
		// conflicting transaction, remove from the bookkeeping maps
		// and set each previous record's credit as unspent.
		prevKey, ok := u.spentBlockOutPointKeys[input.PreviousOutpoint]
		if ok {
			delete(u.spentBlockOutPointKeys, input.PreviousOutpoint)
			delete(u.spentBlockOutPoints, prevKey)
			prev, err := s.lookupBlockTx(prevKey.BlockTxKey)
			if err != nil {
				return err
			}
			prev.credits[prevKey.OutputIndex].spentBy = nil
			continue
		}

		// For all unmined transactions with credits spent by this
		// conflicting transaction, remove from the unspent store's
		// spent tracking.
		//
		// Spend tracking is only handled by these maps, so there is
		// no need to modify the record and unset a spent-by pointer.
		if _, ok := u.spentUnconfirmed[input.PreviousOutpoint]; ok {
			delete(u.spentUnconfirmed, input.PreviousOutpoint)
		}
	}

	delete(u.txs, *r.Tx().Sha())
	for _, input := range r.Tx().MsgTx().TxIn {
		delete(u.previousOutpoints, input.PreviousOutpoint)
	}

	return nil
}
Example #8
0
func TestFakeTxs(t *testing.T) {
	// First we need a wallet.
	w, err := wallet.NewWallet("banana wallet", "", []byte("banana"),
		btcwire.MainNet, &wallet.BlockStamp{}, 100)
	if err != nil {
		t.Errorf("Can not create encrypted wallet: %s", err)
		return
	}
	a := &Account{
		Wallet:          w,
		lockedOutpoints: map[btcwire.OutPoint]struct{}{},
	}

	w.Unlock([]byte("banana"))

	// Create and add a fake Utxo so we have some funds to spend.
	//
	// This will pass validation because btcscript is unaware of invalid
	// tx inputs, however, this example would fail in btcd.
	utxo := &tx.Utxo{}
	addr, err := w.NextChainedAddress(&wallet.BlockStamp{}, 100)
	if err != nil {
		t.Errorf("Cannot get next address: %s", err)
		return
	}
	copy(utxo.AddrHash[:], addr.ScriptAddress())
	ophash := (btcwire.ShaHash)([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
		28, 29, 30, 31, 32})
	out := btcwire.NewOutPoint(&ophash, 0)
	utxo.Out = tx.OutPoint(*out)
	ss, err := btcscript.PayToAddrScript(addr)
	if err != nil {
		t.Errorf("Could not create utxo PkScript: %s", err)
		return
	}
	utxo.Subscript = tx.PkScript(ss)
	utxo.Amt = 1000000
	utxo.Height = 12345
	a.UtxoStore = append(a.UtxoStore, utxo)

	// Fake our current block height so btcd doesn't need to be queried.
	curBlock.BlockStamp.Height = 12346

	// Create the transaction.
	pairs := map[string]int64{
		"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": 5000,
	}
	_, err = a.txToPairs(pairs, 1)
	if err != nil {
		t.Errorf("Tx creation failed: %s", err)
		return
	}
}
Example #9
0
func TestFindingSpentCredits(t *testing.T) {
	s := New()

	// Insert transaction and credit which will be spent.
	r, err := s.InsertTx(TstRecvTx, TstRecvTxBlockDetails)
	if err != nil {
		t.Fatal(err)
	}
	_, err = r.AddCredit(0, false)
	if err != nil {
		t.Fatal(err)
	}

	// Insert confirmed transaction which spends the above credit.
	TstSpendingTx.SetIndex(TstSignedTxIndex)
	r2, err := s.InsertTx(TstSpendingTx, TstSignedTxBlockDetails)
	if err != nil {
		t.Fatal(err)
	}
	_, err = r2.AddCredit(0, false)
	if err != nil {
		t.Fatal(err)
	}
	_, err = r2.AddDebits(nil)
	if err != nil {
		t.Fatal(err)
	}

	bal, err := s.Balance(1, TstSignedTxBlockDetails.Height)
	if err != nil {
		t.Fatal(err)
	}
	if bal != btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value) {
		t.Fatal("bad balance")
	}
	unspents, err := s.UnspentOutputs()
	if err != nil {
		t.Fatal(err)
	}
	op := btcwire.NewOutPoint(TstSpendingTx.Sha(), 0)
	if *unspents[0].OutPoint() != *op {
		t.Fatal("unspent outpoint doesn't match expected")
	}
	if len(unspents) > 1 {
		t.Fatal("has more than one unspent credit")
	}
}
Example #10
0
// TestCheckSerializedHeight tests the checkSerializedHeight function with
// various serialized heights and also does negative tests to ensure errors
// and handled properly.
func TestCheckSerializedHeight(t *testing.T) {
	// Create an empty coinbase template to be used in the tests below.
	coinbaseOutpoint := btcwire.NewOutPoint(&btcwire.ShaHash{}, math.MaxUint32)
	coinbaseTx := btcwire.NewMsgTx()
	coinbaseTx.Version = 2
	coinbaseTx.AddTxIn(btcwire.NewTxIn(coinbaseOutpoint, nil))

	//
	tests := []struct {
		sigScript  []byte // Serialized data
		wantHeight int64  // Expected height
		err        error  // Expected error type
	}{
		// No serialized height length.
		{[]byte{}, 0, btcchain.RuleError("")},
		// Serialized height length with no height bytes.
		{[]byte{0x02}, 0, btcchain.RuleError("")},
		// Serialized height length with too few height bytes.
		{[]byte{0x02, 0x4a}, 0, btcchain.RuleError("")},
		// Serialized height that needs 2 bytes to encode.
		{[]byte{0x02, 0x4a, 0x52}, 21066, nil},
		// Serialized height that needs 2 bytes to encode, but backwards
		// endianness.
		{[]byte{0x02, 0x4a, 0x52}, 19026, btcchain.RuleError("")},
		// Serialized height that needs 3 bytes to encode.
		{[]byte{0x03, 0x40, 0x0d, 0x03}, 200000, nil},
		// Serialized height that needs 3 bytes to encode, but backwards
		// endianness.
		{[]byte{0x03, 0x40, 0x0d, 0x03}, 1074594560, btcchain.RuleError("")},
	}

	t.Logf("Running %d tests", len(tests))
	for i, test := range tests {
		msgTx := coinbaseTx.Copy()
		msgTx.TxIn[0].SignatureScript = test.sigScript
		tx := btcutil.NewTx(msgTx)

		err := btcchain.TstCheckSerializedHeight(tx, test.wantHeight)
		if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
			t.Errorf("checkSerializedHeight #%d wrong error type "+
				"got: %v <%T>, want: %T", i, err, err, test.err)
			continue
		}
	}
}
Example #11
0
func rpcTxPick(exact bool, targetAmnt int64, params BuilderParams) (*TxInParams, error) {
	// selects an unspent outpoint that is funded over the minAmount
	list, err := params.Client.ListUnspent()
	if err != nil {
		log.Println("list unpsent threw")
		return nil, err
	}
	if len(list) < 1 {
		return nil, errors.New("No unspent outputs at all.")
	}

	for _, prevJson := range list {
		_amnt, _ := btcutil.NewAmount(prevJson.Amount)
		amnt := int64(_amnt)
		txid := prevJson.TxId
		prevHash, _ := btcwire.NewShaHashFromStr(txid)
		outPoint := btcwire.NewOutPoint(prevHash, prevJson.Vout)

		_, contained := params.PendingSet[outPointStr(outPoint)]
		// This unpsent is in the pending set and it either exactly equals the target or
		// has a value above that target
		if !contained && (exact && targetAmnt == amnt || !exact && targetAmnt <= amnt) {
			// Found one, lets use it
			script, _ := hex.DecodeString(prevJson.ScriptPubKey)
			// None of the above ~should~ ever throw errors
			txOut := btcwire.NewTxOut(amnt, script)

			prevAddress, _ := btcutil.DecodeAddress(prevJson.Address, params.NetParams)
			wifkey, err := params.Client.DumpPrivKey(prevAddress)
			if err != nil {
				return nil, err
			}
			inParams := TxInParams{
				TxOut:    txOut,
				OutPoint: outPoint,
				Wif:      wifkey,
			}
			params.PendingSet[outPointStr(outPoint)] = struct{}{}
			return &inParams, nil
		}
	}
	// Never found a good outpoint
	return nil, errors.New("No txout with the right funds")
}
Example #12
0
// removeTransaction is the internal function which implements the public
// RemoveTransaction.  See the comment for RemoveTransaction for more details.
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *txMemPool) removeTransaction(tx *btcutil.Tx) {
	// Remove any transactions which rely on this one.
	txHash := tx.Sha()
	for i := uint32(0); i < uint32(len(tx.MsgTx().TxOut)); i++ {
		outpoint := btcwire.NewOutPoint(txHash, i)
		if txRedeemer, exists := mp.outpoints[*outpoint]; exists {
			mp.removeTransaction(txRedeemer)
		}
	}

	// Remove the transaction and mark the referenced outpoints as unspent
	// by the pool.
	if txDesc, exists := mp.pool[*txHash]; exists {
		for _, txIn := range txDesc.Tx.MsgTx().TxIn {
			delete(mp.outpoints, txIn.PreviousOutpoint)
		}
		delete(mp.pool, *txHash)
	}
}
Example #13
0
// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
// based on the passed block height to the passed public key.  It also accepts
// an extra nonce value for the signature script.  This extra nonce helps ensure
// the transaction is not a duplicate transaction (paying the same value to the
// same public key address would otherwise be an identical transaction for
// block version 1).
func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int64, addr btcutil.Address) (*btcutil.Tx, error) {
	// Create a script to pay to the specific address.
	pkScript, err := btcscript.PayToAddrScript(addr)
	if err != nil {
		return nil, err
	}

	tx := btcwire.NewMsgTx()
	tx.AddTxIn(&btcwire.TxIn{
		// Coinbase transactions have no inputs, so previous outpoint is
		// zero hash and max index.
		PreviousOutpoint: *btcwire.NewOutPoint(&btcwire.ShaHash{},
			btcwire.MaxPrevOutIndex),
		SignatureScript: coinbaseScript,
		Sequence:        btcwire.MaxTxInSequenceNum,
	})
	tx.AddTxOut(&btcwire.TxOut{
		Value: btcchain.CalcBlockSubsidy(nextBlockHeight,
			activeNetParams.Params),
		PkScript: pkScript,
	})
	return btcutil.NewTx(tx), nil
}
Example #14
0
// TestTx tests the MsgTx API.
func TestTx(t *testing.T) {
	pver := btcwire.ProtocolVersion

	// Block 100000 hash.
	hashStr := "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
	hash, err := btcwire.NewShaHashFromStr(hashStr)
	if err != nil {
		t.Errorf("NewShaHashFromStr: %v", err)
	}

	// Ensure the command is expected value.
	wantCmd := "tx"
	msg := btcwire.NewMsgTx()
	if cmd := msg.Command(); cmd != wantCmd {
		t.Errorf("NewMsgAddr: wrong command - got %v want %v",
			cmd, wantCmd)
	}

	// Ensure max payload is expected value for latest protocol version.
	// Num addresses (varInt) + max allowed addresses.
	wantPayload := uint32(1000 * 1000)
	maxPayload := msg.MaxPayloadLength(pver)
	if maxPayload != wantPayload {
		t.Errorf("MaxPayloadLength: wrong max payload length for "+
			"protocol version %d - got %v, want %v", pver,
			maxPayload, wantPayload)
	}

	// Ensure we get the same transaction output point data back out.
	prevOutIndex := uint32(1)
	prevOut := btcwire.NewOutPoint(hash, prevOutIndex)
	if !prevOut.Hash.IsEqual(hash) {
		t.Errorf("NewOutPoint: wrong hash - got %v, want %v",
			spew.Sprint(&prevOut.Hash), spew.Sprint(hash))
	}
	if prevOut.Index != prevOutIndex {
		t.Errorf("NewOutPoint: wrong index - got %v, want %v",
			prevOut.Index, prevOutIndex)
	}

	// Ensure we get the same transaction input back out.
	sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62}
	txIn := btcwire.NewTxIn(prevOut, sigScript)
	if !reflect.DeepEqual(&txIn.PreviousOutpoint, prevOut) {
		t.Errorf("NewTxIn: wrong prev outpoint - got %v, want %v",
			spew.Sprint(&txIn.PreviousOutpoint),
			spew.Sprint(prevOut))
	}
	if !bytes.Equal(txIn.SignatureScript, sigScript) {
		t.Errorf("NewTxIn: wrong signature script - got %v, want %v",
			spew.Sdump(txIn.SignatureScript),
			spew.Sdump(sigScript))
	}

	// Ensure we get the same transaction output back out.
	txValue := int64(5000000000)
	pkScript := []byte{
		0x41, // OP_DATA_65
		0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
		0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
		0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
		0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
		0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
		0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
		0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
		0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
		0xa6, // 65-byte signature
		0xac, // OP_CHECKSIG
	}
	txOut := btcwire.NewTxOut(txValue, pkScript)
	if txOut.Value != txValue {
		t.Errorf("NewTxOut: wrong pk script - got %v, want %v",
			txOut.Value, txValue)

	}
	if !bytes.Equal(txOut.PkScript, pkScript) {
		t.Errorf("NewTxOut: wrong pk script - got %v, want %v",
			spew.Sdump(txOut.PkScript),
			spew.Sdump(pkScript))
	}

	// Ensure transaction inputs are added properly.
	msg.AddTxIn(txIn)
	if !reflect.DeepEqual(msg.TxIn[0], txIn) {
		t.Errorf("AddTxIn: wrong transaction input added - got %v, want %v",
			spew.Sprint(msg.TxIn[0]), spew.Sprint(txIn))
	}

	// Ensure transaction outputs are added properly.
	msg.AddTxOut(txOut)
	if !reflect.DeepEqual(msg.TxOut[0], txOut) {
		t.Errorf("AddTxIn: wrong transaction output added - got %v, want %v",
			spew.Sprint(msg.TxOut[0]), spew.Sprint(txOut))
	}

	// Ensure the copy produced an identical transaction message.
	newMsg := msg.Copy()
	if !reflect.DeepEqual(newMsg, msg) {
		t.Errorf("Copy: mismatched tx messages - got %v, want %v",
			spew.Sdump(newMsg), spew.Sdump(msg))
	}

	return
}
Example #15
0
// handleCreateRawTransaction handles createrawtransaction commands.
func handleCreateRawTransaction(s *rpcServer, cmd btcjson.Cmd) (interface{}, error) {
	c := cmd.(*btcjson.CreateRawTransactionCmd)

	// Add all transaction inputs to a new transaction after performing
	// some validity checks.
	mtx := btcwire.NewMsgTx()
	for _, input := range c.Inputs {
		txHash, err := btcwire.NewShaHashFromStr(input.Txid)
		if err != nil {
			return nil, btcjson.ErrDecodeHexString
		}

		if input.Vout < 0 {
			return nil, btcjson.Error{
				Code:    btcjson.ErrInvalidParameter.Code,
				Message: "Invalid parameter, vout must be positive",
			}
		}

		prevOut := btcwire.NewOutPoint(txHash, uint32(input.Vout))
		txIn := btcwire.NewTxIn(prevOut, []byte{})
		mtx.AddTxIn(txIn)
	}

	// Add all transaction outputs to the transaction after performing
	// some validity checks.
	for encodedAddr, amount := range c.Amounts {
		// Ensure amount is in the valid range for monetary amounts.
		if amount <= 0 || amount > btcutil.MaxSatoshi {
			return nil, btcjson.Error{
				Code:    btcjson.ErrType.Code,
				Message: "Invalid amount",
			}
		}

		// Decode the provided address.
		addr, err := btcutil.DecodeAddress(encodedAddr,
			activeNetParams.btcnet)
		if err != nil {
			return nil, btcjson.Error{
				Code: btcjson.ErrInvalidAddressOrKey.Code,
				Message: btcjson.ErrInvalidAddressOrKey.Message +
					": " + err.Error(),
			}
		}

		// Ensure the address is one of the supported types and that
		// the network encoded with the address matches the network the
		// server is currently on.
		switch addr.(type) {
		case *btcutil.AddressPubKeyHash:
		case *btcutil.AddressScriptHash:
		default:
			return nil, btcjson.ErrInvalidAddressOrKey
		}
		if !addr.IsForNet(s.server.btcnet) {
			return nil, btcjson.Error{
				Code: btcjson.ErrInvalidAddressOrKey.Code,
				Message: fmt.Sprintf("%s: %q",
					btcjson.ErrInvalidAddressOrKey.Message,
					encodedAddr),
			}
		}

		// Create a new script which pays to the provided address.
		pkScript, err := btcscript.PayToAddrScript(addr)
		if err != nil {
			return nil, btcjson.Error{
				Code:    btcjson.ErrInternal.Code,
				Message: err.Error(),
			}
		}

		txOut := btcwire.NewTxOut(amount, pkScript)
		mtx.AddTxOut(txOut)
	}

	// Return the serialized and hex-encoded transaction.
	mtxHex, err := messageToHex(mtx)
	if err != nil {
		return nil, err
	}
	return mtxHex, nil
}
Example #16
0
func TestFilterInsertP2PubKeyOnly(t *testing.T) {
	blockStr := "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc" +
		"880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367" +
		"117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010" +
		"00000000000000000000000000000000000000000000000000000000000" +
		"0000ffffffff07044c86041b0136ffffffff0100f2052a0100000043410" +
		"4eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2" +
		"c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a22522" +
		"47d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255" +
		"120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356" +
		"e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062e" +
		"a10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa" +
		"608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ec" +
		"bba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141" +
		"b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac0000000001000000" +
		"03fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26a" +
		"f16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23" +
		"b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6" +
		"b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e" +
		"29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245b" +
		"d69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585" +
		"caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e7" +
		"5429df397b5af83000000004948304502202bdb79c596a9ffc24e96f438" +
		"6199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b72" +
		"4fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffff" +
		"ff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cb" +
		"cb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9cecc" +
		"d328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f11" +
		"87779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff010071" +
		"4460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8" +
		"d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397" +
		"cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3" +
		"e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e4022100" +
		"8581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7" +
		"c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf64852" +
		"61c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d" +
		"3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f2" +
		"48e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124" +
		"c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e93" +
		"0220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346" +
		"669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6" +
		"485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270e" +
		"fb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051" +
		"fd372bb7a537232946e0a46f53636b4dafdaa4000000008c49304602210" +
		"0c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de" +
		"35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46f" +
		"c37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0" +
		"f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f" +
		"4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f8" +
		"94aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493" +
		"046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8a" +
		"a788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415" +
		"588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb" +
		"7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018" +
		"ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8" +
		"040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188a" +
		"c000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758d" +
		"f616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34" +
		"fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243" +
		"bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec" +
		"20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442" +
		"e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632" +
		"d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10" +
		"eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a91" +
		"4a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000" +
		"000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850" +
		"927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec" +
		"2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a25" +
		"7b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e5" +
		"21fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455f" +
		"e30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098" +
		"544bffffffff0240420f00000000001976a9144676d1b820d63ec272f19" +
		"00d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00" +
		"d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc91750" +
		"1ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f10000" +
		"00008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e" +
		"280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba80" +
		"7892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b" +
		"5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c4" +
		"7d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41e" +
		"d70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d0" +
		"68000000008b4830450221008513ad65187b903aed1102d1d0c47688127" +
		"658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de6603" +
		"5fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50b" +
		"e1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b0682" +
		"0edca9ef982c35fda2d255afba340068c5035552368bc7200c1488fffff" +
		"fff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e40" +
		"0f8699eb4888ac00000000"
	blockBytes, err := hex.DecodeString(blockStr)
	if err != nil {
		t.Errorf("TestFilterInsertP2PubKeyOnly DecodeString failed: %v", err)
		return
	}
	block, err := btcutil.NewBlockFromBytes(blockBytes)
	if err != nil {
		t.Errorf("TestFilterInsertP2PubKeyOnly NewBlockFromBytes failed: %v", err)
		return
	}

	f := bloom.NewFilter(10, 0, 0.000001, btcwire.BloomUpdateP2PubkeyOnly)

	// Generation pubkey
	inputStr := "04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c" +
		"876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a" +
		"2252247d97a46a91"
	inputBytes, err := hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterInsertP2PubKeyOnly DecodeString failed: %v", err)
		return
	}
	f.Add(inputBytes)

	// Output address of 4th transaction
	inputStr = "b6efd80d99179f4f4ff6f4dd0a007d018c385d21"
	inputBytes, err = hex.DecodeString(inputStr)
	if err != nil {
		t.Errorf("TestFilterInsertP2PubKeyOnly DecodeString failed: %v", err)
		return
	}
	f.Add(inputBytes)

	// Ignore return value -- this is just used to update the filter.
	_, _ = bloom.NewMerkleBlock(block, f)

	// We should match the generation pubkey
	inputStr = "147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"
	sha, err := btcwire.NewShaHashFromStr(inputStr)
	if err != nil {
		t.Errorf("TestMerkleBlockP2PubKeyOnly NewShaHashFromStr failed: %v", err)
		return
	}
	outpoint := btcwire.NewOutPoint(sha, 0)
	if !f.MatchesOutPoint(outpoint) {
		t.Errorf("TestMerkleBlockP2PubKeyOnly didn't match the generation "+
			"outpoint %s", inputStr)
		return
	}

	// We should not match the 4th transaction, which is not p2pk
	inputStr = "02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"
	sha, err = btcwire.NewShaHashFromStr(inputStr)
	if err != nil {
		t.Errorf("TestMerkleBlockP2PubKeyOnly NewShaHashFromStr failed: %v", err)
		return
	}
	outpoint = btcwire.NewOutPoint(sha, 0)
	if f.MatchesOutPoint(outpoint) {
		t.Errorf("TestMerkleBlockP2PubKeyOnly matched outpoint %s", inputStr)
		return
	}
}
Example #17
0
// TestTxWire tests the MsgTx wire encode and decode for various numbers
// of transaction inputs and outputs and protocol versions.
func TestTxWire(t *testing.T) {
	// Previous transaction output point for coinbase to test.
	prevOutIndex := uint32(0xffffffff)
	prevOut := btcwire.NewOutPoint(&btcwire.ShaHash{}, prevOutIndex)

	// Transaction input to test.
	sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62}
	txIn := btcwire.NewTxIn(prevOut, sigScript)
	txIn.Sequence = 0xffffffff

	// Transaction output to test.
	txValue := int64(5000000000)
	pkScript := []byte{
		0x41, // OP_DATA_65
		0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
		0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
		0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
		0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
		0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
		0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
		0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
		0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
		0xa6, // 65-byte signature
		0xac, // OP_CHECKSIG
	}
	txOut := btcwire.NewTxOut(txValue, pkScript)

	// Empty tx message.
	noTx := btcwire.NewMsgTx()
	noTx.Version = 1
	noTxEncoded := []byte{
		0x01, 0x00, 0x00, 0x00, // Version
		0x00,                   // Varint for number of input transactions
		0x00,                   // Varint for number of output transactions
		0x00, 0x00, 0x00, 0x00, // Lock time
	}

	multiTx := btcwire.NewMsgTx()
	multiTx.Version = 1
	multiTx.AddTxIn(txIn)
	multiTx.AddTxOut(txOut)
	multiTx.LockTime = 0
	multiTxEncoded := []byte{
		0x01, 0x00, 0x00, 0x00, // Version
		0x01, // Varint for number of input transactions
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash
		0xff, 0xff, 0xff, 0xff, // Prevous output index
		0x07,                                     // Varint for length of signature script
		0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62, // Signature script
		0xff, 0xff, 0xff, 0xff, // Sequence
		0x01,                                           // Varint for number of output transactions
		0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount
		0x43, // Varint for length of pk script
		0x41, // OP_DATA_65
		0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
		0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
		0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
		0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
		0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
		0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
		0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
		0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
		0xa6,                   // 65-byte signature
		0xac,                   // OP_CHECKSIG
		0x00, 0x00, 0x00, 0x00, // Lock time
	}

	tests := []struct {
		in   *btcwire.MsgTx // Message to encode
		out  *btcwire.MsgTx // Expected decoded message
		buf  []byte         // Wire encoding
		pver uint32         // Protocol version for wire encoding
	}{
		// Latest protocol version with no transactions.
		{
			noTx,
			noTx,
			noTxEncoded,
			btcwire.ProtocolVersion,
		},

		// Latest protocol version with multiple transactions.
		{
			multiTx,
			multiTx,
			multiTxEncoded,
			btcwire.ProtocolVersion,
		},

		// Protocol version BIP0035Version with no transactions.
		{
			noTx,
			noTx,
			noTxEncoded,
			btcwire.BIP0035Version,
		},

		// Protocol version BIP0035Version with multiple transactions.
		{
			multiTx,
			multiTx,
			multiTxEncoded,
			btcwire.BIP0035Version,
		},

		// Protocol version BIP0031Version with no transactions.
		{
			noTx,
			noTx,
			noTxEncoded,
			btcwire.BIP0031Version,
		},

		// Protocol version BIP0031Version with multiple transactions.
		{
			multiTx,
			multiTx,
			multiTxEncoded,
			btcwire.BIP0031Version,
		},

		// Protocol version NetAddressTimeVersion with no transactions.
		{
			noTx,
			noTx,
			noTxEncoded,
			btcwire.NetAddressTimeVersion,
		},

		// Protocol version NetAddressTimeVersion with multiple transactions.
		{
			multiTx,
			multiTx,
			multiTxEncoded,
			btcwire.NetAddressTimeVersion,
		},

		// Protocol version MultipleAddressVersion with no transactions.
		{
			noTx,
			noTx,
			noTxEncoded,
			btcwire.MultipleAddressVersion,
		},

		// Protocol version MultipleAddressVersion with multiple transactions.
		{
			multiTx,
			multiTx,
			multiTxEncoded,
			btcwire.MultipleAddressVersion,
		},
	}

	t.Logf("Running %d tests", len(tests))
	for i, test := range tests {
		// Encode the message to wire format.
		var buf bytes.Buffer
		err := test.in.BtcEncode(&buf, test.pver)
		if err != nil {
			t.Errorf("BtcEncode #%d error %v", i, err)
			continue
		}
		if !bytes.Equal(buf.Bytes(), test.buf) {
			t.Errorf("BtcEncode #%d\n got: %s want: %s", i,
				spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
			continue
		}

		// Decode the message from wire format.
		var msg btcwire.MsgTx
		rbuf := bytes.NewBuffer(test.buf)
		err = msg.BtcDecode(rbuf, test.pver)
		if err != nil {
			t.Errorf("BtcDecode #%d error %v", i, err)
			continue
		}
		if !reflect.DeepEqual(&msg, test.out) {
			t.Errorf("BtcDecode #%d\n got: %s want: %s", i,
				spew.Sdump(&msg), spew.Sdump(test.out))
			continue
		}
	}
}
Example #18
0
// InsertBlock inserts raw block and transaction data from a block into the
// database.  The first block inserted into the database will be treated as the
// genesis block.  Every subsequent block insert requires the referenced parent
// block to already exist.
func (db *LevelDb) InsertBlock(block *btcutil.Block) (height int64, rerr error) {
	db.dbLock.Lock()
	defer db.dbLock.Unlock()
	defer func() {
		if rerr == nil {
			rerr = db.processBatches()
		} else {
			db.lBatch().Reset()
		}
	}()

	blocksha, err := block.Sha()
	if err != nil {
		log.Warnf("Failed to compute block sha %v", blocksha)
		return 0, err
	}
	mblock := block.MsgBlock()
	rawMsg, err := block.Bytes()
	if err != nil {
		log.Warnf("Failed to obtain raw block sha %v", blocksha)
		return 0, err
	}
	txloc, err := block.TxLoc()
	if err != nil {
		log.Warnf("Failed to obtain raw block sha %v", blocksha)
		return 0, err
	}

	// Insert block into database
	newheight, err := db.insertBlockData(blocksha, &mblock.Header.PrevBlock,
		rawMsg)
	if err != nil {
		log.Warnf("Failed to insert block %v %v %v", blocksha,
			&mblock.Header.PrevBlock, err)
		return 0, err
	}

	// At least two blocks in the long past were generated by faulty
	// miners, the sha of the transaction exists in a previous block,
	// detect this condition and 'accept' the block.
	for txidx, tx := range mblock.Transactions {
		txsha, err := block.TxSha(txidx)
		if err != nil {
			log.Warnf("failed to compute tx name block %v idx %v err %v", blocksha, txidx, err)
			return 0, err
		}
		spentbuflen := (len(tx.TxOut) + 7) / 8
		spentbuf := make([]byte, spentbuflen, spentbuflen)
		if len(tx.TxOut)%8 != 0 {
			for i := uint(len(tx.TxOut) % 8); i < 8; i++ {
				spentbuf[spentbuflen-1] |= (byte(1) << i)
			}
		}

		err = db.insertTx(txsha, newheight, txloc[txidx].TxStart, txloc[txidx].TxLen, spentbuf)
		if err != nil {
			log.Warnf("block %v idx %v failed to insert tx %v %v err %v", blocksha, newheight, &txsha, txidx, err)
			return 0, err
		}

		// Some old blocks contain duplicate transactions
		// Attempt to cleanly bypass this problem by marking the
		// first as fully spent.
		// http://blockexplorer.com/b/91812 dup in 91842
		// http://blockexplorer.com/b/91722 dup in 91880
		if newheight == 91812 {
			dupsha, err := btcwire.NewShaHashFromStr("d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599")
			if err != nil {
				panic("invalid sha string in source")
			}
			if txsha.IsEqual(dupsha) {
				// marking TxOut[0] as spent
				po := btcwire.NewOutPoint(dupsha, 0)
				txI := btcwire.NewTxIn(po, []byte("garbage"))

				var spendtx btcwire.MsgTx
				spendtx.AddTxIn(txI)
				err = db.doSpend(&spendtx)
				if err != nil {
					log.Warnf("block %v idx %v failed to spend tx %v %v err %v", blocksha, newheight, &txsha, txidx, err)
				}
			}
		}
		if newheight == 91722 {
			dupsha, err := btcwire.NewShaHashFromStr("e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468")
			if err != nil {
				panic("invalid sha string in source")
			}
			if txsha.IsEqual(dupsha) {
				// marking TxOut[0] as spent
				po := btcwire.NewOutPoint(dupsha, 0)
				txI := btcwire.NewTxIn(po, []byte("garbage"))

				var spendtx btcwire.MsgTx
				spendtx.AddTxIn(txI)
				err = db.doSpend(&spendtx)
				if err != nil {
					log.Warnf("block %v idx %v failed to spend tx %v %v err %v", blocksha, newheight, &txsha, txidx, err)
				}
			}
		}

		err = db.doSpend(tx)
		if err != nil {
			log.Warnf("block %v idx %v failed to spend tx %v %v err %v", blocksha, newheight, txsha, txidx, err)
			return 0, err
		}
	}
	return newheight, nil
}
Example #19
0
// NtfnProcessedTx handles the btcws.ProcessedTxNtfn notification.
func NtfnProcessedTx(n btcjson.Cmd, marshaled []byte) {
	ptn, ok := n.(*btcws.ProcessedTxNtfn)
	if !ok {
		log.Errorf("%v handler: unexpected type", n.Method())
		return
	}

	// Create useful types from the JSON strings.
	receiver, err := btcutil.DecodeAddr(ptn.Receiver)
	if err != nil {
		log.Errorf("%v handler: error parsing receiver: %v", n.Method(), err)
		return
	}
	txID, err := btcwire.NewShaHashFromStr(ptn.TxID)
	if err != nil {
		log.Errorf("%v handler: error parsing txid: %v", n.Method(), err)
		return
	}
	blockHash, err := btcwire.NewShaHashFromStr(ptn.BlockHash)
	if err != nil {
		log.Errorf("%v handler: error parsing block hash: %v", n.Method(), err)
		return
	}
	pkscript, err := hex.DecodeString(ptn.PkScript)
	if err != nil {
		log.Errorf("%v handler: error parsing pkscript: %v", n.Method(), err)
		return
	}

	// Lookup account for address in result.
	aname, err := LookupAccountByAddress(ptn.Receiver)
	if err == ErrNotFound {
		log.Warnf("Received rescan result for unknown address %v", ptn.Receiver)
		return
	}
	a, err := accountstore.Account(aname)
	if err == ErrAcctNotExist {
		log.Errorf("Missing account for rescaned address %v", ptn.Receiver)
	}

	// Create RecvTx to add to tx history.
	t := &tx.RecvTx{
		TxID:         *txID,
		TxOutIdx:     ptn.TxOutIndex,
		TimeReceived: time.Now().Unix(),
		BlockHeight:  ptn.BlockHeight,
		BlockHash:    *blockHash,
		BlockIndex:   int32(ptn.BlockIndex),
		BlockTime:    ptn.BlockTime,
		Amount:       ptn.Amount,
		ReceiverHash: receiver.ScriptAddress(),
	}

	// 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.
	req := SendTxHistSyncRequest{
		txid:     *txID,
		response: make(chan SendTxHistSyncResponse),
	}
	SendTxHistSyncChans.access <- req
	resp := <-req.response
	if resp.ok {
		// Wait until send history has been recorded.
		<-resp.c
		SendTxHistSyncChans.remove <- *txID
	}

	// Record the tx history.
	a.TxStore.Lock()
	a.TxStore.s.InsertRecvTx(t)
	a.TxStore.Unlock()
	a.ScheduleTxStoreWrite()

	// 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.
	recvTxOP := btcwire.NewOutPoint(txID, ptn.TxOutIndex)
	previouslyNotifiedReq := NotifiedRecvTxRequest{
		op:       *recvTxOP,
		response: make(chan NotifiedRecvTxResponse),
	}
	NotifiedRecvTxChans.access <- previouslyNotifiedReq
	if <-previouslyNotifiedReq.response {
		NotifyMinedTx <- t
		NotifiedRecvTxChans.remove <- *recvTxOP
	} else {
		// Notify frontends of new recv tx and mark as notified.
		NotifiedRecvTxChans.add <- *recvTxOP
		NotifyNewTxDetails(frontendNotificationMaster, a.Name(), t.TxInfo(a.Name(),
			ptn.BlockHeight, a.Wallet.Net())[0])
	}

	if !ptn.Spent {
		u := &tx.Utxo{
			Amt:       uint64(ptn.Amount),
			Height:    ptn.BlockHeight,
			Subscript: pkscript,
		}
		copy(u.Out.Hash[:], txID[:])
		u.Out.Index = uint32(ptn.TxOutIndex)
		copy(u.AddrHash[:], receiver.ScriptAddress())
		copy(u.BlockHash[:], blockHash[:])
		a.UtxoStore.Lock()
		a.UtxoStore.s.Insert(u)
		a.UtxoStore.Unlock()
		a.ScheduleUtxoStoreWrite()

		// If this notification came from mempool, notify frontends of
		// the new unconfirmed balance immediately.  Otherwise, wait until
		// the blockconnected notifiation is processed.
		if u.Height == -1 {
			bal := a.CalculateBalance(0) - a.CalculateBalance(1)
			NotifyWalletBalanceUnconfirmed(frontendNotificationMaster,
				a.name, bal)
		}
	}

	// Notify frontends of new account balance.
	confirmed := a.CalculateBalance(1)
	unconfirmed := a.CalculateBalance(0) - confirmed
	NotifyWalletBalance(frontendNotificationMaster, a.name, confirmed)
	NotifyWalletBalanceUnconfirmed(frontendNotificationMaster, a.name, unconfirmed)
}
Example #20
0
func (s *Store) moveMinedTx(r *txRecord, block *Block) error {
	delete(s.unconfirmed.txs, *r.Tx().Sha())

	// Find collection and insert records.  Error out if there are records
	// saved for this block and index.
	key := BlockTxKey{r.Tx().Index(), block.Height}
	b := s.blockCollectionForInserts(block)
	txIndex := uint32(len(b.txs))
	b.txIndexes[key.BlockIndex] = txIndex
	b.txs = append(b.txs, r)

	for _, input := range r.Tx().MsgTx().TxIn {
		delete(s.unconfirmed.previousOutpoints, input.PreviousOutpoint)

		// For all mined transactions with credits spent by this
		// transaction, remove them from the spentBlockOutPoints map
		// (signifying that there is no longer an unconfirmed
		// transaction which spending that credit), and update the
		// credit's spent by tracking with the block key of the
		// newly-mined transaction.
		prev, ok := s.unconfirmed.spentBlockOutPointKeys[input.PreviousOutpoint]
		if !ok {
			continue
		}
		delete(s.unconfirmed.spentBlockOutPointKeys, input.PreviousOutpoint)
		delete(s.unconfirmed.spentBlockOutPoints, prev)
		rr, err := s.lookupBlockTx(prev.BlockTxKey)
		if err != nil {
			return err
		}
		if len(rr.credits) <= int(prev.OutputIndex) {
			rr.credits = extendCredits(rr.credits, prev.OutputIndex)
		}
		rr.credits[prev.OutputIndex].spentBy = &key
		// debits should already be non-nil
		r.debits.spends = append(r.debits.spends, &prev)
	}

	// For each credit in r, if the credit is spent by another unconfirmed
	// transaction, move the spending transaction from spentUnconfirmed
	// (which signifies a transaction spending another unconfirmed tx) to
	// spentBlockTxs (which signifies an unconfirmed transaction spending a
	// confirmed tx) and modify the mined transaction's record to refer to
	// the credit being spent by an unconfirmed transaction.
	//
	// If the credit is not spent, modify the store's unspent bookkeeping
	// maps to include the credit and increment the amount deltas by the
	// credit's value.
	for i, credit := range r.credits {
		if credit == nil {
			continue
		}
		op := btcwire.NewOutPoint(r.Tx().Sha(), uint32(i))
		outputKey := BlockOutputKey{key, uint32(i)}
		if rr, ok := s.unconfirmed.spentUnconfirmed[*op]; ok {
			delete(s.unconfirmed.spentUnconfirmed, *op)
			s.unconfirmed.spentBlockOutPointKeys[*op] = outputKey
			s.unconfirmed.spentBlockOutPoints[outputKey] = rr
			credit.spentBy = &BlockTxKey{BlockHeight: -1}
		} else if credit.spentBy == nil {
			// Mark entire transaction as containing at least one
			// unspent credit.
			s.unspent[key.BlockHeight] = struct{}{}
			b.unspent[key.BlockIndex] = txIndex

			// Increment spendable amount delta as a result of
			// moving this credit to this block.
			value := r.Tx().MsgTx().TxOut[i].Value
			b.amountDeltas.Spendable += btcutil.Amount(value)
		}
	}

	// If this moved transaction debits from any previous credits, decrement
	// the amount deltas by the total input amount.  Because this
	// transaction was moved from the unconfirmed transaction set, this can
	// never be a coinbase.
	if r.debits != nil {
		b.amountDeltas.Spendable -= r.debits.amount
	}

	return nil
}
Example #21
0
// OutPoint returns the outpoint needed to include in a transaction input
// to spend this output.
func (c Credit) OutPoint() *btcwire.OutPoint {
	return btcwire.NewOutPoint(c.Tx().Sha(), c.OutputIndex)
}
Example #22
0
func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, body []byte, s *rpcServer) error {
	var message btcjson.Message
	err := json.Unmarshal(body, &message)
	if err != nil {
		reply := btcjson.Reply{
			Result: nil,
			Error:  &btcjson.ErrParse,
			Id:     nil,
		}

		log.Tracef("RPCS: reply: %v", reply)

		replychan <- &reply
		return fmt.Errorf("RPCS: Error unmarshalling json message: %v", err)
	}
	log.Tracef("RPCS: received: %v", message)

	var rawReply btcjson.Reply
	defer func() {
		replychan <- &rawReply
		close(replychan)
	}()

	// Deal with commands
	switch message.Method {
	case "getcurrentnet":
		var net btcwire.BitcoinNet
		if cfg.TestNet3 {
			net = btcwire.TestNet3
		} else {
			net = btcwire.MainNet
		}
		rawReply = btcjson.Reply{
			Result: float64(net),
			Id:     &message.Id,
		}

	case "getbestblock":
		// All other "get block" commands give either the height, the
		// hash, or both but require the block SHA.  This gets both for
		// the best block.
		sha, height, err := s.server.db.NewestSha()
		if err != nil {
			log.Errorf("RPCS: Error getting newest block: %v", err)
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &btcjson.ErrBestBlockHash,
				Id:     &message.Id,
			}
			return err
		}
		rawReply = btcjson.Reply{
			Result: map[string]interface{}{
				"hash":   sha.String(),
				"height": height,
			},
			Id: &message.Id,
		}

	case "rescan":
		minblock, maxblock := int64(0), btcdb.AllShas
		params, ok := message.Params.([]interface{})
		if !ok || len(params) < 2 {
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &btcjson.ErrInvalidParams,
				Id:     &message.Id,
			}
			return ErrBadParamsField
		}
		fminblock, ok := params[0].(float64)
		if !ok {
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &btcjson.ErrInvalidParams,
				Id:     &message.Id,
			}
			return ErrBadParamsField
		}
		minblock = int64(fminblock)
		iaddrs, ok := params[1].([]interface{})
		if !ok {
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &btcjson.ErrInvalidParams,
				Id:     &message.Id,
			}
			return ErrBadParamsField
		}

		// addrHashes holds a set of string-ified address hashes.
		addrHashes := make(map[string]bool, len(iaddrs))
		for i := range iaddrs {
			addr, ok := iaddrs[i].(string)
			if !ok {
				rawReply = btcjson.Reply{
					Result: nil,
					Error:  &btcjson.ErrInvalidParams,
					Id:     &message.Id,
				}
				return ErrBadParamsField
			}

			addrhash, _, err := btcutil.DecodeAddress(addr)
			if err != nil {
				rawReply = btcjson.Reply{
					Result: nil,
					Error:  &btcjson.ErrInvalidParams,
					Id:     &message.Id,
				}
				return ErrBadParamsField
			}

			addrHashes[string(addrhash)] = true
		}

		if len(params) > 2 {
			fmaxblock, ok := params[2].(float64)
			if !ok {
				rawReply = btcjson.Reply{
					Result: nil,
					Error:  &btcjson.ErrInvalidParams,
					Id:     &message.Id,
				}
				return ErrBadParamsField
			}
			maxblock = int64(fmaxblock)
		}

		log.Debugf("RPCS: Begining rescan")

		// FetchHeightRange may not return a complete list of block shas for
		// the given range, so fetch range as many times as necessary.
		for {
			blkshalist, err := s.server.db.FetchHeightRange(minblock, maxblock)
			if err != nil {
				return err
			}
			if len(blkshalist) == 0 {
				break
			}

			for i := range blkshalist {
				blk, err := s.server.db.FetchBlockBySha(&blkshalist[i])
				if err != nil {
					return err
				}
				txShaList, err := blk.TxShas()
				if err != nil {
					return err
				}
				txList := s.server.db.FetchTxByShaList(txShaList)
				for _, txReply := range txList {
					if txReply.Err != nil || txReply.Tx == nil {
						continue
					}
					for txOutIdx, txout := range txReply.Tx.TxOut {
						st, txaddrhash, err := btcscript.ScriptToAddrHash(txout.PkScript)
						if st != btcscript.ScriptAddr || err != nil {
							continue
						}
						txaddr, err := btcutil.EncodeAddress(txaddrhash, s.server.btcnet)
						if err != nil {
							log.Errorf("Error encoding address: %v", err)
							return err
						}
						if ok := addrHashes[string(txaddrhash)]; ok {
							reply := btcjson.Reply{
								Result: struct {
									Sender    string `json:"sender"`
									Receiver  string `json:"receiver"`
									BlockHash string `json:"blockhash"`
									Height    int64  `json:"height"`
									TxHash    string `json:"txhash"`
									Index     uint32 `json:"index"`
									Amount    int64  `json:"amount"`
									PkScript  string `json:"pkscript"`
									Spent     bool   `json:"spent"`
								}{
									Sender:    "Unknown", // TODO(jrick)
									Receiver:  txaddr,
									BlockHash: blkshalist[i].String(),
									Height:    blk.Height(),
									TxHash:    txReply.Sha.String(),
									Index:     uint32(txOutIdx),
									Amount:    txout.Value,
									PkScript:  btcutil.Base58Encode(txout.PkScript),
									Spent:     txReply.TxSpent[txOutIdx],
								},
								Error: nil,
								Id:    &message.Id,
							}
							replychan <- &reply
						}
					}
				}
			}

			if maxblock-minblock > int64(len(blkshalist)) {
				minblock += int64(len(blkshalist))
			} else {
				break
			}
		}

		rawReply = btcjson.Reply{
			Result: nil,
			Error:  nil,
			Id:     &message.Id,
		}

		log.Debug("RPCS: Finished rescan")

	case "notifynewtxs":
		params, ok := message.Params.([]interface{})
		if !ok || len(params) != 1 {
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &btcjson.ErrInvalidParams,
				Id:     &message.Id,
			}
			return ErrBadParamsField
		}
		addr, ok := params[0].(string)
		if !ok {
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &btcjson.ErrInvalidParams,
				Id:     &message.Id,
			}
			return ErrBadParamsField
		}
		addrhash, _, err := btcutil.DecodeAddress(addr)
		if err != nil {
			jsonError := btcjson.Error{
				Code:    btcjson.ErrInvalidParams.Code,
				Message: "Cannot decode address",
			}
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &jsonError,
				Id:     &message.Id,
			}
			return ErrBadParamsField
		}
		var hash addressHash
		copy(hash[:], addrhash)
		s.ws.requests.AddTxRequest(walletNotification, hash, message.Id)

		rawReply = btcjson.Reply{
			Result: nil,
			Error:  nil,
			Id:     &message.Id,
		}

	case "notifyspent":
		params, ok := message.Params.([]interface{})
		if !ok || len(params) != 2 {
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &btcjson.ErrInvalidParams,
				Id:     &message.Id,
			}
			return ErrBadParamsField
		}
		hashBE, ok1 := params[0].(string)
		index, ok2 := params[1].(float64)
		if !ok1 || !ok2 {
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &btcjson.ErrInvalidParams,
				Id:     &message.Id,
			}
			return ErrBadParamsField
		}
		hash, err := btcwire.NewShaHashFromStr(hashBE)
		if err != nil {
			jsonError := btcjson.Error{
				Code:    btcjson.ErrInvalidParams.Code,
				Message: "Hash string cannot be parsed.",
			}
			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &jsonError,
				Id:     &message.Id,
			}
			return ErrBadParamsField
		}
		op := btcwire.NewOutPoint(hash, uint32(index))
		s.ws.requests.AddSpentRequest(walletNotification, op, message.Id)

		rawReply = btcjson.Reply{
			Result: nil,
			Error:  nil,
			Id:     &message.Id,
		}

	default:
		rawReply = btcjson.Reply{
			Result: nil,
			Error:  &btcjson.ErrMethodNotFound,
			Id:     &message.Id,
		}
	}
	return btcjson.ErrMethodNotFound
}
Example #23
0
func Test_dupTx(t *testing.T) {

	// Ignore db remove errors since it means we didn't have an old one.
	dbname := fmt.Sprintf("tstdbdup0")
	dbnamever := dbname + ".ver"
	_ = os.RemoveAll(dbname)
	_ = os.RemoveAll(dbnamever)
	db, err := btcdb.CreateDB("leveldb", dbname)
	if err != nil {
		t.Errorf("Failed to open test database %v", err)
		return
	}
	defer os.RemoveAll(dbname)
	defer os.RemoveAll(dbnamever)
	defer db.Close()

	testdatafile := filepath.Join("testdata", "blocks1-256.bz2")
	blocks, err := loadBlocks(t, testdatafile)
	if err != nil {
		t.Errorf("Unable to load blocks from test data for: %v",
			err)
		return
	}

	var lastSha *btcwire.ShaHash

	// Populate with the fisrt 256 blocks, so we have blocks to 'mess with'
	err = nil
out:
	for height := int64(0); height < int64(len(blocks)); height++ {
		block := blocks[height]

		// except for NoVerify which does not allow lookups check inputs
		mblock := block.MsgBlock()
		var txneededList []*btcwire.ShaHash
		for _, tx := range mblock.Transactions {
			for _, txin := range tx.TxIn {
				if txin.PreviousOutpoint.Index == uint32(4294967295) {
					continue
				}
				origintxsha := &txin.PreviousOutpoint.Hash
				txneededList = append(txneededList, origintxsha)

				if !db.ExistsTxSha(origintxsha) {
					t.Errorf("referenced tx not found %v ", origintxsha)
				}

				_, err = db.FetchTxBySha(origintxsha)
				if err != nil {
					t.Errorf("referenced tx not found %v err %v ", origintxsha, err)
				}
			}
		}
		txlist := db.FetchUnSpentTxByShaList(txneededList)
		for _, txe := range txlist {
			if txe.Err != nil {
				t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
				break out
			}
		}

		newheight, err := db.InsertBlock(block)
		if err != nil {
			t.Errorf("failed to insert block %v err %v", height, err)
			break out
		}
		if newheight != height {
			t.Errorf("height mismatch expect %v returned %v", height, newheight)
			break out
		}

		newSha, blkid, err := db.NewestSha()
		if err != nil {
			t.Errorf("failed to obtain latest sha %v %v", height, err)
		}

		if blkid != height {
			t.Errorf("height doe not match latest block height %v %v %v", blkid, height, err)
		}

		blkSha, _ := block.Sha()
		if *newSha != *blkSha {
			t.Errorf("Newest block sha does not match freshly inserted one %v %v %v ", newSha, blkSha, err)
		}
		lastSha = blkSha
	}

	// genrate a new block based on the last sha
	// these block are not verified, so there are a bunch of garbage fields
	// in the 'generated' block.

	var bh btcwire.BlockHeader

	bh.Version = 2
	bh.PrevBlock = *lastSha
	// Bits, Nonce are not filled in

	mblk := btcwire.NewMsgBlock(&bh)

	hash, _ := btcwire.NewShaHashFromStr("df2b060fa2e5e9c8ed5eaf6a45c13753ec8c63282b2688322eba40cd98ea067a")

	po := btcwire.NewOutPoint(hash, 0)
	txI := btcwire.NewTxIn(po, []byte("garbage"))
	txO := btcwire.NewTxOut(50000000, []byte("garbageout"))

	var tx btcwire.MsgTx
	tx.AddTxIn(txI)
	tx.AddTxOut(txO)

	mblk.AddTransaction(&tx)

	blk := btcutil.NewBlock(mblk)

	fetchList := []*btcwire.ShaHash{hash}
	listReply := db.FetchUnSpentTxByShaList(fetchList)
	for _, lr := range listReply {
		if lr.Err != nil {
			t.Errorf("sha %v spent %v err %v\n", lr.Sha,
				lr.TxSpent, lr.Err)
		}
	}

	_, err = db.InsertBlock(blk)
	if err != nil {
		t.Errorf("failed to insert phony block %v", err)
	}

	// ok, did it 'spend' the tx ?

	listReply = db.FetchUnSpentTxByShaList(fetchList)
	for _, lr := range listReply {
		if lr.Err != btcdb.TxShaMissing {
			t.Errorf("sha %v spent %v err %v\n", lr.Sha,
				lr.TxSpent, lr.Err)
		}
	}

	txshalist, _ := blk.TxShas()
	for _, txsha := range txshalist {
		txReply, err := db.FetchTxBySha(txsha)
		if err != nil {
			t.Errorf("fully spent lookup %v err %v\n", hash, err)
		} else {
			for _, lr := range txReply {
				if lr.Err != nil {
					fmt.Errorf("stx %v spent %v err %v\n", lr.Sha,
						lr.TxSpent, lr.Err)
				}
			}
		}
	}

	t.Logf("Dropping block")

	err = db.DropAfterBlockBySha(lastSha)
	if err != nil {
		t.Errorf("failed to drop spending block %v", err)
	}
}
Example #24
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)
		}
	}
}
Example #25
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)
	}
}