diff --git a/UTXOPool.go b/UTXOPool.go new file mode 100644 index 000000000..79073170a --- /dev/null +++ b/UTXOPool.go @@ -0,0 +1,37 @@ +package main + +// UTXOPool is the data structure to store the current balance. +type UTXOPool struct { + utxos map[string]int +} + +// func (utxoPool *UTXOPool) handleTransaction(transaction Transaction, receiver string) { +// if !isValidTransaction(transaction) { +// return +// } +// // utxoPool[] +// } + +// func (utxoPool *UTXOPool) isValidTransaction(transaction Transaction) { +// const { inputPublicKey, amount, fee } = transaction +// const utxo = this.utxos[inputPublicKey] +// return utxo !== undefined && utxo.amount >= (amount + fee) && amount > 0 +// } + +// func (utxoPool *UTXOPool) handleTransaction(transaction, feeReceiver) { +// if (!this.isValidTransaction(transaction)) +// return +// const inputUTXO = this.utxos[transaction.inputPublicKey]; +// inputUTXO.amount -= transaction.amount +// inputUTXO.amount -= transaction.fee +// if (inputUTXO.amount === 0) +// delete this.utxos[transaction.inputPublicKey] +// this.addUTXO(transaction.outputPublicKey, transaction.amount) +// this.addUTXO(feeReceiver, transaction.fee) +// } + +// func (utxoPool *UTXOPool) isValidTransaction(transaction Transaction) { +// const { inputPublicKey, amount, fee } = transaction +// const utxo = utxoPool.utxos[inputPublicKey] +// return utxo !== undefined && utxo.amount >= (amount + fee) && amount > 0 +// } diff --git a/block.go b/block.go index dd0afd1ff..9af9cac92 100644 --- a/block.go +++ b/block.go @@ -10,28 +10,30 @@ import ( // Block keeps block headers type Block struct { Timestamp int64 - Data []byte + utxoPool []UTXOPool PrevBlockHash []byte Hash []byte } -// SetHash calculates and sets block hash +//SetHash calculates and sets block hash func (b *Block) SetHash() { timestamp := []byte(strconv.FormatInt(b.Timestamp, 10)) - headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{}) + // headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{}) + headers := bytes.Join([][]byte{b.PrevBlockHash, timestamp}, []byte{}) hash := sha256.Sum256(headers) b.Hash = hash[:] } // NewBlock creates and returns Block -func NewBlock(data string, prevBlockHash []byte) *Block { - block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}} +func NewBlock(utxoPool []UTXOPool, prevBlockHash []byte) *Block { + + block := &Block{time.Now().Unix(), utxoPool, prevBlockHash, []byte{}} block.SetHash() return block } // NewGenesisBlock creates and returns genesis Block func NewGenesisBlock() *Block { - return NewBlock("Genesis Block", []byte{}) + return NewBlock([]UTXOPool{}, []byte{}) } diff --git a/blockchain.go b/blockchain.go index 7d72857b7..3662f6868 100644 --- a/blockchain.go +++ b/blockchain.go @@ -8,7 +8,9 @@ type Blockchain struct { // AddBlock saves provided data as a block in the blockchain func (bc *Blockchain) AddBlock(data string) { prevBlock := bc.blocks[len(bc.blocks)-1] - newBlock := NewBlock(data, prevBlock.Hash) + + // TODO(minhdoan): Parse data. + newBlock := NewBlock({}, prevBlock.Hash) bc.blocks = append(bc.blocks, newBlock) } diff --git a/transaction.go b/transaction.go new file mode 100644 index 000000000..0e68efc2e --- /dev/null +++ b/transaction.go @@ -0,0 +1,35 @@ +package main + +import ( + "bytes" + "crypto/sha256" + "encoding/gob" + "log" + "strings" +) + +const subsidy = 10 + +// Transaction represents a Bitcoin transaction +type Transaction struct { + ID []byte + data string +} + +func (tx *Transaction) Parse() { + strings.Split("a,b,c", ",") +} + +// SetID sets ID of a transaction +func (tx *Transaction) SetID() { + 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[:] +} diff --git a/utils.go b/utils.go index 8651f741c..e3813f87a 100644 --- a/utils.go +++ b/utils.go @@ -5,6 +5,8 @@ import ( "encoding/binary" "encoding/gob" "log" + "strconv" + "strings" ) // IntToHex converts an int64 to a byte array @@ -37,3 +39,32 @@ func DeserializeBlock(d []byte) *Block { return &block } + +// 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) == 2 { + intValue, err := strconv.Atoi(pair[1]) + if err != nil { + pair[0] = strings.Trim(pair[0]) + res[pair[0]] = intValue + } + } + } + return res +} diff --git a/utils_test.go b/utils_test.go new file mode 100644 index 000000000..bc7255297 --- /dev/null +++ b/utils_test.go @@ -0,0 +1,25 @@ +package main + +import "testing" + +func TestConvertIntoMap(t *testing.T) { + data := "minh:3,mike:2" + res := ConvertIntoMap(data) + if len(res) != 2 { + t.Errorf("Result should have 2 pairs (key, value)") + } + if val, ok := res["minh"]; !ok { + t.Errorf("Result should contain key minh") + } else { + if res["minh"] != 3 { + t.Errorf("Value of minh should be 3") + } + } + if val, ok := res["mike"]; !ok { + t.Errorf("Result should contain key mike") + } else { + if res["minh"] != 3 { + t.Errorf("Value of minh should be 2") + } + } +}