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/utxopool.go

116 lines
3.2 KiB

package blockchain
import (
"encoding/hex"
)
// UTXOPool stores transactions and balance associated with each address.
type UTXOPool struct {
// Mapping from address to a map of transaction id to a map of the index of output
// array in that transaction to that balance.
utxo map[string]map[string]int
}
// VerifyTransactions verifies if a list of transactions valid.
func (utxopool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool {
spentTXOs := make(map[string]map[string]bool)
if utxopool != nil {
for _, tx := range transactions {
inTotal := 0
// Calculate the sum of TxInput
for _, in := range tx.TxInput {
inTxID := hex.EncodeToString(in.TxID)
// Check if the transaction with the addres is spent or not.
if val, ok := spentTXOs[in.Address][inTxID]; ok {
if val {
return false
}
}
// Mark the transactions with the addres spent.
if _, ok := spentTXOs[in.Address]; ok {
spentTXOs[in.Address][inTxID] = true
} else {
spentTXOs[in.Address] = make(map[string]bool)
spentTXOs[in.Address][inTxID] = true
}
// Sum the balance up to the inTotal.
if val, ok := utxopool.utxo[in.Address][inTxID]; ok {
inTotal += val
} else {
return false
}
}
outTotal := 0
// Calculate the sum of TxOutput
for _, out := range tx.TxOutput {
outTotal += out.Value
}
if inTotal != outTotal {
return false
}
}
}
return true
}
// VerifyAndUpdate verifies a list of transactions and update utxoPool.
func (utxopool *UTXOPool) VerifyAndUpdate(transactions []*Transaction) bool {
if utxopool.VerifyTransactions(transactions) {
utxopool.Update(transactions)
return true
}
return false
}
// Update utxo balances with a list of new transactions.
func (utxopool *UTXOPool) Update(transactions []*Transaction) {
if utxopool != nil {
for _, tx := range transactions {
curTxID := hex.EncodeToString(tx.ID)
// Remove
for _, in := range tx.TxInput {
inTxID := hex.EncodeToString(in.TxID)
delete(utxopool.utxo[in.Address], inTxID)
}
// Update
for _, out := range tx.TxOutput {
if _, ok := utxopool.utxo[out.Address]; ok {
utxopool.utxo[out.Address][curTxID] = out.Value
} else {
utxopool.utxo[out.Address] = make(map[string]int)
utxopool.utxo[out.Address][curTxID] = out.Value
}
}
}
}
}
// CreateUTXOPoolFromTransaction a utxo pool from a genesis transaction.
func CreateUTXOPoolFromTransaction(tx *Transaction) *UTXOPool {
var utxoPool UTXOPool
txID := hex.EncodeToString(tx.ID)
utxoPool.utxo = make(map[string]map[string]int)
for _, out := range tx.TxOutput {
utxoPool.utxo[out.Address] = make(map[string]int)
utxoPool.utxo[out.Address][txID] = DefaultCoinbaseValue
}
return &utxoPool
}
// CreateUTXOPoolFromGenesisBlockChain a utxo pool from a genesis blockchain.
func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool {
tx := bc.blocks[0].Transactions[0]
var utxoPool UTXOPool
txID := hex.EncodeToString(tx.ID)
utxoPool.utxo = make(map[string]map[string]int)
for _, out := range tx.TxOutput {
utxoPool.utxo[out.Address] = make(map[string]int)
utxoPool.utxo[out.Address][txID] = DefaultCoinbaseValue
}
return &utxoPool
}