示例#1
0
func TestCreateSpendsWithBurn(t *testing.T) {
	now := tNow()
	amt := wallet.Balance{10e6, 100}
	uxs := makeUxBalances([]wallet.Balance{
		wallet.Balance{1e6, 50},
		wallet.Balance{8e6, 40},
		wallet.Balance{2e6, 60},
	}, now)
	// Force them to get sorted
	uxs[2].Head.BkSeq = uint64(0)
	uxs[1].Head.BkSeq = uint64(1)
	uxs[0].Head.BkSeq = uint64(2)
	cuxs := append(coin.UxArray{}, uxs...)
	// Should spend 8e6,2e6 for the exact amount, but have to add 1e6 to
	// obtain +50 for a 50% fee
	spends, err := createSpends(now, uxs, amt, 0, 2)
	assert.Nil(t, err)
	assert.Equal(t, len(spends), 3)
	assert.Equal(t, spends, coin.UxArray{cuxs[2], cuxs[1], cuxs[0]})

	have := wallet.Balance{0, 0}
	for _, ux := range spends {
		have = have.Add(wallet.NewBalanceFromUxOut(now, &ux))
	}
	burn, change, err := calculateBurnAndChange(have.Hours, amt.Hours, 0, 2)
	assert.Equal(t, burn, uint64(50))
	assert.Equal(t, change, uint64(0))
	assert.Nil(t, err)
}
示例#2
0
文件: spend.go 项目: skycoin/skycoin
//delete this function
func createSpends(headTime uint64, uxa coin.UxArray,
	amt wallet.Balance) (coin.UxArray, error) {
	if amt.Coins == 0 {
		return nil, errors.New("Zero spend amount")
	}
	if amt.Coins%1e6 != 0 {
		return nil, errors.New("Coins must be multiple of 1e6")
	}

	uxs := OldestUxOut(uxa)
	sort.Sort(uxs)

	have := wallet.Balance{0, 0}
	spending := make(coin.UxArray, 0)
	for i := range uxs {
		b := wallet.NewBalanceFromUxOut(headTime, &uxs[i]) //this is bullshit
		if b.Coins == 0 || b.Coins%1e6 != 0 {
			logger.Error("UxOut coins are 0 or 1e6, can't spend")
			continue
		}
		have = have.Add(b)
		spending = append(spending, uxs[i])
	}

	if amt.Coins > have.Coins {
		return nil, errors.New("Not enough coins")
	}

	return spending, nil
}
示例#3
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
}
示例#4
0
文件: spend.go 项目: skycoin/skycoin
//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
}
示例#5
0
func createSpends(headTime uint64, uxa coin.UxArray,
	amt wallet.Balance, fee, burnFactor uint64) (coin.UxArray, error) {
	if amt.Coins == 0 {
		return nil, errors.New("Zero spend amount")
	}
	if amt.Coins%1e6 != 0 {
		return nil, errors.New("Coins must be multiple of 1e6")
	}

	uxs := OldestUxOut(uxa)
	sort.Sort(uxs)

	have := wallet.Balance{0, 0}
	spending := make(coin.UxArray, 0)
	for i, _ := range uxs {
		burn, _, err := calculateBurnAndChange(have.Hours, amt.Hours,
			fee, burnFactor)
		if err == nil {
			trueHours := amt.Hours + fee + burn
			// Adjust hours as a moving target as outputs change
			if have.Coins > amt.Coins && have.Hours >= trueHours {
				break
			}
			// If we have the exact amount of both, we don't need any extra coins
			// for change
			if have.Coins == amt.Coins && have.Hours == trueHours {
				break
			}
		}

		b := wallet.NewBalanceFromUxOut(headTime, &uxs[i])
		if b.Coins == 0 || b.Coins%1e6 != 0 {
			logger.Error("UxOut coins are 0 or 1e6, can't spend")
			continue
		}
		have = have.Add(b)
		spending = append(spending, uxs[i])
	}
	if amt.Coins > have.Coins {
		return nil, errors.New("Not enough coins")
	}
	if amt.Hours+fee > have.Hours {
		return nil, errors.New("Not enough hours")
	}
	if _, _, err := calculateBurnAndChange(have.Hours, amt.Hours, fee,
		burnFactor); err != nil {
		return nil, errors.New("Not enough hours to burn")
	}
	return spending, nil
}
示例#6
0
func TestCreateSpends(t *testing.T) {
	now := tNow()
	amt := wallet.Balance{12e6, 125}
	uxs := makeUxBalances([]wallet.Balance{
		wallet.Balance{1e6, 50},
		wallet.Balance{8e6, 10}, // 3
		wallet.Balance{2e6, 80}, // 2
		wallet.Balance{5e6, 15}, // 4
		wallet.Balance{7e6, 20}, // 1
	}, now)
	uxs[4].Head.BkSeq = uint64(1)
	uxs[3].Head.BkSeq = uint64(4)
	uxs[2].Head.BkSeq = uint64(2)
	uxs[1].Head.BkSeq = uint64(3)
	uxs[0].Head.BkSeq = uint64(5)
	if sort.IsSorted(OldestUxOut(uxs)) {
		uxs[0], uxs[1] = uxs[1], uxs[0]
	}
	assert.False(t, sort.IsSorted(OldestUxOut(uxs)))
	expectedSorting := coin.UxArray{uxs[4], uxs[2], uxs[1], uxs[3], uxs[0]}
	cuxs := append(coin.UxArray{}, uxs...)
	sort.Sort(OldestUxOut(cuxs))
	assert.Equal(t, expectedSorting, cuxs)
	assert.True(t, sort.IsSorted(OldestUxOut(cuxs)))
	assert.False(t, sort.IsSorted(OldestUxOut(uxs)))

	ouxs := append(coin.UxArray{}, uxs...)
	spends, err := createSpends(now, uxs, amt, 0, 0)
	assert.True(t, sort.IsSorted(OldestUxOut(uxs)))
	assert.Nil(t, err)
	assert.Equal(t, spends, cuxs[:len(spends)])
	assert.Equal(t, len(spends), 4)
	assert.Equal(t, spends, coin.UxArray{ouxs[4], ouxs[2], ouxs[1], ouxs[3]})

	// Recalculate what it should be
	b := wallet.Balance{0, 0}
	ouxs = make(coin.UxArray, 0, len(spends))
	for _, ux := range cuxs {
		if b.Coins > amt.Coins && b.Hours >= amt.Hours {
			break
		}
		b = b.Add(wallet.NewBalanceFromUxOut(now, &ux))
		ouxs = append(ouxs, ux)
	}
	assert.Equal(t, len(ouxs), len(spends))
	assert.Equal(t, ouxs, spends)
}