Пример #1
0
func TestCreateUnspents(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	// 1 out
	tx := coin.Transaction{}
	tx.PushOutput(genAddress, 11e6, 255)
	bh := coin.BlockHeader{
		Time:  tNow(),
		BkSeq: uint64(1),
	}
	uxout := coin.CreateUnspents(bh, tx)
	assert.Equal(t, len(uxout), 1)
	assertValidUnspents(t, bh, tx, uxout)

	// Multiple outs.  Should work regardless of validity
	tx = coin.Transaction{}
	ux := makeUxOut(t)
	tx.PushInput(ux.Hash())
	tx.PushOutput(genAddress, 100, 150)
	tx.PushOutput(genAddress, 200, 77)
	bh.BkSeq++
	uxout = coin.CreateUnspents(bh, tx)
	assert.Equal(t, len(uxout), 2)
	assertValidUnspents(t, bh, tx, uxout)

	// No outs
	tx = coin.Transaction{}
	uxout = coin.CreateUnspents(bh, tx)
	assertValidUnspents(t, bh, tx, uxout)
}
Пример #2
0
// InjectTxn 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 (utp *UnconfirmedTxnPool) InjectTxn(bc *Blockchain,
	t coin.Transaction) (error, bool) {

	if err := t.Verify(); err != nil {
		return err, false
	}

	if err := VerifyTransactionFee(bc, &t); err != nil {
		return err, false
	}
	if err := bc.VerifyTransaction(t); err != nil {
		return err, false
	}

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

	// Add txn to index
	unspent := bc.GetUnspent()
	utp.Txns[h] = utp.createUnconfirmedTxn(unspent, t)
	// Add predicted unspents
	utp.Unspent[h] = coin.CreateUnspents(bc.Head().Head, t)

	return nil, false
}
Пример #3
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
	h := t.Hash()
	ut, ok := self.Txns[h]
	if ok {
		now := util.Now()
		ut.Received = now
		ut.Checked = now
		self.Txns[h] = ut
		return nil, true
	}

	// Add txn to index
	self.Txns[h] = self.createUnconfirmedTxn(&bc.Unspent, t, addrs)
	// Add predicted unspents
	self.Unspent[h] = coin.CreateUnspents(bc.Head().Head, t)

	return nil, false
}
Пример #4
0
// ExecuteBlock Attempts to append block to blockchain.  Returns the UxOuts created,
// and an error if the block is invalid.
func (bc *Blockchain) ExecuteBlock(b *coin.Block) (coin.UxArray, error) {
	var uxs coin.UxArray
	err := bc.verifyBlock(*b)
	if err != nil {
		return nil, err
	}
	txns := b.Body.Transactions
	for _, tx := range txns {
		// Remove spent outputs
		bc.unspent.DelMultiple(tx.In)
		// Create new outputs
		txUxs := coin.CreateUnspents(b.Head, tx)
		for i := range txUxs {
			bc.unspent.Add(txUxs[i])
		}
		uxs = append(uxs, txUxs...)
	}

	b.Head.PrevHash = bc.head
	bc.addBlock(b)

	// update the head
	bc.head = b.HashHeader()
	bc.notify(*b)
	return uxs, nil
}
Пример #5
0
// VerifyTransaction checks that the inputs to the transaction exist,
// that the transaction does not create or destroy coins and that the
// signatures on the transaction are valid
func (bc Blockchain) VerifyTransaction(tx coin.Transaction) error {
	//CHECKLIST: DONE: check for duplicate ux inputs/double spending
	//CHECKLIST: DONE: check that inputs of transaction have not been spent
	//CHECKLIST: DONE: check there are no duplicate outputs

	// Q: why are coin hours based on last block time and not
	// current time?
	// A: no two computers will agree on system time. Need system clock
	// indepedent timing that everyone agrees on. fee values would depend on
	// local clock

	// Check transaction type and length
	// Check for duplicate outputs
	// Check for duplicate inputs
	// Check for invalid hash
	// Check for no inputs
	// Check for no outputs
	// Check for non 1e6 multiple coin outputs
	// Check for zero coin outputs
	// Check valid looking signatures
	if err := tx.Verify(); err != nil {
		return err
	}

	uxIn, err := bc.unspent.GetMultiple(tx.In)
	if err != nil {
		return err
	}
	// Checks whether ux inputs exist,
	// Check that signatures are allowed to spend inputs
	if err := tx.VerifyInput(uxIn); err != nil {
		return err
	}

	// Get the UxOuts we expect to have when the block is created.
	uxOut := coin.CreateUnspents(bc.Head().Head, tx)
	// Check that there are any duplicates within this set
	if uxOut.HasDupes() {
		return errors.New("Duplicate unspent outputs in transaction")
	}
	if DebugLevel1 {
		// Check that new unspents don't collide with existing.  This should
		// also be checked in verifyTransactions
		for i := range uxOut {
			if bc.unspent.Has(uxOut[i].Hash()) {
				return errors.New("New unspent collides with existing unspent")
			}
		}
	}

	// Check that no coins are lost, and sufficient coins and hours are spent
	err = coin.VerifyTransactionSpending(bc.Time(), uxIn, uxOut)
	if err != nil {
		return err
	}
	return nil
}
Пример #6
0
// AllIncommingOutputs returns all predicted incomming outputs.
func (utp *UnconfirmedTxnPool) AllIncommingOutputs(bh coin.BlockHeader) []ReadableOutput {
	outs := []ReadableOutput{}
	for _, tx := range utp.Txns {
		uxOuts := coin.CreateUnspents(bh, tx.Txn)
		for _, ux := range uxOuts {
			outs = append(outs, NewReadableOutput(ux))
		}
	}
	return outs
}
Пример #7
0
func TestSpendsForAddresses(t *testing.T) {
	up := NewUnconfirmedTxnPool()
	unspent := coin.NewUnspentPool()
	addrs := make(map[cipher.Address]byte, 0)
	n := 4
	useAddrs := make([]cipher.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.CreateUnspents(coin.BlockHeader{}, 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]})
}
Пример #8
0
func (bc *Blockchain) updateUnspent(b coin.Block) error {
	if err := bc.verifyBlock(b); err != nil {
		return err
	}
	txns := b.Body.Transactions
	for _, tx := range txns {
		// Remove spent outputs
		bc.unspent.DelMultiple(tx.In)
		// Create new outputs
		txUxs := coin.CreateUnspents(b.Head, tx)
		for i := range txUxs {
			bc.unspent.Add(txUxs[i])
		}
	}
	return nil
}
Пример #9
0
func getUx(bc historydb.Blockchainer, seq uint64, txID cipher.SHA256, addr string) (*coin.UxOut, error) {
	b := bc.GetBlockInDepth(seq)
	if b == nil {
		return nil, fmt.Errorf("no block in depth:%v", seq)
	}
	tx, ok := b.GetTransaction(txID)
	if !ok {
		return nil, errors.New("found transaction failed")
	}
	uxs := coin.CreateUnspents(b.Head, tx)
	for _, u := range uxs {
		if u.Body.Address.String() == addr {
			return &u, nil
		}
	}
	return nil, nil
}
Пример #10
0
// ProcessBlock will index the transaction, outputs,etc.
func (hd *HistoryDB) ProcessBlock(b *coin.Block) error {
	// index the transactions
	for _, t := range b.Body.Transactions {
		tx := Transaction{
			Tx:       t,
			BlockSeq: b.Seq(),
		}
		if err := hd.txns.Add(&tx); err != nil {
			return err
		}

		// handle tx in, genesis transaction's vin is empty, so should be ignored.
		if b.Seq() > 0 {
			for _, in := range t.In {
				o, err := hd.outputs.Get(in)
				if err != nil {
					return err
				}
				// update output's spent block seq and txid.
				o.SpentBlockSeq = b.Seq()
				o.SpentTxID = t.Hash()
				if err := hd.outputs.Set(*o); err != nil {
					return err
				}
			}
		}

		// handle the tx out
		uxArray := coin.CreateUnspents(b.Head, t)
		for _, ux := range uxArray {
			uxOut := UxOut{
				Out: ux,
			}
			if err := hd.outputs.Set(uxOut); err != nil {
				return err
			}

			if err := hd.addrUx.Add(ux.Body.Address, ux.Hash()); err != nil {
				return err
			}
		}
	}
	return nil
}
Пример #11
0
func (fbc *fakeBlockchain) ExecuteBlock(b *coin.Block) (coin.UxArray, error) {
	var uxs coin.UxArray
	txns := b.Body.Transactions
	for _, tx := range txns {
		// Remove spent outputs
		fbc.unspent.DelMultiple(tx.In)
		// Create new outputs
		txUxs := coin.CreateUnspents(b.Head, tx)
		for i := range txUxs {
			fbc.unspent.Add(txUxs[i])
		}
		uxs = append(uxs, txUxs...)
	}

	b.Head.PrevHash = fbc.Head().HashHeader()
	fbc.blocks = append(fbc.blocks, *b)

	return uxs, nil
}
Пример #12
0
func TestCreateGenesisBlock(t *testing.T) {
	ft := FakeTree{}
	now := tNow()
	b := NewBlockchain(&ft, nil)
	b.CreateGenesisBlock(genAddress, _genCoins, now)
	// gb := createGenesisBlock(genAddress, now, _genCoins)
	assert.Equal(t, b.Time(), now)
	assert.Equal(t, b.Head().Head.BkSeq, uint64(0))
	assert.Equal(t, len(b.Head().Body.Transactions), 1)
	assert.Equal(t, len(b.Head().Body.Transactions[0].Out), 1)
	assert.Equal(t, len(b.Head().Body.Transactions[0].In), 0)
	txn := b.Head().Body.Transactions[0]
	txo := txn.Out[0]
	assert.Equal(t, txo.Address, genAddress)
	assert.Equal(t, txo.Coins, _genCoins)
	assert.Equal(t, txo.Hours, _genCoins)
	assert.Equal(t, len(b.GetUnspent().Pool), 1)
	ux := b.GetUnspent().Array()[0]
	assert.Equal(t, ux.Head.BkSeq, uint64(0))
	assert.Equal(t, ux.Head.Time, now)
	assert.Equal(t, ux.Head.Time, b.Head().Head.Time)
	assert.Equal(t, ux.Body.SrcTransaction, txn.InnerHash)
	assert.Equal(t, ux.Body.Address, genAddress)
	assert.Equal(t, ux.Body.Coins, _genCoins)
	assert.Equal(t, txo.Coins, ux.Body.Coins)
	assert.Equal(t, txo.Hours, ux.Body.Hours)
	// 1 hour per coin, at init
	assert.Equal(t, ux.Body.Hours, _genCoins)
	h := cipher.Merkle([]cipher.SHA256{b.Head().Body.Transactions[0].Hash()})
	assert.Equal(t, b.Head().Head.BodyHash, h)
	assert.Equal(t, b.Head().Head.PrevHash, cipher.SHA256{})
	// TODO -- check valid snapshot
	assert.NotEqual(t, b.Head().Head.UxHash, [4]byte{})
	expect := coin.CreateUnspents(b.Head().Head, txn)
	expect.Sort()
	have := b.GetUnspent().Array()
	have.Sort()
	assert.Equal(t, expect, have)
	// Panicing
	assert.Panics(t, func() {
		b.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	})
}
Пример #13
0
func assertValidUnspent(t *testing.T, bc *coin.Blockchain,
	unspent TxnUnspents, tx coin.Transaction) {
	expect := coin.CreateUnspents(bc.Head().Head, tx)
	assert.NotEqual(t, len(expect), 0)
	sum := 0
	for _, uxs := range unspent {
		sum += len(uxs)
	}
	assert.Equal(t, len(expect), sum)
	uxs := unspent[tx.Hash()]
	for _, ux := range expect {
		found := false
		for _, u := range uxs {
			if u.Hash() == ux.Hash() {
				found = true
				break
			}
		}
		assert.True(t, found)
	}
}
Пример #14
0
func assertExecuteBlock(t *testing.T, bc *Blockchain, b coin.Block,
	tx coin.Transaction) {
	seq := bc.Head().Head.BkSeq
	nUxs := len(bc.GetUnspent().Pool)
	uxs, err := bc.ExecuteBlock(&b)
	assert.Nil(t, err)
	assert.Equal(t, bc.Head().Head.BkSeq, seq+1)
	assert.Equal(t, len(uxs), len(tx.Out))
	assert.False(t, uxs.HasDupes())
	assert.Equal(t, len(bc.GetUnspent().Pool), nUxs+len(tx.Out)-len(tx.In))
	for _, ux := range uxs {
		assert.True(t, bc.GetUnspent().Has(ux.Hash()))
		ux2, ok := bc.GetUnspent().Get(ux.Hash())
		assert.True(t, ok)
		assert.Equal(t, ux, ux2)
	}
	uxs2 := coin.CreateUnspents(bc.Head().Head, tx)
	assert.Equal(t, len(uxs2), len(uxs))
	for i, u := range uxs2 {
		assert.Equal(t, u.Body, uxs[i].Body)
	}
}
Пример #15
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)
	uncheckedHash := invalidTxUnchecked.Hash()
	checkedHash := invalidTxChecked.Hash()
	up.Unspent[uncheckedHash] = coin.CreateUnspents(coin.BlockHeader{},
		invalidTxUnchecked)
	up.Unspent[checkedHash] = coin.CreateUnspents(coin.BlockHeader{},
		invalidTxChecked)

	// 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), 5)
	for _, uxs := range up.Unspent {
		assert.Equal(t, len(uxs), 2)
	}
	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), 3)
	for _, uxs := range up.Unspent {
		assert.Equal(t, len(uxs), 2)
	}
	assert.Equal(t, len(up.Txns), 3)
}
Пример #16
0
func TestVerifyTransaction(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	gb := bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	// Genesis block is not valid by normal standards
	assert.NotNil(t, bc.VerifyTransaction(gb.Body.Transactions[0]))
	assert.Equal(t, bc.Len(), uint64(1))
	_, ux := addBlockToBlockchain(t, bc)
	assert.Equal(t, bc.Len(), uint64(3))

	// Valid txn
	tx, _ := makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100, 50)
	assert.Nil(t, bc.VerifyTransaction(tx))
	assert.Equal(t, bc.Len(), uint64(3))

	// Failure, spending unknown output
	tx, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100, 50)
	tx.Sigs = nil
	tx.In[0] = cipher.SHA256{}
	tx.SignInputs([]cipher.SecKey{genSecret})
	tx.UpdateHeader()
	assertError(t, bc.VerifyTransaction(tx), "Unspent output does not exist")
	assert.Equal(t, bc.Len(), uint64(3))

	// Failure, duplicate input
	tx, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100, 50)
	tx.Sigs = nil
	tx.In = append(tx.In, tx.In[0])
	tx.SignInputs([]cipher.SecKey{genSecret, genSecret})
	tx.UpdateHeader()
	assertError(t, bc.VerifyTransaction(tx), "Duplicate spend")
	assert.Equal(t, bc.Len(), uint64(3))

	// Failure, zero coin output
	tx, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100, 50)
	tx.Sigs = nil
	tx.PushOutput(genAddress, 0, 100)
	tx.SignInputs([]cipher.SecKey{genSecret})
	tx.UpdateHeader()
	assertError(t, bc.VerifyTransaction(tx), "Zero coin output")

	// Failure, hash collision with unspents
	tx, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100, 50)
	uxOut := coin.CreateUnspents(bc.Head().Head, tx)
	bc.GetUnspent().Add(uxOut[0])
	assertError(t, bc.VerifyTransaction(tx),
		"New unspent collides with existing unspent")

	// Failure, not spending enough coins
	tx, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100, 50)
	tx.PushOutput(genAddress, 10e6, 100)
	tx.Sigs = nil
	tx.SignInputs([]cipher.SecKey{genSecret})
	tx.UpdateHeader()
	assertError(t, bc.VerifyTransaction(tx), "Insufficient coins")

	// Failure, spending outputs we don't own
	_, s := cipher.GenerateKeyPair()
	tx = coin.Transaction{}
	for _, u := range bc.GetUnspent().Pool {
		if u.Body.Address != genAddress {
			ux = u
			break
		}
	}
	assert.NotEqual(t, ux.Body.Address, genAddress)
	tx.PushInput(ux.Hash())
	tx.PushOutput(genAddress, ux.Body.Coins, ux.Body.Hours)
	tx.SignInputs([]cipher.SecKey{s})
	tx.UpdateHeader()
	assertError(t, bc.VerifyTransaction(tx),
		"Signature not valid for output being spent")

	// Failure, wrong signature for txn hash
	tx = coin.Transaction{}
	tx.PushInput(ux.Hash())
	tx.SignInputs([]cipher.SecKey{genSecret})
	tx.PushOutput(genAddress, ux.Body.Coins, ux.Body.Hours)
	tx.UpdateHeader()
	assertError(t, bc.VerifyTransaction(tx),
		"Signature not valid for output being spent")
}
Пример #17
0
func TestVerifyTransactionSpending(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)

	// Overspending hours

	tx := coin.Transaction{}
	uxs := bc.GetUnspent().Array()
	tx.PushInput(uxs[0].Hash())
	tx.PushOutput(genAddress, 1e6, uxs[0].Body.Hours)
	tx.PushOutput(genAddress, uxs[0].Body.Coins-1e6, 1)
	uxIn, err := bc.GetUnspent().GetMultiple(tx.In)
	assert.Nil(t, err)
	uxOut := coin.CreateUnspents(bc.Head().Head, tx)
	assertError(t, coin.VerifyTransactionSpending(bc.Time(), uxIn, uxOut),
		"Insufficient coin hours")

	// add block to blockchain.
	_, ux := addBlockToBlockchain(t, bc)
	// addBlockToBlockchain(t, bc)

	// Valid
	tx, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100, 50)
	uxIn, err = bc.GetUnspent().GetMultiple(tx.In)
	assert.Nil(t, err)
	uxOut = coin.CreateUnspents(bc.Head().Head, tx)
	assert.Nil(t, coin.VerifyTransactionSpending(bc.Time(), uxIn, uxOut))

	// Destroying coins
	tx = coin.Transaction{}
	tx.PushInput(ux.Hash())
	tx.PushOutput(genAddress, 1e6, 100)
	tx.PushOutput(genAddress, 10e6, 100)
	uxIn, err = bc.GetUnspent().GetMultiple(tx.In)
	assert.Nil(t, err)
	uxOut = coin.CreateUnspents(bc.Head().Head, tx)
	err = coin.VerifyTransactionSpending(bc.Time(), uxIn, uxOut)
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(),
		"Transactions may not create or destroy coins")
	assertError(t, coin.VerifyTransactionSpending(bc.Time(), uxIn, uxOut),
		"Transactions may not create or destroy coins")

	// Insufficient coins
	tx = coin.Transaction{}
	tx.PushInput(ux.Hash())
	p, s := cipher.GenerateKeyPair()
	a := cipher.AddressFromPubKey(p)
	coins := ux.Body.Coins
	assert.True(t, coins > 1e6)
	tx.PushOutput(a, 1e6, 100)
	tx.PushOutput(genAddress, coins-1e6, 100)
	tx.SignInputs([]cipher.SecKey{genSecret})
	tx.UpdateHeader()
	b, err := bc.NewBlockFromTransactions(coin.Transactions{tx}, bc.Time()+_incTime)
	assert.Nil(t, err)
	uxs, err = bc.ExecuteBlock(&b)
	assert.Nil(t, err)
	tx = coin.Transaction{}
	tx.PushInput(uxs[0].Hash())
	tx.PushOutput(a, 10e6, 1)
	tx.SignInputs([]cipher.SecKey{s})
	tx.UpdateHeader()
	uxIn, err = bc.GetUnspent().GetMultiple(tx.In)
	assert.Nil(t, err)
	uxOut = coin.CreateUnspents(bc.Head().Head, tx)
	assertError(t, coin.VerifyTransactionSpending(bc.Time(), uxIn, uxOut),
		"Insufficient coins")
}