The core protocol of WoopChain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
woop/blockchain/blockchain.go

99 lines
2.4 KiB

package blockchain
import (
6 years ago
"encoding/hex"
)
// Blockchain keeps a sequence of Blocks
type Blockchain struct {
6 years ago
blocks []*Block
}
const genesisCoinbaseData = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
// FindUnspentTransactions returns a list of transactions containing unspent outputs
func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction {
6 years ago
var unspentTXs []Transaction
spentTXOs := make(map[string][]int)
for index := len(bc.blocks) - 1; index >= 0; index-- {
block := bc.blocks[index]
BreakTransaction:
for _, tx := range block.Transactions {
6 years ago
txID := hex.EncodeToString(tx.ID)
6 years ago
idx := -1
if spentTXOs[txID] != nil {
6 years ago
idx = 0
}
6 years ago
for outIdx, txOutput := range tx.TxOutput {
if idx >= 0 && spentTXOs[txID][idx] == outIdx {
6 years ago
idx++
continue
}
6 years ago
if txOutput.Address == address {
6 years ago
unspentTXs = append(unspentTXs, *tx)
continue BreakTransaction
}
}
}
}
return unspentTXs
}
// FindUTXO finds and returns all unspent transaction outputs
func (bc *Blockchain) FindUTXO(address string) []TXOutput {
6 years ago
var UTXOs []TXOutput
unspentTXs := bc.FindUnspentTransactions(address)
for _, tx := range unspentTXs {
6 years ago
for _, txOutput := range tx.TxOutput {
if txOutput.Address == address {
6 years ago
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) {
6 years ago
unspentOutputs := make(map[string][]int)
unspentTXs := bc.FindUnspentTransactions(address)
accumulated := 0
Work:
6 years ago
for _, tx := range unspentTXs {
6 years ago
txID := hex.EncodeToString(tx.ID)
6 years ago
6 years ago
for outIdx, txOutput := range tx.TxOutput {
if txOutput.Address == address && accumulated < amount {
accumulated += txOutput.Value
6 years ago
unspentOutputs[txID] = append(unspentOutputs[txID], outIdx)
if accumulated >= amount {
break Work
}
}
}
}
return accumulated, unspentOutputs
}
// CreateBlockchain creates a new blockchain DB
func CreateBlockchain(address string) *Blockchain {
// TODO: We assume we have not created any blockchain before.
// In current bitcoin, we can check if we created a blockchain before accessing local db.
cbtx := NewCoinbaseTX(address, genesisCoinbaseData)
genesis := NewGenesisBlock(cbtx)
bc := Blockchain{[]*Block{genesis}}
return &bc
}