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