Esempio n. 1
0
func TestCreateAndExecuteBlock(t *testing.T) {
	defer cleanupVisor()

	// Test as not master, should fail
	vc := newGenesisConfig(t)
	v := NewVisor(vc)
	assert.Panics(t, func() { v.CreateAndExecuteBlock() })

	// Test as master, no txns
	vc = newMasterVisorConfig(t)
	v = NewVisor(vc)
	_, err := v.CreateAndExecuteBlock()
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "No transactions")

	// Test as master, more txns than allowed
	vc.BlockCreationInterval = uint64(101)
	v = NewVisor(vc)
	txns := addValidTxns(t, v, 3)
	txns = coin.SortTransactions(txns, getFee)
	v.Config.MaxBlockSize = txns[0].Size()
	assert.Equal(t, len(v.blockchain.Blocks), 1)
	assert.Equal(t, len(v.blockSigs.Sigs), 1)
	sb, err := v.CreateAndExecuteBlock()
	assert.Nil(t, err)

	assert.Equal(t, len(sb.Block.Body.Transactions), 1)
	assert.Equal(t, len(v.blockchain.Blocks), 2)
	assert.Equal(t, len(v.blockSigs.Sigs), 2)
	assert.Equal(t, v.blockchain.Blocks[1], sb.Block)
	assert.Equal(t, v.blockSigs.Sigs[1], sb.Sig)
	assert.Equal(t, len(v.Unconfirmed.Txns), 2)
	assert.Equal(t, sb.Block.Head.Time-v.blockchain.Blocks[0].Head.Time,
		vc.BlockCreationInterval)
	rawTxns := v.Unconfirmed.RawTxns()
	rawTxns = coin.SortTransactions(rawTxns, getFee)
	assert.Equal(t, len(rawTxns), 2)
	for _, tx := range sb.Block.Body.Transactions {
		assert.NotEqual(t, tx.Hash(), rawTxns[0].Hash())
		assert.NotEqual(t, tx.Hash(), rawTxns[1].Hash())
	}
	assert.Equal(t, txns[1].Hash(), rawTxns[0].Hash())
	assert.Equal(t, txns[2].Hash(), rawTxns[1].Hash())
	assert.Nil(t, v.blockSigs.Verify(v.Config.MasterKeys.Public, v.blockchain))

	// No txns, forcing NewBlockFromTransactions to fail
	v = NewVisor(vc)
	assert.Equal(t, len(v.Unconfirmed.Txns), 0)
	txns = addValidTxns(t, v, 3)
	v.Config.MaxBlockSize = 0
	sb, err = v.CreateAndExecuteBlock()
	assert.NotNil(t, err)
	assert.Equal(t, len(v.blockchain.Blocks), 1)
	assert.Equal(t, len(v.blockSigs.Sigs), 1)
	assert.Equal(t, len(v.Unconfirmed.Txns), 3)
}
Esempio n. 2
0
func TestRawTxns(t *testing.T) {
	ut := NewUnconfirmedTxnPool()
	utxs := make(coin.Transactions, 4)
	for i := 0; i < len(utxs); i++ {
		utx := addUnconfirmedTxnToPool(ut)
		utxs[i] = utx.Txn
	}
	utxs = coin.SortTransactions(utxs, getFee)
	txns := ut.RawTxns()
	txns = coin.SortTransactions(txns, getFee)
	for i, tx := range txns {
		assert.Equal(t, utxs[i], tx)
	}
}
Esempio n. 3
0
// Creates a SignedBlock from pending transactions
// Applies transaction limit constraint
// Applies max block size constraint
// Should order transactions by priority
func (self *Blockchain) CreateBlock() (coin.Block, error) {
	//var sb SignedBlock
	if self.SecKey == (cipher.SecKey{}) {
		log.Panic("Only master chain can create blocks")
	}

	txns := self.Unconfirmed.RawTxns()

	//sort
	//arbritrate
	//truncate

	//TODO: sort by arrival time/announce time
	//TODO: filter valid first

	txns = coin.SortTransactions(txns, self.Blockchain.TransactionFee)
	txns = self.blockchain.ArbitrateTransactions(txns)
	nTxns := len(txns)
	if nTxns > MaxTransactionsPerBlock {
		txns = txns[:MaxTransactionsPerBlock]
	}
	txns = txns.TruncateBytesTo(MaxBlockSize) //cap at 32 KB
	//TODO: ERROR< NewBlockFromTransactions arbritates!
	b, err := self.blockchain.NewBlockFromTransactions(txns,
		uint64(time.Now().Unix()))
	//remove creation interval, from new block
	if err != nil {
		return b, err
	}
	return b, err
}
Esempio n. 4
0
func addValidTxns(t *testing.T, v *Visor, n int) coin.Transactions {
	txns := make(coin.Transactions, n)
	for i := 0; i < len(txns); i++ {
		txn, err := makeValidTxn(v)
		assert.Nil(t, err)
		txns[i] = txn
	}
	for _, txn := range txns {
		err, known := v.RecordTxn(txn)
		assert.Nil(t, err)
		assert.False(t, known)
	}
	txns = coin.SortTransactions(txns, getFee)
	assert.Equal(t, len(v.Unconfirmed.Txns), n)
	return txns
}
Esempio n. 5
0
// Creates a SignedBlock from pending transactions
func (self *Visor) CreateBlock(when uint64) (SignedBlock, error) {
	var sb SignedBlock
	if !self.Config.IsMaster {
		log.Panic("Only master chain can create blocks")
	}
	if len(self.Unconfirmed.Txns) == 0 {
		return sb, errors.New("No transactions")
	}
	txns := self.Unconfirmed.RawTxns()
	txns = coin.SortTransactions(txns, self.Blockchain.TransactionFee)
	txns = txns.TruncateBytesTo(self.Config.MaxBlockSize)
	b, err := self.Blockchain.NewBlockFromTransactions(txns, when)
	if err != nil {
		return sb, err
	}
	return self.SignBlock(b), nil
}
Esempio n. 6
0
// Validates a set of Transactions, individually, against each other and
// against the Blockchain.  If firstFail is true, it will return an error
// as soon as it encounters one.  Else, it will return an array of
// Transactions that are valid as a whole.  It may return an error if
// firstFalse is false, if there is no way to filter the txns into a valid
// array, i.e. processTransactions(processTransactions(txn, false), true)
// should not result in an error, unless all txns are invalid.
// TODO:
//  - move arbitration to visor
//  - blockchain should have strict checking
func (bc Blockchain) processTransactions(txns coin.Transactions, arbitrating bool) (coin.Transactions, error) {
	// Transactions need to be sorted by fee and hash before arbitrating
	if arbitrating {
		txns = coin.SortTransactions(txns, bc.TransactionFee)
	}
	//TODO: audit
	if len(txns) == 0 {
		if arbitrating {
			return txns, nil
		}
		// If there are no transactions, a block should not be made
		return nil, errors.New("No transactions")
	}

	skip := make(map[int]byte)
	uxHashes := make(coin.UxHashSet, len(txns))
	for i, tx := range txns {
		// Check the transaction against itself.  This covers the hash,
		// signature indices and duplicate spends within itself
		err := bc.VerifyTransaction(tx)
		if err != nil {
			if arbitrating {
				skip[i] = byte(1)
				continue
			} else {
				return nil, err
			}
		}
		// Check that each pending unspent will be unique
		uxb := coin.UxBody{
			SrcTransaction: tx.Hash(),
		}
		for _, to := range tx.Out {
			uxb.Coins = to.Coins
			uxb.Hours = to.Hours
			uxb.Address = to.Address
			h := uxb.Hash()
			_, exists := uxHashes[h]
			if exists {
				if arbitrating {
					skip[i] = byte(1)
					continue
				} else {
					m := "Duplicate unspent output across transactions"
					return nil, errors.New(m)
				}
			}
			if DebugLevel1 {
				// Check that the expected unspent is not already in the pool.
				// This should never happen because its a hash collision
				if bc.unspent.Has(h) {
					if arbitrating {
						skip[i] = byte(1)
						continue
					} else {
						m := "Output hash is in the UnspentPool"
						return nil, errors.New(m)
					}
				}
			}
			uxHashes[h] = byte(1)
		}
	}

	// Filter invalid transactions before arbitrating between colliding ones
	if len(skip) > 0 {
		newtxns := make(coin.Transactions, len(txns)-len(skip))
		j := 0
		for i := range txns {
			if _, shouldSkip := skip[i]; !shouldSkip {
				newtxns[j] = txns[i]
				j++
			}
		}
		txns = newtxns
		skip = make(map[int]byte)
	}

	// Check to ensure that there are no duplicate spends in the entire block,
	// and that we aren't creating duplicate outputs.  Duplicate outputs
	// within a single Transaction are already checked by VerifyTransaction
	hashes := txns.Hashes()
	for i := 0; i < len(txns)-1; i++ {
		s := txns[i]
		for j := i + 1; j < len(txns); j++ {
			t := txns[j]
			if DebugLevel1 {
				if hashes[i] == hashes[j] {
					// This is a non-recoverable error for filtering, and
					// should never occur.  It indicates a hash collision
					// amongst different txns. Duplicate transactions are
					// caught earlier, when duplicate expected outputs are
					// checked for, and will not trigger this.
					return nil, errors.New("Duplicate transaction")
				}
			}
			for a := range s.In {
				for b := range t.In {
					if s.In[a] == t.In[b] {
						if arbitrating {
							// The txn with the highest fee and lowest hash
							// is chosen when attempting a double spend.
							// Since the txns are sorted, we skip the 2nd
							// iterable
							skip[j] = byte(1)
						} else {
							m := "Cannot spend output twice in the same block"
							return nil, errors.New(m)
						}
					}
				}
			}
		}
	}

	// Filter the final results, if necessary
	if len(skip) > 0 {
		newtxns := make(coin.Transactions, len(txns)-len(skip))
		j := 0
		for i := range txns {
			if _, shouldSkip := skip[i]; !shouldSkip {
				newtxns[j] = txns[i]
				j++
			}
		}
		return newtxns, nil
	}

	return txns, nil
}
Esempio n. 7
0
func TestGetOldOwnedTransactions(t *testing.T) {
	mv := setupMasterVisor()
	up := mv.Unconfirmed

	// Setup txns
	notOursNew, err := makeValidTxn(mv)
	assert.Nil(t, err)
	notOursOld, err := makeValidTxn(mv)
	assert.Nil(t, err)
	ourSpendNew, err := makeValidTxn(mv)
	assert.Nil(t, err)
	ourSpendOld, err := makeValidTxn(mv)
	assert.Nil(t, err)
	ourReceiveNew, err := makeValidTxn(mv)
	assert.Nil(t, err)
	ourReceiveOld, err := makeValidTxn(mv)
	assert.Nil(t, err)
	ourBothNew, err := makeValidTxn(mv)
	assert.Nil(t, err)
	ourBothOld, err := makeValidTxn(mv)
	assert.Nil(t, err)

	// Add a transaction that is not ours, both new and old
	err, known := up.RecordTxn(mv.blockchain, notOursNew, nil, testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)
	up.SetAnnounced(notOursNew.Hash(), util.Now())
	err, known = up.RecordTxn(mv.blockchain, notOursOld, nil, testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)

	// Add a transaction that is our spend, both new and old
	addrs := make(map[coin.Address]byte, 1)
	ux, ok := mv.blockchain.Unspent.Get(ourSpendNew.In[0])
	assert.True(t, ok)
	addrs[ux.Body.Address] = byte(1)
	err, known = up.RecordTxn(mv.blockchain, ourSpendNew, addrs, testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)
	up.SetAnnounced(ourSpendNew.Hash(), util.Now())
	addrs = make(map[coin.Address]byte, 1)
	ux, ok = mv.blockchain.Unspent.Get(ourSpendNew.In[0])
	assert.True(t, ok)
	addrs[ux.Body.Address] = byte(1)
	err, known = up.RecordTxn(mv.blockchain, ourSpendOld, addrs, testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)

	// Add a transaction that is our receive, both new and old
	addrs = make(map[coin.Address]byte, 1)
	addrs[ourReceiveNew.Out[1].Address] = byte(1)
	err, known = up.RecordTxn(mv.blockchain, ourReceiveNew, addrs,
		testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)
	up.SetAnnounced(ourReceiveNew.Hash(), util.Now())
	addrs = make(map[coin.Address]byte, 1)
	addrs[ourReceiveOld.Out[1].Address] = byte(1)
	err, known = up.RecordTxn(mv.blockchain, ourReceiveOld, addrs,
		testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)
	// Add a transaction that is both our spend and receive, both new and old
	addrs = make(map[coin.Address]byte, 2)
	ux, ok = mv.blockchain.Unspent.Get(ourBothNew.In[0])
	assert.True(t, ok)
	addrs[ux.Body.Address] = byte(1)
	addrs[ourBothNew.Out[1].Address] = byte(1)
	assert.Equal(t, len(addrs), 2)
	err, known = up.RecordTxn(mv.blockchain, ourBothNew, addrs, testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)
	up.SetAnnounced(ourBothNew.Hash(), util.Now())
	addrs = make(map[coin.Address]byte, 1)
	ux, ok = mv.blockchain.Unspent.Get(ourBothOld.In[0])
	assert.True(t, ok)
	addrs[ux.Body.Address] = byte(1)
	addrs[ourBothOld.Out[1].Address] = byte(1)
	assert.Equal(t, len(addrs), 2)
	err, known = up.RecordTxn(mv.blockchain, ourBothOld, addrs, testBlockSize, 0)
	assert.Nil(t, err)
	assert.False(t, known)

	// Get the old owned txns
	utxns := up.GetOldOwnedTransactions(time.Hour)

	// Check that the 3 txns are ones we are interested in and old enough
	assert.Equal(t, len(utxns), 3)
	mapTxns := make(map[coin.SHA256]bool)
	txns := make(coin.Transactions, len(utxns))
	for i, utx := range utxns {
		txns[i] = utx.Txn
		assert.True(t, utx.IsOurSpend || utx.IsOurReceive)
		assert.True(t, utx.Announced.IsZero())
		mapTxns[utx.Hash()] = true
	}
	assert.Equal(t, len(mapTxns), 3)
	txns = coin.SortTransactions(txns, getFee)
	expectTxns := coin.Transactions{ourSpendOld, ourReceiveOld, ourBothOld}
	expectTxns = coin.SortTransactions(expectTxns, getFee)
	assert.Equal(t, txns, expectTxns)
}
Esempio n. 8
0
func TestProcessTransactions(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	fmt.Println("genesis time:", bc.GetGenesisBlock().Time())
	assert.Equal(t, bc.Len(), uint64(1))
	_, ux := addBlockToBlockchain(t, bc)
	assert.Equal(t, bc.Len(), uint64(3))

	// Invalid, no transactions in block
	// arbitrating=false
	txns, err := bc.processTransactions(coin.Transactions{}, false)
	assert.Nil(t, txns)
	assertError(t, err, "No transactions")
	// arbitrating=true
	txns, err = bc.processTransactions(coin.Transactions{}, true)
	assert.Equal(t, len(txns), 0)
	assert.Nil(t, err)

	// Invalid, txn.Verify() fails
	// TODO -- combine all txn.Verify() failures into one test
	// method, and call it from here, from ExecuteBlock(), from
	// Verify(), from VerifyTransaction()
	txns = coin.Transactions{}
	txn := coin.Transaction{}
	txn.PushInput(ux.Hash())
	txn.PushOutput(genAddress, 777, 100)
	txn.SignInputs([]cipher.SecKey{genSecret})
	txn.UpdateHeader()
	txns = append(txns, txn)
	// arbitrating=false
	txns2, err := bc.processTransactions(txns, false)
	assert.Nil(t, txns2)
	assertError(t, err,
		"Transaction outputs must be multiple of 1e6 base units")
	// arbitrating=true
	txns2, err = bc.processTransactions(txns, true)
	assert.NotNil(t, txns2)
	assert.Nil(t, err)
	assert.Equal(t, len(txns2), 0)

	// Invalid, duplicate unspent will be created by these txns
	txn, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100,
		100)
	txns = coin.Transactions{txn, txn}
	// arbitrating=false
	txns2, err = bc.processTransactions(txns, false)
	assertError(t, err, "Duplicate unspent output across transactions")
	assert.Nil(t, txns2)
	// arbitrating=true.  One of the offending transactions should be removed
	txns2, err = bc.processTransactions(txns, true)
	assert.Nil(t, err)
	assert.Equal(t, len(txns2), 1)
	assert.Equal(t, txns2[0], txn)

	// Check that a new output will not collide with the existing pool
	txn, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100,
		100)
	txns = coin.Transactions{txn}
	uxb := coin.UxBody{
		SrcTransaction: txn.Hash(),
		Coins:          txn.Out[0].Coins,
		Hours:          txn.Out[0].Hours,
		Address:        txn.Out[0].Address,
	}
	bc.GetUnspent().Add(coin.UxOut{Body: uxb})
	// arbitrating=false
	txns2, err = bc.processTransactions(txns, false)
	assertError(t, err, "New unspent collides with existing unspent")
	assert.Nil(t, txns2)
	// arbitrating=true
	txns2, err = bc.processTransactions(txns, true)
	assert.Equal(t, len(txns2), 0)
	assert.NotNil(t, txns2)
	assert.Nil(t, err)

	// Spending of duplicate inputs being spent across txns
	txn, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100,
		100)
	txn2, _ := makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100,
		100)
	txn2.Out = nil
	txn2.PushOutput(makeAddress(), 1e6, 100)
	txn2.PushOutput(makeAddress(), ux.Body.Coins-1e6, 100)
	txn2.Sigs = nil
	txn2.SignInputs([]cipher.SecKey{genSecret})
	txn2.UpdateHeader()
	txns = coin.SortTransactions(coin.Transactions{txn, txn2}, bc.TransactionFee)
	// arbitrating=false
	txns2, err = bc.processTransactions(txns, false)
	assertError(t, err, "Cannot spend output twice in the same block")
	assert.Nil(t, txns2)
	// arbitrating=true
	txns2, err = bc.processTransactions(txns, true)
	assert.Nil(t, err)
	assert.Equal(t, len(txns2), 1)
	assert.Equal(t, txns2[0], txns[0])
}
Esempio n. 9
0
func TestNewBlockFromTransactions(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	gb := bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	// gb.Head.Version = 0x0F
	// bc.Blocks[0] = gb
	// assert.Equal(t, bc.GetGenesisBlock().Head.Version, uint32(0x0F))

	assert.Equal(t, bc.Len(), uint64(1))
	_, ux := addBlockToBlockchain(t, bc)
	assert.Equal(t, bc.Len(), uint64(3))

	// No transactions
	_, err := bc.NewBlockFromTransactions(coin.Transactions{},
		bc.Time()+_incTime)
	assertError(t, err, "No transactions")
	assert.Equal(t, bc.Len(), uint64(3))

	// Bad currentTime, must be greater than head time
	fee := uint64(100)
	txn, _ := makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100,
		fee)
	txns := coin.Transactions{txn}
	assert.Panics(t, func() {
		bc.NewBlockFromTransactions(txns, bc.Time())
	})

	// Valid transaction
	hrs := ux.CoinHours(bc.Time())
	seq := bc.Head().Head.BkSeq
	b, err := bc.NewBlockFromTransactions(txns, bc.Time()+_incTime)
	assert.Nil(t, err)
	assert.Equal(t, len(b.Body.Transactions), 1)
	assert.Equal(t, b.Body.Transactions[0], txn)
	assert.Equal(t, b.Head.BkSeq, seq+1)
	assert.Equal(t, b.Head.Time, bc.Time()+_incTime)
	assert.Equal(t, b.Head.Version, gb.Head.Version)
	assert.Equal(t, b.Head.Fee, fee)
	assert.Equal(t, b.Head.Fee, hrs-txn.OutputHours())
	assert.NotEqual(t, b.Head.Fee, uint64(0))

	// Invalid transaction
	txn.InnerHash = cipher.SHA256{}
	txns = coin.Transactions{txn}
	_, err = bc.NewBlockFromTransactions(txns, bc.Time()+_incTime)
	assertError(t, err, "Invalid header hash")

	// Multiple transactions, sorted
	// First, split our genesis block into two, so we can make 2 valid txns
	uxs := splitUnspent(t, bc, ux)

	// tNow, make two valid txns
	txn = coin.Transaction{}
	txn.PushInput(uxs[0].Hash())
	txn.PushOutput(genAddress, uxs[0].Body.Coins, uxs[0].Body.Hours)
	txn.SignInputs([]cipher.SecKey{genSecret})
	txn.UpdateHeader()
	txn2 := coin.Transaction{}
	txn2.PushInput(uxs[1].Hash())
	txn2.PushOutput(genAddress, uxs[1].Body.Coins, uxs[1].Body.Hours)
	txn2.SignInputs([]cipher.SecKey{genSecret})
	txn2.UpdateHeader()

	// Combine them and sort
	txns = coin.Transactions{txn, txn2}
	txns = coin.SortTransactions(txns, bc.TransactionFee)
	b, err = bc.NewBlockFromTransactions(txns, bc.Time()+_incTime)
	assert.Nil(t, err)
	assert.Equal(t, len(b.Body.Transactions), 2)
	assert.Equal(t, b.Body.Transactions, txns)

	// Order should be preserved
	txns2 := coin.Transactions{txn, txn2}
	sTxns := coin.NewSortableTransactions(txns2, bc.TransactionFee)
	if sTxns.IsSorted() {
		txns2[0], txns2[1] = txns2[1], txns2[0]
	}
	b, err = bc.NewBlockFromTransactions(txns2, bc.Time()+_incTime)
	assert.Nil(t, err)
	assert.Equal(t, len(b.Body.Transactions), 2)
	assert.Equal(t, b.Body.Transactions, txns2)
}
Esempio n. 10
0
func TestExecuteBlock(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	assert.Equal(t, bc.Len(), uint64(1))
	_, ux := addBlockToBlockchain(t, bc)
	assert.Equal(t, bc.Len(), uint64(3))

	// Invalid block returns error
	b := coin.Block{}
	uxs, err := bc.ExecuteBlock(&b)
	assert.NotNil(t, err)
	assert.Nil(t, uxs)

	// Valid block, spends are removed from the unspent pool, new ones are
	// added.  Blocks is updated, and new unspents are returns
	assert.Equal(t, bc.Len(), uint64(3))
	assert.Equal(t, len(bc.GetUnspent().Pool), 2)
	spuxs := splitUnspent(t, bc, ux)
	tx := coin.Transaction{}
	tx.PushInput(spuxs[0].Hash())
	coins := spuxs[0].Body.Coins
	extra := coins % 4e6
	coins = (coins - extra) / 4
	tx.PushOutput(genAddress, coins+extra, spuxs[0].Body.Hours/5)
	tx.PushOutput(genAddress, coins, spuxs[0].Body.Hours/6)
	tx.PushOutput(genAddress, coins, spuxs[0].Body.Hours/7)
	tx.PushOutput(genAddress, coins, spuxs[0].Body.Hours/8)
	tx.SignInputs([]cipher.SecKey{genSecret})
	tx.UpdateHeader()
	tx2 := coin.Transaction{}
	tx2.PushInput(spuxs[1].Hash())
	tx2.PushOutput(genAddress, spuxs[1].Body.Coins, spuxs[1].Body.Hours/10)
	tx2.SignInputs([]cipher.SecKey{genSecret})
	tx2.UpdateHeader()
	txns := coin.Transactions{tx, tx2}
	sTxns := coin.NewSortableTransactions(txns, bc.TransactionFee)
	unswapped := sTxns.IsSorted()
	txns = coin.SortTransactions(txns, bc.TransactionFee)
	assert.Nil(t, bc.verifyTransactions(txns))
	seq := bc.Head().Head.BkSeq
	b, err = bc.NewBlockFromTransactions(txns, bc.Time()+_incTime)
	assert.Equal(t, b.Head.BkSeq, seq+1)
	assert.Nil(t, err)
	assert.Equal(t, len(b.Body.Transactions), 2)
	assert.Equal(t, b.Body.Transactions, txns)
	uxs, err = bc.ExecuteBlock(&b)
	assert.Nil(t, err)
	assert.Equal(t, len(uxs), 5)
	// Check that all unspents look correct and are in the unspent pool
	txOuts := []coin.TransactionOutput{}
	if unswapped {
		txOuts = append(txOuts, tx.Out...)
		txOuts = append(txOuts, tx2.Out...)
	} else {
		txOuts = append(txOuts, tx2.Out...)
		txOuts = append(txOuts, tx.Out...)
	}
	for i, ux := range uxs {
		if unswapped {
			if i < len(tx.Out) {
				assert.Equal(t, ux.Body.SrcTransaction, tx.Hash())
			} else {
				assert.Equal(t, ux.Body.SrcTransaction, tx2.Hash())
			}
		} else {
			if i < len(tx2.Out) {
				assert.Equal(t, ux.Body.SrcTransaction, tx2.Hash())
			} else {
				assert.Equal(t, ux.Body.SrcTransaction, tx.Hash())
			}
		}
		assert.Equal(t, ux.Body.Address, txOuts[i].Address)
		assert.Equal(t, ux.Body.Coins, txOuts[i].Coins)
		assert.Equal(t, ux.Body.Hours, txOuts[i].Hours)
		assert.Equal(t, ux.Head.BkSeq, b.Head.BkSeq)
		assert.Equal(t, ux.Head.Time, b.Head.Time)
		assert.True(t, bc.GetUnspent().Has(ux.Hash()))
	}
	// Check that all spends are no longer in the pool
	txIns := []cipher.SHA256{}
	txIns = append(txIns, tx.In...)
	txIns = append(txIns, tx2.In...)
	for _, ux := range txIns {
		assert.False(t, bc.GetUnspent().Has(ux))
	}
}