Use the UTXO set to send coins
This commit is contained in:
parent
0b7d2ac63f
commit
3e491be4d7
|
@ -95,31 +95,6 @@ func NewBlockchain() *Blockchain {
|
|||
return &bc
|
||||
}
|
||||
|
||||
// FindSpendableOutputs finds and returns unspent outputs to reference in inputs
|
||||
func (bc *Blockchain) FindSpendableOutputs(pubKeyHash []byte, amount int) (int, map[string][]int) {
|
||||
unspentOutputs := make(map[string][]int)
|
||||
unspentTXs := bc.FindUnspentTransactions(pubKeyHash)
|
||||
accumulated := 0
|
||||
|
||||
Work:
|
||||
for _, tx := range unspentTXs {
|
||||
txID := hex.EncodeToString(tx.ID)
|
||||
|
||||
for outIdx, out := range tx.Vout {
|
||||
if out.IsLockedWithKey(pubKeyHash) && accumulated < amount {
|
||||
accumulated += out.Value
|
||||
unspentOutputs[txID] = append(unspentOutputs[txID], outIdx)
|
||||
|
||||
if accumulated >= amount {
|
||||
break Work
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return accumulated, unspentOutputs
|
||||
}
|
||||
|
||||
// FindTransaction finds a transaction by its ID
|
||||
func (bc *Blockchain) FindTransaction(ID []byte) (Transaction, error) {
|
||||
bci := bc.Iterator()
|
||||
|
@ -141,52 +116,6 @@ func (bc *Blockchain) FindTransaction(ID []byte) (Transaction, error) {
|
|||
return Transaction{}, errors.New("Transaction is not found")
|
||||
}
|
||||
|
||||
// FindUnspentTransactions returns a list of transactions containing unspent outputs
|
||||
func (bc *Blockchain) FindUnspentTransactions(pubKeyHash []byte) []Transaction {
|
||||
var unspentTXs []Transaction
|
||||
spentTXOs := make(map[string][]int)
|
||||
bci := bc.Iterator()
|
||||
|
||||
for {
|
||||
block := bci.Next()
|
||||
|
||||
for _, tx := range block.Transactions {
|
||||
txID := hex.EncodeToString(tx.ID)
|
||||
|
||||
Outputs:
|
||||
for outIdx, out := range tx.Vout {
|
||||
// Was the output spent?
|
||||
if spentTXOs[txID] != nil {
|
||||
for _, spentOutIdx := range spentTXOs[txID] {
|
||||
if spentOutIdx == outIdx {
|
||||
continue Outputs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if out.IsLockedWithKey(pubKeyHash) {
|
||||
unspentTXs = append(unspentTXs, *tx)
|
||||
}
|
||||
}
|
||||
|
||||
if tx.IsCoinbase() == false {
|
||||
for _, in := range tx.Vin {
|
||||
if in.UsesKey(pubKeyHash) {
|
||||
inTxID := hex.EncodeToString(in.Txid)
|
||||
spentTXOs[inTxID] = append(spentTXOs[inTxID], in.Vout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(block.PrevBlockHash) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return unspentTXs
|
||||
}
|
||||
|
||||
// FindAllUTXO finds all unspent transaction outputs and returns transactions with spent outputs removed
|
||||
func (bc *Blockchain) FindAllUTXO() map[string]TXOutputs {
|
||||
UTXO := make(map[string]TXOutputs)
|
||||
|
|
|
@ -14,9 +14,10 @@ func (cli *CLI) send(from, to string, amount int) {
|
|||
}
|
||||
|
||||
bc := NewBlockchain()
|
||||
UTXOSet := UTXOSet{bc}
|
||||
defer bc.db.Close()
|
||||
|
||||
tx := NewUTXOTransaction(from, to, amount, bc)
|
||||
tx := NewUTXOTransaction(from, to, amount, &UTXOSet)
|
||||
cbTx := NewCoinbaseTX(from, "")
|
||||
txs := []*Transaction{cbTx, tx}
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ func NewCoinbaseTX(to, data string) *Transaction {
|
|||
}
|
||||
|
||||
// NewUTXOTransaction creates a new transaction
|
||||
func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transaction {
|
||||
func NewUTXOTransaction(from, to string, amount int, UTXOSet *UTXOSet) *Transaction {
|
||||
var inputs []TXInput
|
||||
var outputs []TXOutput
|
||||
|
||||
|
@ -195,7 +195,7 @@ func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transactio
|
|||
}
|
||||
wallet := wallets.GetWallet(from)
|
||||
pubKeyHash := HashPubKey(wallet.PublicKey)
|
||||
acc, validOutputs := bc.FindSpendableOutputs(pubKeyHash, amount)
|
||||
acc, validOutputs := UTXOSet.FindSpendableOutputs(pubKeyHash, amount)
|
||||
|
||||
if acc < amount {
|
||||
log.Panic("ERROR: Not enough funds")
|
||||
|
@ -222,7 +222,7 @@ func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transactio
|
|||
|
||||
tx := Transaction{nil, inputs, outputs}
|
||||
tx.ID = tx.Hash()
|
||||
bc.SignTransaction(&tx, wallet.PrivateKey)
|
||||
UTXOSet.Blockchain.SignTransaction(&tx, wallet.PrivateKey)
|
||||
|
||||
return &tx
|
||||
}
|
||||
|
|
31
utxo_set.go
31
utxo_set.go
|
@ -110,3 +110,34 @@ func (u UTXOSet) FindUTXO(pubKeyHash []byte) []TXOutput {
|
|||
|
||||
return UTXOs
|
||||
}
|
||||
|
||||
// FindSpendableOutputs finds and returns unspent outputs to reference in inputs
|
||||
func (u UTXOSet) FindSpendableOutputs(pubkeyHash []byte, amount int) (int, map[string][]int) {
|
||||
unspentOutputs := make(map[string][]int)
|
||||
accumulated := 0
|
||||
db := u.Blockchain.db
|
||||
|
||||
err := db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte(utxoBucket))
|
||||
c := b.Cursor()
|
||||
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
txID := hex.EncodeToString(k)
|
||||
outs := DeserializeOutputs(v)
|
||||
|
||||
for outIdx, out := range outs.Outputs {
|
||||
if out.IsLockedWithKey(pubkeyHash) && accumulated < amount {
|
||||
accumulated += out.Value
|
||||
unspentOutputs[txID] = append(unspentOutputs[txID], outIdx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
return accumulated, unspentOutputs
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue