Implement UTXOSet.Update
This commit is contained in:
parent
3e491be4d7
commit
fe34c88dfc
182
utxo_set.go
182
utxo_set.go
|
@ -14,6 +14,87 @@ type UTXOSet struct {
|
||||||
Blockchain *Blockchain
|
Blockchain *Blockchain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindUTXO finds UTXO for a public key hash
|
||||||
|
func (u UTXOSet) FindUTXO(pubKeyHash []byte) []TXOutput {
|
||||||
|
var UTXOs []TXOutput
|
||||||
|
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() {
|
||||||
|
outs := DeserializeOutputs(v)
|
||||||
|
|
||||||
|
for _, out := range outs.Outputs {
|
||||||
|
if out.IsLockedWithKey(pubKeyHash) {
|
||||||
|
UTXOs = append(UTXOs, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return UTXOs
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCount returns the number of transactions in the UTXO set
|
||||||
|
func (u UTXOSet) GetCount() int {
|
||||||
|
db := u.Blockchain.db
|
||||||
|
counter := 0
|
||||||
|
|
||||||
|
err := db.View(func(tx *bolt.Tx) error {
|
||||||
|
b := tx.Bucket([]byte(utxoBucket))
|
||||||
|
c := b.Cursor()
|
||||||
|
|
||||||
|
for k, _ := c.First(); k != nil; k, _ = c.Next() {
|
||||||
|
counter++
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return counter
|
||||||
|
}
|
||||||
|
|
||||||
// Reindex rebuilds the UTXO set
|
// Reindex rebuilds the UTXO set
|
||||||
func (u UTXOSet) Reindex() {
|
func (u UTXOSet) Reindex() {
|
||||||
db := u.Blockchain.db
|
db := u.Blockchain.db
|
||||||
|
@ -61,76 +142,51 @@ func (u UTXOSet) Reindex() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCount returns the number of transactions in the UTXO set
|
// Update updates the UTXO set with transactions from the Block
|
||||||
func (u UTXOSet) GetCount() int {
|
// The Block is considered to be the tip of a blockchain
|
||||||
db := u.Blockchain.db
|
func (u UTXOSet) Update(block *Block) {
|
||||||
counter := 0
|
|
||||||
|
|
||||||
err := db.View(func(tx *bolt.Tx) error {
|
|
||||||
b := tx.Bucket([]byte(utxoBucket))
|
|
||||||
c := b.Cursor()
|
|
||||||
|
|
||||||
for k, _ := c.First(); k != nil; k, _ = c.Next() {
|
|
||||||
counter++
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return counter
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindUTXO finds UTXO for a public key hash
|
|
||||||
func (u UTXOSet) FindUTXO(pubKeyHash []byte) []TXOutput {
|
|
||||||
var UTXOs []TXOutput
|
|
||||||
db := u.Blockchain.db
|
db := u.Blockchain.db
|
||||||
|
|
||||||
err := db.View(func(tx *bolt.Tx) error {
|
err := db.Update(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket([]byte(utxoBucket))
|
b := tx.Bucket([]byte(utxoBucket))
|
||||||
c := b.Cursor()
|
|
||||||
|
|
||||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
for _, tx := range block.Transactions {
|
||||||
outs := DeserializeOutputs(v)
|
if tx.IsCoinbase() == false {
|
||||||
|
for _, vin := range tx.Vin {
|
||||||
for _, out := range outs.Outputs {
|
updatedOuts := TXOutputs{}
|
||||||
if out.IsLockedWithKey(pubKeyHash) {
|
data := b.Get(vin.Txid)
|
||||||
UTXOs = append(UTXOs, out)
|
outs := DeserializeOutputs(data)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
for outIdx, out := range outs.Outputs {
|
||||||
if out.IsLockedWithKey(pubkeyHash) && accumulated < amount {
|
if outIdx != vin.Vout {
|
||||||
accumulated += out.Value
|
updatedOuts.Outputs = append(updatedOuts.Outputs, out)
|
||||||
unspentOutputs[txID] = append(unspentOutputs[txID], outIdx)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(updatedOuts.Outputs) == 0 {
|
||||||
|
err := b.Delete(vin.Txid)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := b.Put(vin.Txid, updatedOuts.Serialize())
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newOutputs := TXOutputs{}
|
||||||
|
for _, out := range tx.Vout {
|
||||||
|
newOutputs.Outputs = append(newOutputs.Outputs, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := b.Put(tx.ID, newOutputs.Serialize())
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -138,6 +194,4 @@ func (u UTXOSet) FindSpendableOutputs(pubkeyHash []byte, amount int) (int, map[s
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return accumulated, unspentOutputs
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue