parent
73b873b90b
commit
800cdb575d
@ -1,8 +1,10 @@ |
||||
{ |
||||
"workbench.colorTheme": "Solarized Light", |
||||
"npm.enableScriptExplorer": true, |
||||
"window.zoomLevel": 3, |
||||
"editor.tabSize": 4, |
||||
"editor.insertSpaces": true, |
||||
"editor.detectIndentation": true |
||||
} |
||||
"workbench.colorTheme": "Solarized Light", |
||||
"npm.enableScriptExplorer": true, |
||||
"window.zoomLevel": 3, |
||||
"editor.tabSize": 4, |
||||
"editor.insertSpaces": true, |
||||
"editor.detectIndentation": false, |
||||
"editor.tabCompletion": true, |
||||
} |
||||
|
@ -1,98 +1,98 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/hex" |
||||
"encoding/hex" |
||||
) |
||||
|
||||
// Blockchain keeps a sequence of Blocks
|
||||
type Blockchain struct { |
||||
blocks []*Block |
||||
blocks []*Block |
||||
} |
||||
|
||||
// AddBlock saves provided data as a block in the blockchain
|
||||
func (bc *Blockchain) AddBlock(data string) { |
||||
prevBlock := bc.blocks[len(bc.blocks)-1] |
||||
prevBlock := bc.blocks[len(bc.blocks)-1] |
||||
|
||||
// TODO(minhdoan): Parse data.
|
||||
newBlock := NewBlock({}, prevBlock.Hash) |
||||
bc.blocks = append(bc.blocks, newBlock) |
||||
// TODO(minhdoan): Parse data.
|
||||
newBlock := NewBlock({}, prevBlock.Hash) |
||||
bc.blocks = append(bc.blocks, newBlock) |
||||
} |
||||
|
||||
// NewBlockchain creates a new Blockchain with genesis Block
|
||||
func NewBlockchain() *Blockchain { |
||||
return &Blockchain{[]*Block{NewGenesisBlock()}} |
||||
return &Blockchain{[]*Block{NewGenesisBlock()}} |
||||
} |
||||
|
||||
// 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) - 1; 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 { |
||||
idx++ |
||||
continue |
||||
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 { |
||||
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 { |
||||
idx++ |
||||
continue |
||||
} |
||||
|
||||
if txOutput.address == address { |
||||
unspentTXs = append(unspentTXs, *tx) |
||||
continue BreakTransaction |
||||
} |
||||
} |
||||
} |
||||
|
||||
if txOutput.address == address { |
||||
unspentTXs = append(unspentTXs, *tx) |
||||
continue BreakTransaction |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return unspentTXs |
||||
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 |
||||
} |
||||
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 |
||||
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 |
||||
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 |
||||
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 |
||||
return accumulated, unspentOutputs |
||||
} |
||||
|
@ -1,40 +1,40 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"bytes" |
||||
"crypto/sha256" |
||||
"encoding/gob" |
||||
"log" |
||||
"bytes" |
||||
"crypto/sha256" |
||||
"encoding/gob" |
||||
"log" |
||||
) |
||||
|
||||
// Transaction represents a Bitcoin transaction
|
||||
type Transaction struct { |
||||
id []byte |
||||
txInput []TXInput |
||||
txOutput []TXOutput |
||||
id []byte |
||||
txInput []TXInput |
||||
txOutput []TXOutput |
||||
} |
||||
|
||||
type TXOutput struct { |
||||
address string |
||||
value int |
||||
address string |
||||
value int |
||||
} |
||||
|
||||
type TXInput struct { |
||||
txId []byte |
||||
txOutputIndex int |
||||
address string |
||||
txId []byte |
||||
txOutputIndex int |
||||
address string |
||||
} |
||||
|
||||
// SetID sets ID of a transaction
|
||||
func (tx *Transaction) SetId() { |
||||
var encoded bytes.Buffer |
||||
var hash [32]byte |
||||
var encoded bytes.Buffer |
||||
var hash [32]byte |
||||
|
||||
enc := gob.NewEncoder(&encoded) |
||||
err := enc.Encode(tx) |
||||
if err != nil { |
||||
log.Panic(err) |
||||
} |
||||
hash = sha256.Sum256(encoded.Bytes()) |
||||
tx.ID = hash[:] |
||||
enc := gob.NewEncoder(&encoded) |
||||
err := enc.Encode(tx) |
||||
if err != nil { |
||||
log.Panic(err) |
||||
} |
||||
hash = sha256.Sum256(encoded.Bytes()) |
||||
tx.ID = hash[:] |
||||
} |
||||
|
Loading…
Reference in new issue