示例#1
0
// TransferFunds will create a transaction that transfers an amount of
// NMC-satoshis to a hashed public key.
func (a *Account) TransferFunds(amount int64, pubkeyHash string) (*Transaction, error) {
	// Decode the hex representation of the Public Key.
	hashBytes, err := hex.DecodeString(pubkeyHash)
	if err != nil {
		return nil, err
	}

	// Convert it to a btcd address object.
	addr, err := btcutil.NewAddressPubKeyHash(hashBytes, &chaincfg.MainNetParams)
	if err != nil {
		return nil, err
	}

	// Generate the pkScript for this output.
	pkScript, err := txscript.PayToAddrScript(addr)
	if err != nil {
		return nil, err
	}

	// That is the only output here.
	txOutput := []*wire.TxOut{
		wire.NewTxOut(amount, pkScript),
	}

	// Build the transaction.
	return a.buildTransaction(txOutput)
}
示例#2
0
func (a *Account) buildTransactionVersion(
	output []*wire.TxOut,
	input []*UTXO,
	version int32,
) (*Transaction, error) {
	// Calculate the amount of the transaction.
	var amount int64
	for _, v := range output {
		amount += v.Value
	}

	// Remove the amount associated with the inputs we already have.
	for _, v := range input {
		amount -= v.Amount
	}

	// Add the transaction fee to the outputs - we will not
	// redirect this amount in the change output.
	amount += txFee

	// Ensure that we have enough money in the account to make the transaction.
	if a.Balance() < amount {
		return nil, fmt.Errorf("zooko: balance (%d) is too low to make transaction (%d)",
			a.Balance(), amount)
	}

	// Sort the transactions list by amount so that we pick the
	// highest.
	sort.Sort(a.Unspent)

	msgTx := wire.NewMsgTx()
	msgTx.Version = version

	var balance int64
	var toSpend UTXOList
	for balance < amount {
		// Get the next highest transaction
		newTx := a.Unspent[len(toSpend)]

		txIn, err := newTx.ToWire()
		if err != nil {
			return nil, err
		}

		// Convert the UTXO to a TxIn and add to the MsgTx. Currently no scriptSig.
		msgTx.AddTxIn(txIn)

		// Update our structures
		toSpend = append(toSpend, newTx)
		balance += newTx.Amount
	}

	for _, v := range input {
		txIn, err := v.ToWire()
		if err != nil {
			return nil, err
		}

		msgTx.AddTxIn(txIn)

		toSpend = append(toSpend, v)

		// Update the balance and amount to reflect the real
		// numbers.
		balance += v.Amount
		amount += v.Amount
	}

	msgTx.TxOut = output

	// Build a change transaction.
	hasChange := false
	if amount < balance {
		change := balance - amount
		hasChange = true

		addr, err := a.PublicKeyHash()
		if err != nil {
			return nil, err
		}

		// Create the pay to public key hash script.
		pkScript, err := txscript.PayToAddrScript(addr)
		if err != nil {
			return nil, err
		}

		// Add the change transaction.
		msgTx.AddTxOut(wire.NewTxOut(change, pkScript))
	}

	// We will now create the SigScript for each of the TxIn.
	for index, input := range toSpend {
		sigScript, err := txscript.SignTxOutput(&chaincfg.MainNetParams,
			msgTx, index, input.PkScript, txscript.SigHashAll,
			a, nil, nil)
		if err != nil {
			return nil, err
		}

		// Set the signature script on the transaction.
		msgTx.TxIn[index].SignatureScript = sigScript
	}

	// Provide a list of new unspent transactions if we happened
	// to include a change transaction.
	var newUnspent []*UTXO
	if hasChange {
		// The change transaction is always the last index.
		changeIndex := len(msgTx.TxOut) - 1
		change := msgTx.TxOut[changeIndex]

		dataId, err := msgTx.TxSha()
		if err != nil {
			return nil, err
		}

		// Create the new Unspent Transaction Output
		newUnspent = append(newUnspent, &UTXO{
			TxID:     dataId.String(),
			Output:   uint32(changeIndex),
			Amount:   change.Value,
			PkScript: change.PkScript,
		})
	}

	// We must create a change transaction as a TxOut to ourselves
	// and save that as a new UTXO.
	return &Transaction{
		MsgTx: msgTx,

		Spent: toSpend,
		New:   newUnspent,

		Amount: balance,
	}, nil
}