Пример #1
0
func InitTransaction() coin.Transaction {
	var tx coin.Transaction

	output := cipher.MustSHA256FromHex("043836eb6f29aaeb8b9bfce847e07c159c72b25ae17d291f32125e7f1912e2a0")
	tx.PushInput(output)

	for i := 0; i < 100; i++ {
		addr := cipher.MustDecodeBase58Address(AddrList[i])
		tx.PushOutput(addr, 1e12, 1) // 10e6*10e6
	}
	/*
		seckeys := make([]cipher.SecKey, 1)
		seckey := ""
		seckeys[0] = cipher.MustSecKeyFromHex(seckey)
		tx.SignInputs(seckeys)
	*/

	txs := make([]cipher.Sig, 1)
	sig := "ed9bd7a31fe30b9e2d53b35154233dfdf48aaaceb694a07142f84cdf4f5263d21b723f631817ae1c1f735bea13f0ff2a816e24a53ccb92afae685fdfc06724de01"
	txs[0] = cipher.MustSigFromHex(sig)
	tx.Sigs = txs

	tx.UpdateHeader()

	err := tx.Verify()

	if err != nil {
		log.Panic(err)
	}

	log.Printf("signature= %s", tx.Sigs[0].Hex())
	return tx
}
Пример #2
0
func (fbc *fakeBlockchain) CreateGenesisBlock(genesisAddr cipher.Address, genesisCoins, timestamp uint64) coin.Block {
	txn := coin.Transaction{}
	txn.PushOutput(genesisAddr, genesisCoins, genesisCoins)
	body := coin.BlockBody{coin.Transactions{txn}}
	prevHash := cipher.SHA256{}
	head := coin.BlockHeader{
		Time:     timestamp,
		BodyHash: body.Hash(),
		PrevHash: prevHash,
		BkSeq:    0,
		Version:  0,
		Fee:      0,
		UxHash:   coin.NewUnspentPool().GetUxHash(),
	}
	b := coin.Block{
		Head: head,
		Body: body,
	}
	// b.Body.Transactions[0].UpdateHeader()
	fbc.blocks = append(fbc.blocks, b)
	ux := coin.UxOut{
		Head: coin.UxHead{
			Time:  timestamp,
			BkSeq: 0,
		},
		Body: coin.UxBody{
			SrcTransaction: txn.InnerHash, //user inner hash
			Address:        genesisAddr,
			Coins:          genesisCoins,
			Hours:          genesisCoins, // Allocate 1 coin hour per coin
		},
	}
	fbc.unspent.Add(ux)
	return b
}
Пример #3
0
func splitUnspent(t *testing.T, bc *Blockchain, ux coin.UxOut) coin.UxArray {
	tx := coin.Transaction{}
	hrs := ux.CoinHours(bc.Time())
	if hrs < 2 {
		log.Panic("Not enough hours, would generate duplicate output")
	}
	assert.Equal(t, ux.Body.Address, genAddress)
	tx.PushInput(ux.Hash())
	coinsA := ux.Body.Coins / 2
	coinsB := coinsA
	if (ux.Body.Coins/1e6)%2 == 1 {
		coinsA = (ux.Body.Coins - 1e6) / 2
		coinsB = coinsA + 1e6
	}
	tx.PushOutput(genAddress, coinsA, hrs/4)
	tx.PushOutput(genAddress, coinsB, hrs/2)
	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)
	assert.Equal(t, len(uxs), 2)
	return uxs
}
Пример #4
0
func makeTransactionForChainWithHoursFee(t *testing.T, bc *Blockchain,
	ux coin.UxOut, sec cipher.SecKey, hours, fee uint64) (coin.Transaction, cipher.SecKey) {
	chrs := ux.CoinHours(bc.Time())
	if chrs < hours+fee {
		log.Panicf("CoinHours underflow. Have %d, need at least %d", chrs,
			hours+fee)
	}
	assert.Equal(t, cipher.AddressFromPubKey(cipher.PubKeyFromSecKey(sec)), ux.Body.Address)
	knownUx, exists := bc.GetUnspent().Get(ux.Hash())
	assert.True(t, exists)
	assert.Equal(t, knownUx, ux)
	tx := coin.Transaction{}
	tx.PushInput(ux.Hash())
	p, newSec := cipher.GenerateKeyPair()
	addr := cipher.AddressFromPubKey(p)
	tx.PushOutput(addr, 1e6, hours)
	coinsOut := ux.Body.Coins - 1e6
	if coinsOut > 0 {
		tx.PushOutput(genAddress, coinsOut, chrs-hours-fee)
	}
	tx.SignInputs([]cipher.SecKey{sec})
	assert.Equal(t, len(tx.Sigs), 1)
	assert.Nil(t, cipher.ChkSig(ux.Body.Address, cipher.AddSHA256(tx.HashInner(), tx.In[0]), tx.Sigs[0]))
	tx.UpdateHeader()
	assert.Nil(t, tx.Verify())
	err := bc.VerifyTransaction(tx)
	assert.Nil(t, err)
	return tx, newSec
}
Пример #5
0
func TestBlockchainVerifyBlock(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	gb := bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	// Genesis block not valid after the fact
	assert.NotNil(t, bc.verifyBlock(gb))
	assert.Equal(t, bc.Len(), uint64(1))
	_, ux := addBlockToBlockchain(t, bc)
	assert.Equal(t, bc.Len(), uint64(3))

	// Valid block
	tx := coin.Transaction{}
	tx.PushInput(ux.Hash())
	tx.PushOutput(genAddress, ux.Body.Coins, ux.CoinHours(bc.Time()))
	tx.SignInputs([]cipher.SecKey{genSecret})
	tx.UpdateHeader()
	b, err := bc.NewBlockFromTransactions(coin.Transactions{tx}, bc.Time()+_incTime)
	assert.Equal(t, len(b.Body.Transactions), 1)
	assert.Equal(t, len(b.Body.Transactions[0].Out), 1)
	assert.Nil(t, err)
	assert.Nil(t, bc.verifyBlock(b))

	// Invalid block header
	b.Head.BkSeq = gb.Head.BkSeq
	assert.Equal(t, len(b.Body.Transactions), 1)
	assert.Equal(t, len(b.Body.Transactions[0].Out), 1)
	assertError(t, bc.verifyBlock(b), "BkSeq invalid")

	// Invalid transactions, makes duplicate outputs
	b.Head.BkSeq = bc.Head().Head.BkSeq + 1
	b.Body.Transactions = append(b.Body.Transactions, b.Body.Transactions[0])
	b.Head.BodyHash = b.HashBody()
	assertError(t, bc.verifyBlock(b),
		"Duplicate unspent output across transactions")
}
Пример #6
0
func makeTransactionWithSecret(t *testing.T) (coin.Transaction, cipher.SecKey) {
	tx := coin.Transaction{}
	ux, s := makeUxOutWithSecret(t)
	tx.PushInput(ux.Hash())
	tx.SignInputs([]cipher.SecKey{s})
	tx.PushOutput(makeAddress(), 10e6, 100)
	tx.UpdateHeader()
	return tx, s
}
Пример #7
0
// Creates a Transaction spending coins and hours from our coins
func CreateSpendingTransaction(wlt wallet.Wallet,
	unconfirmed *UnconfirmedTxnPool, unspent *coin.UnspentPool,
	headTime uint64, amt wallet.Balance, fee, burnFactor uint64,
	dest cipher.Address) (coin.Transaction, error) {
	txn := coin.Transaction{}
	auxs := unspent.AllForAddresses(wlt.GetAddresses())
	// Subtract pending spends from available
	puxs := unconfirmed.SpendsForAddresses(unspent, wlt.GetAddressSet())
	auxs = auxs.Sub(puxs)

	// Determine which unspents to spend
	spends, err := createSpends(headTime, auxs.Flatten(), amt, fee, burnFactor)
	if err != nil {
		return txn, err
	}

	// Add these unspents as tx inputs
	toSign := make([]cipher.SecKey, len(spends))
	spending := wallet.Balance{0, 0}
	for i, au := range spends {
		entry, exists := wlt.GetEntry(au.Body.Address)
		if !exists {
			log.Panic("On second thought, the wallet entry does not exist")
		}
		txn.PushInput(au.Hash())
		toSign[i] = entry.Secret
		spending.Coins += au.Body.Coins
		spending.Hours += au.CoinHours(headTime)
	}

	// Determine how much change we get back, if any
	_, changeHours, err := calculateBurnAndChange(spending.Hours,
		amt.Hours, fee, burnFactor)
	if err != nil {
		// This should not occur, else createSpends is broken
		return txn, err
	}
	change := wallet.NewBalance(spending.Coins-amt.Coins, changeHours)
	// TODO -- send change to a new address
	changeAddr := spends[0].Body.Address
	if change.Coins == 0 {
		if change.Hours > 0 {
			msg := ("Have enough coins, but not enough to send coin hours " +
				"change back. Would spend %d more hours than requested.")
			return txn, fmt.Errorf(msg, change.Hours)
		}
	} else {
		txn.PushOutput(changeAddr, change.Coins, change.Hours)
	}

	// Finalize the the transaction
	txn.PushOutput(dest, amt.Coins, amt.Hours)
	txn.SignInputs(toSign)
	txn.UpdateHeader()
	return txn, nil
}
Пример #8
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]})
}
Пример #9
0
func makeMultipleOutputs(t *testing.T, bc *Blockchain) {
	txn := coin.Transaction{}
	ux := bc.GetUnspent().Array()[0]
	txn.PushInput(ux.Hash())
	txn.PushOutput(genAddress, 1e6, 100)
	txn.PushOutput(genAddress, 2e6, 100)
	txn.PushOutput(genAddress, _genCoins-3e6, 100)
	txn.SignInputs([]cipher.SecKey{genSecret})
	txn.UpdateHeader()
	assert.Nil(t, txn.Verify())
	assert.Nil(t, bc.VerifyTransaction(txn))
	b, err := bc.NewBlockFromTransactions(coin.Transactions{txn},
		bc.Time()+_incTime)
	assert.Nil(t, err)
	assertExecuteBlock(t, bc, b, txn)
}
Пример #10
0
// NewTransaction create skycoin transaction.
func newTransaction(utxos []unspentOut, keys []cipher.SecKey, outs []coin.TransactionOutput) (*coin.Transaction, error) {
	tx := coin.Transaction{}
	// keys := make([]cipher.SecKey, len(utxos))
	for _, u := range utxos {
		tx.PushInput(cipher.MustSHA256FromHex(u.Hash))
	}

	for _, o := range outs {
		if (o.Coins % 1e6) != 0 {
			return nil, errors.New("skycoin coins must be multiple of 1e6")
		}
		tx.PushOutput(o.Address, o.Coins, o.Hours)
	}
	// tx.Verify()

	tx.SignInputs(keys)
	tx.UpdateHeader()
	return &tx, nil
}
Пример #11
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)
}
Пример #12
0
func addBlock(bc historydb.Blockchainer, td testData, tm uint64) (*coin.Block, *coin.Transaction, error) {
	tx := coin.Transaction{}
	// get unspent output
	ux, err := getUx(bc, td.Vin.BlockSeq, td.Vin.TxID, td.Vin.Addr)
	if err != nil {
		return nil, nil, err
	}
	if ux == nil {
		return nil, nil, errors.New("no unspent output")
	}

	tx.PushInput(ux.Hash())
	for _, o := range td.Vouts {
		addr, err := cipher.DecodeBase58Address(o.ToAddr)
		if err != nil {
			return nil, nil, err
		}
		tx.PushOutput(addr, o.Coins, o.Hours)
	}

	sigKey := cipher.MustSecKeyFromHex(td.Vin.SigKey)
	tx.SignInputs([]cipher.SecKey{sigKey})
	tx.UpdateHeader()
	if err := bc.VerifyTransaction(tx); err != nil {
		return nil, nil, err
	}
	preBlock := bc.GetBlock(td.PreBlockHash)
	b := newBlock(*preBlock, tm, *bc.GetUnspent(), coin.Transactions{tx}, _feeCalc)

	// uxs, err := bc.ExecuteBlock(&b)
	_, err = bc.ExecuteBlock(&b)
	if err != nil {
		return nil, nil, err
	}
	return &b, &tx, nil
}
Пример #13
0
//DEPRECATE
//deprecate dependency on wallet
// Creates a Transaction spending coins and hours from our coins
//MOVE SOMEWHERE ELSE
//Move to wallet or move to ???
func CreateSpendingTransaction(wlt wallet.Wallet,
	unconfirmed *UnconfirmedTxnPool, unspent *coin.UnspentPool,
	headTime uint64, amt wallet.Balance,
	dest cipher.Address) (coin.Transaction, error) {
	txn := coin.Transaction{}
	auxs := unspent.AllForAddresses(wlt.GetAddresses())
	// Subtract pending spends from available
	puxs := unconfirmed.SpendsForAddresses(unspent, wlt.GetAddressSet())
	auxs = auxs.Sub(puxs)

	// Determine which unspents to spend
	spends, err := createSpends(headTime, auxs.Flatten(), amt)
	if err != nil {
		return txn, err
	}

	// Add these unspents as tx inputs
	toSign := make([]cipher.SecKey, len(spends))
	spending := wallet.Balance{0, 0}
	for i, au := range spends {
		entry, exists := wlt.GetEntry(au.Body.Address)
		if !exists {
			log.Panic("On second thought, the wallet entry does not exist")
		}
		txn.PushInput(au.Hash())
		toSign[i] = entry.Secret
		spending.Coins += au.Body.Coins
		spending.Hours += au.CoinHours(headTime)
	}

	//keep 1/4th of hours as change
	//send half to each address
	var changeHours uint64 = spending.Hours / 4

	if amt.Coins == spending.Coins {
		txn.PushOutput(dest, amt.Coins, changeHours/2)
		txn.SignInputs(toSign)
		txn.UpdateHeader()
		return txn, nil
	}

	change := wallet.NewBalance(spending.Coins-amt.Coins, changeHours/2)
	// TODO -- send change to a new address
	changeAddr := spends[0].Body.Address

	//create transaction
	txn.PushOutput(changeAddr, change.Coins, change.Hours)
	txn.PushOutput(dest, amt.Coins, changeHours/2)
	txn.SignInputs(toSign)
	txn.UpdateHeader()
	return txn, nil
}
Пример #14
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))
	}
}
Пример #15
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)
}
Пример #16
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])
}
Пример #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")
}