Example #1
0
// Adds a coin.Transaction to the pool, or updates an existing one's timestamps
// Returns an error if txn is invalid, and whether the transaction already
// existed in the pool.
func (self *UnconfirmedTxnPool) RecordTxn(bc *coin.Blockchain,
	t coin.Transaction, addrs map[coin.Address]byte, maxSize int,
	burnFactor uint64) (error, bool) {
	if err := VerifyTransaction(bc, &t, maxSize, burnFactor); err != nil {
		return err, false
	}
	if err := bc.VerifyTransaction(t); err != nil {
		return err, false
	}

	// Update if we already have this txn
	ut, ok := self.Txns[t.Hash()]
	if ok {
		now := util.Now()
		ut.Received = now
		ut.Checked = now
		self.Txns[ut.Txn.Hash()] = ut
		return nil, true
	}

	// Add txn to index
	self.Txns[t.Hash()] = self.createUnconfirmedTxn(&bc.Unspent, t, addrs)
	// Add predicted unspents
	uxs := coin.CreateExpectedUnspents(t)
	for i, _ := range uxs {
		self.Unspent.Add(uxs[i])
	}

	return nil, false
}
Example #2
0
func assertValidUnspent(t *testing.T, bc *coin.Blockchain,
	unspent *coin.UnspentPool, tx coin.Transaction) {
	expect := coin.CreateExpectedUnspents(tx)
	assert.NotEqual(t, len(expect), 0)
	assert.Equal(t, len(expect), len(unspent.Pool))
	for _, ux := range expect {
		assert.True(t, unspent.Has(ux.Hash()))
	}
}
Example #3
0
// Remove a single txn
func (self *UnconfirmedTxnPool) removeTxn(bc *coin.Blockchain, h coin.SHA256) {
	t, ok := self.Txns[h]
	if !ok {
		return
	}
	delete(self.Txns, h)
	outputs := coin.CreateExpectedUnspents(t.Txn)
	hashes := make([]coin.SHA256, len(outputs))
	for i, _ := range outputs {
		hashes[i] = outputs[i].Hash()
	}
	self.Unspent.DelMultiple(hashes)
}
Example #4
0
func TestSpendsForAddresses(t *testing.T) {
	up := NewUnconfirmedTxnPool()
	unspent := coin.NewUnspentPool()
	addrs := make(map[coin.Address]byte, 0)
	n := 4
	useAddrs := make([]coin.Address, n)
	for i, _ := range useAddrs {
		useAddrs[i] = makeAddress()
	}
	useAddrs[1] = useAddrs[0]
	for _, a := range useAddrs {
		addrs[a] = byte(1)
	}
	// Make confirmed transactions to add to unspent pool
	uxs := make(coin.UxArray, 0)
	for i := 0; i < n; i++ {
		txn := coin.Transaction{}
		txn.PushInput(randSHA256())
		txn.PushOutput(useAddrs[i], 10e6, 1000)
		uxa := coin.CreateExpectedUnspents(txn)
		for _, ux := range uxa {
			unspent.Add(ux)
		}
		uxs = append(uxs, uxa...)
	}
	assert.Equal(t, len(uxs), 4)

	// Make unconfirmed txns that spend those unspents
	for i := 0; i < n; i++ {
		txn := coin.Transaction{}
		txn.PushInput(uxs[i].Hash())
		txn.PushOutput(makeAddress(), 10e6, 1000)
		ut := UnconfirmedTxn{
			Txn: txn,
		}
		up.Txns[ut.Hash()] = ut
	}

	// Now look them up
	assert.Equal(t, len(addrs), 3)
	assert.Equal(t, len(up.Txns), 4)
	auxs := up.SpendsForAddresses(&unspent, addrs)
	assert.Equal(t, len(auxs), 3)
	assert.Equal(t, len(auxs[useAddrs[0]]), 2)
	assert.Equal(t, len(auxs[useAddrs[2]]), 1)
	assert.Equal(t, len(auxs[useAddrs[3]]), 1)
	assert.Equal(t, auxs[useAddrs[0]], coin.UxArray{uxs[0], uxs[1]})
	assert.Equal(t, auxs[useAddrs[2]], coin.UxArray{uxs[2]})
	assert.Equal(t, auxs[useAddrs[3]], coin.UxArray{uxs[3]})
}
Example #5
0
// Removes multiple txns at once. Slightly more efficient than a series of
// single RemoveTxns
func (self *UnconfirmedTxnPool) removeTxns(bc *coin.Blockchain,
	hashes []coin.SHA256) {
	uxo := make([]coin.UxOut, 0)
	for i, _ := range hashes {
		if t, ok := self.Txns[hashes[i]]; ok {
			delete(self.Txns, hashes[i])
			uxo = append(uxo, coin.CreateExpectedUnspents(t.Txn)...)
		}
	}
	uxhashes := make([]coin.SHA256, len(uxo))
	for i, _ := range uxo {
		uxhashes[i] = uxo[i].Hash()
	}
	self.Unspent.DelMultiple(uxhashes)
}
Example #6
0
func testRefresh(t *testing.T, mv *Visor,
	refresh func(checkPeriod, maxAge time.Duration)) {
	up := mv.Unconfirmed
	// Add a transaction that is invalid, but will not be checked yet
	// Add a transaction that is invalid, and will be checked and removed
	invalidTxUnchecked, err := makeValidTxn(mv)
	assert.Nil(t, err)
	invalidTxChecked, err := makeValidTxn(mv)
	assert.Nil(t, err)
	assert.Nil(t, invalidTxUnchecked.Verify())
	assert.Nil(t, invalidTxChecked.Verify())
	// Invalidate it by spending the output that this txn references
	invalidator, err := makeValidTxn(mv)
	assert.Nil(t, err)
	err, known := up.RecordTxn(mv.blockchain, invalidator, nil, testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)
	assert.Equal(t, len(up.Txns), 1)
	_, err = mv.CreateAndExecuteBlock()
	assert.Nil(t, err)
	assert.Equal(t, len(up.Txns), 0)
	assert.NotNil(t, mv.blockchain.VerifyTransaction(invalidTxUnchecked))
	assert.NotNil(t, mv.blockchain.VerifyTransaction(invalidTxChecked))

	invalidUtxUnchecked := UnconfirmedTxn{
		Txn:       invalidTxUnchecked,
		Received:  util.Now(),
		Checked:   util.Now(),
		Announced: util.ZeroTime(),
	}
	invalidUtxChecked := invalidUtxUnchecked
	invalidUtxChecked.Txn = invalidTxChecked
	invalidUtxUnchecked.Checked = util.Now().Add(time.Hour)
	invalidUtxChecked.Checked = util.Now().Add(-time.Hour)
	up.Txns[invalidUtxUnchecked.Hash()] = invalidUtxUnchecked
	up.Txns[invalidUtxChecked.Hash()] = invalidUtxChecked
	assert.Equal(t, len(up.Txns), 2)
	for _, ux := range coin.CreateExpectedUnspents(invalidTxUnchecked) {
		up.Unspent.Add(ux)
	}
	for _, ux := range coin.CreateExpectedUnspents(invalidTxChecked) {
		up.Unspent.Add(ux)
	}

	// Create a transaction that is valid, and will not be checked yet
	validTxUnchecked, err := makeValidTxn(mv)
	assert.Nil(t, err)
	// Create a transaction that is valid, and will be checked
	validTxChecked, err := makeValidTxn(mv)
	assert.Nil(t, err)
	// Create a transaction that is expired
	validTxExpired, err := makeValidTxn(mv)
	assert.Nil(t, err)

	// Add the transaction that is valid, and will not be checked yet
	err, known = up.RecordTxn(mv.blockchain, validTxUnchecked, nil,
		testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)
	validUtxUnchecked := up.Txns[validTxUnchecked.Hash()]
	validUtxUnchecked.Checked = util.Now().Add(time.Hour)
	up.Txns[validUtxUnchecked.Hash()] = validUtxUnchecked
	assert.Equal(t, len(up.Txns), 3)

	// Add the transaction that is valid, and will be checked
	err, known = up.RecordTxn(mv.blockchain, validTxChecked, nil,
		testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)
	validUtxChecked := up.Txns[validTxChecked.Hash()]
	validUtxChecked.Checked = util.Now().Add(-time.Hour)
	up.Txns[validUtxChecked.Hash()] = validUtxChecked
	assert.Equal(t, len(up.Txns), 4)

	// Add the transaction that is expired
	err, known = up.RecordTxn(mv.blockchain, validTxExpired, nil,
		testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)
	validUtxExpired := up.Txns[validTxExpired.Hash()]
	validUtxExpired.Received = util.Now().Add(-time.Hour)
	up.Txns[validTxExpired.Hash()] = validUtxExpired
	assert.Equal(t, len(up.Txns), 5)

	// Pre-sanity check
	assert.Equal(t, len(up.Unspent.Pool), 2*5)
	assert.Equal(t, len(up.Txns), 5)

	// Refresh
	checkPeriod := time.Second * 2
	maxAge := time.Second * 4
	refresh(checkPeriod, maxAge)

	// All utxns that are unchecked should be exactly the same
	assert.Equal(t, up.Txns[validUtxUnchecked.Hash()], validUtxUnchecked)
	assert.Equal(t, up.Txns[invalidUtxUnchecked.Hash()], invalidUtxUnchecked)
	// The valid one that is checked should have its checked status updated
	validUtxCheckedUpdated := up.Txns[validUtxChecked.Hash()]
	assert.True(t,
		validUtxCheckedUpdated.Checked.After(validUtxChecked.Checked))
	validUtxChecked.Checked = validUtxCheckedUpdated.Checked
	assert.Equal(t, validUtxChecked, validUtxCheckedUpdated)
	// The invalid checked one and the expired one should be removed
	_, ok := up.Txns[invalidUtxChecked.Hash()]
	assert.False(t, ok)
	_, ok = up.Txns[validUtxExpired.Hash()]
	assert.False(t, ok)
	// Also, the unspents should have 2 * nRemaining
	assert.Equal(t, len(up.Unspent.Pool), 2*3)
	assert.Equal(t, len(up.Txns), 3)
}