diff --git a/blockchain.go b/blockchain.go index ca77f50c6..f40b82153 100644 --- a/blockchain.go +++ b/blockchain.go @@ -1,5 +1,9 @@ package main +import ( + "encoding/hex" +) + // Blockchain keeps a sequence of Blocks type Blockchain struct { blocks []*Block @@ -17,4 +21,77 @@ func (bc *Blockchain) AddBlock(data string) { // NewBlockchain creates a new Blockchain with genesis Block func NewBlockchain() *Blockchain { return &Blockchain{[]*Block{NewGenesisBlock()}} -} \ No newline at end of file +} + +// FindUnspentTransactions returns a list of transactions containing unspent outputs +func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction { + var unspentTXs []Transaction + spentTXOs := make(map[string][]int) + + for index := len(bc.blocks); index >= 0; index-- { + block := bc.blocks[index]; + + BreakTransaction: + for _, tx := range block.Transactions { + txId := hex.EncodeToString(tx.Id) + + idx := -1 + if spentTXOs[txId] != nil { + idx = 0 + } + for outIdx, txOutput := range tx.txOutput { + if idx >= 0 spentTXOs[txId][idx] == outIdx { + continue + } + + if txOutput.address == address { + unspentTXs = append(unspentTXs, *tx) + continue BreakTransaction + } + } + } + } + return unspentTXs +} + +// FindUTXO finds and returns all unspent transaction outputs +func (bc *Blockchain) FindUTXO(address string) []TXOutput { + var UTXOs []TXOutput + unspentTXs := bc.FindUnspentTransactions(address) + + for _, tx := range unspentTXs { + for _, txOutput := range tx.txOutput { + if txOutput.address == address { + UTXOs = append(UTXOs, txOutput) + break + } + } + } + + return UTXOs +} + +// FindSpendableOutputs finds and returns unspent outputs to reference in inputs +func (bc *Blockchain) FindSpendableOutputs(address string, amount int) (int, map[string][]int) { + unspentOutputs := make(map[string][]int) + unspentTXs := bc.FindUnspentTransactions(address) + accumulated := 0 + +Work: + for _, tx := range unspentTXs { + txID := hex.EncodeToString(tx.ID) + + for outIdx, txOutput := range tx.txOutput { + if txOutput.address == address && accumulated < amount { + accumulated += txOutput.value + unspentOutputs[txID] = append(unspentOutputs[txID], outIdx) + + if accumulated >= amount { + break Work + } + } + } + } + + return accumulated, unspentOutputs +} diff --git a/transaction.go b/transaction.go index 0c44dde1f..f37fdc7f4 100644 --- a/transaction.go +++ b/transaction.go @@ -9,24 +9,24 @@ import ( // Transaction represents a Bitcoin transaction type Transaction struct { - ID []byte - Vin []TXInput - Vout []TXOutput + id []byte + txInput []TXInput + txOutput []TXOutput } type TXOutput struct { - Addresss string - Value int + address string + value int } type TXInput struct { - Txid []byte - outIndex int - Address string + txId []byte + txOutputIndex int + address string } // SetID sets ID of a transaction -func (tx *Transaction) SetID() { +func (tx *Transaction) SetId() { var encoded bytes.Buffer var hash [32]byte