parent
4cd5370f9c
commit
32d1f71ac1
@ -1,98 +1,89 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/hex" |
||||
"encoding/hex" |
||||
) |
||||
|
||||
// Blockchain keeps a sequence of Blocks
|
||||
type Blockchain struct { |
||||
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] |
||||
|
||||
// TODO(minhdoan): Parse data.
|
||||
newBlock := NewBlock({}, prevBlock.Hash) |
||||
bc.blocks = append(bc.blocks, newBlock) |
||||
blocks []*Block |
||||
} |
||||
|
||||
// NewBlockchain creates a new Blockchain with genesis Block
|
||||
func NewBlockchain() *Blockchain { |
||||
return &Blockchain{[]*Block{NewGenesisBlock()}} |
||||
func NewBlockchain(address string) *Blockchain { |
||||
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 |
||||
} |
||||
|
||||
if txOutput.address == address { |
||||
unspentTXs = append(unspentTXs, *tx) |
||||
continue BreakTransaction |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return unspentTXs |
||||
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 |
||||
} |
||||
} |
||||
} |
||||
} |
||||
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 |
||||
} |
||||
} |
||||
} |
||||
|
||||
return UTXOs |
||||
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 |
||||
} |
||||
|
||||
// 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 |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return accumulated, unspentOutputs |
||||
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 |
||||
} |
||||
|
@ -1,70 +1,32 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/binary" |
||||
"encoding/gob" |
||||
"log" |
||||
"strconv" |
||||
"strings" |
||||
"bytes" |
||||
"encoding/binary" |
||||
"log" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
// IntToHex converts an int64 to a byte array
|
||||
func IntToHex(num int64) []byte { |
||||
buff := new(bytes.Buffer) |
||||
err := binary.Write(buff, binary.BigEndian, num) |
||||
if err != nil { |
||||
log.Panic(err) |
||||
} |
||||
buff := new(bytes.Buffer) |
||||
err := binary.Write(buff, binary.BigEndian, num) |
||||
if err != nil { |
||||
log.Panic(err) |
||||
} |
||||
|
||||
return buff.Bytes() |
||||
} |
||||
|
||||
// Serialize is to serialize a block into []byte.
|
||||
func (b *Block) Serialize() []byte { |
||||
var result bytes.Buffer |
||||
encoder := gob.NewEncoder(&result) |
||||
|
||||
err := encoder.Encode(b) |
||||
|
||||
return result.Bytes() |
||||
} |
||||
|
||||
// DeserializeBlock is to deserialize []byte into a Block.
|
||||
func DeserializeBlock(d []byte) *Block { |
||||
var block Block |
||||
|
||||
decoder := gob.NewDecoder(bytes.NewReader(d)) |
||||
err := decoder.Decode(&block) |
||||
|
||||
return &block |
||||
return buff.Bytes() |
||||
} |
||||
|
||||
// Helper library to convert '1,2,3,4' into []int{1,2,3,4}.
|
||||
func ConvertIntoInts(data string) []int { |
||||
var res = []int{} |
||||
items := strings.Split(data, " ") |
||||
for _, value := range items { |
||||
intValue, err := strconv.Atoi(value) |
||||
checkError(err) |
||||
res = append(res, intValue) |
||||
} |
||||
return res |
||||
} |
||||
|
||||
// Helper library to convert '1,2,3,4' into []int{1,2,3,4}.
|
||||
func ConvertIntoMap(data string) map[string]int { |
||||
var res = map[string]int |
||||
items := strings.Split(data, ",") |
||||
for _, value := range items { |
||||
pair := strings.Split(value, " ") |
||||
if len(pair) == 3 { |
||||
intValue, err := strconv.Atoi(pair[2]) |
||||
if err != nil { |
||||
pair[0] = strings.Trim(pair[0]) |
||||
res[pair[0]] = intValue |
||||
} |
||||
} |
||||
} |
||||
return res |
||||
var res = []int{} |
||||
items := strings.Split(data, " ") |
||||
for _, value := range items { |
||||
intValue, err := strconv.Atoi(value) |
||||
checkError(err) |
||||
res = append(res, intValue) |
||||
} |
||||
return res |
||||
} |
||||
|
Loading…
Reference in new issue