Example #1
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)
}
Example #2
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))
	}
}