Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor improvment #11

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@ Part 2: https://www.youtube.com/watch?v=Hl75dJxy2L8

Part 3: https://www.youtube.com/watch?v=h_CY5tDnSoo

Part 4: https://www.youtube.com/watch?v=Ryhp__du_8Q

Part 5: https://www.youtube.com/watch?v=-IiGvPlGhNY

Part 6: https://www.youtube.com/watch?v=4qDqsmjm2PA

TODO:
1- Add multiple transfer money to transaction section
2- Add a reward for every block

Also the name is Bita Coin, Bita is my daughter. Bita means unique in Persian.
24 changes: 21 additions & 3 deletions blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import (
"fmt"
)

const (
Difficulty = 20
)

// BlockChain is the group of a block, with difficulty level
type BlockChain struct {
Difficulty int
Expand All @@ -23,7 +27,7 @@ func (bc *BlockChain) Add(data ...*Transaction) (*Block, error) {
if err != nil {
return nil, fmt.Errorf("Getting the last block failed: %w", err)
}
b := NewBlock(data, bc.Mask, hash)
b := NewBlock(data, bc.Difficulty, hash)
if err := bc.store.Append(b); err != nil {
return nil, fmt.Errorf("Append new block to store failed: %w", err)
}
Expand Down Expand Up @@ -57,10 +61,24 @@ func (bc *BlockChain) Print(header bool, count int) error {
return err
}

// AllBlocks get list of all block
func (bc *BlockChain) AllBlocks() []*Block {
var blocks []*Block
err := Iterate(bc.store, func(b *Block) error {
blocks = append(blocks, b)
return nil
})

if err != nil {

}
return blocks
}

// Validate all data in the block chain
func (bc *BlockChain) Validate() error {
return Iterate(bc.store, func(b *Block) error {
if err := b.Validate(bc.Mask); err != nil {
if err := b.Validate(bc.Difficulty); err != nil {
return fmt.Errorf("block chain is not valid: %w", err)
}

Expand Down Expand Up @@ -124,7 +142,7 @@ func NewBlockChain(genesis []byte, difficulty int, store Store) (*BlockChain, er
return nil, fmt.Errorf("store already initialized")
}
gbTxn := NewCoinBaseTxn(genesis, nil)
gb := NewBlock([]*Transaction{gbTxn}, bc.Mask, []byte{})
gb := NewBlock([]*Transaction{gbTxn}, bc.Difficulty, []byte{})
if err := store.Append(gb); err != nil {
return nil, fmt.Errorf("Add Genesis block to store failed: %w", err)
}
Expand Down
36 changes: 31 additions & 5 deletions blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ package bitacoin

import (
"bytes"
"encoding/gob"
"fmt"
"log"
"time"
)

// Block is the core data for the block chain. it can contain anything,
// a block is like a record in a table in database
type Block struct {
Timestamp time.Time
Difficulty int
Transactions []*Transaction

Nonce int32
Expand All @@ -26,28 +29,51 @@ func (b *Block) String() string {

// Validate try to validate the current block, it needs a difficulty mask
// for validating the hash difficulty
func (b *Block) Validate(mask []byte) error {
func (b *Block) Validate(difficulty int) error {
h := EasyHash(b.Timestamp.UnixNano(), calculateTxnsHash(b.Transactions...), b.PrevHash, b.Nonce)
if !bytes.Equal(h, b.Hash) {
return fmt.Errorf("the hash is invalid it should be %x is %x", h, b.Hash)
}

if !GoodEnough(mask, h) {
return fmt.Errorf("hash is not good enough with mask %x", mask)
if !CompareHash(difficulty, h) {
return fmt.Errorf("hash is not good enough with mask %d", difficulty)
}

return nil
}

// NewBlock creates a new block in the system, it needs deficulty mask for
// create a good hash, and also the previous block hash
func NewBlock(txns []*Transaction, mask, prevHash []byte) *Block {
func NewBlock(txns []*Transaction, difficulty int, prevHash []byte) *Block {
b := Block{
Timestamp: time.Now(),
Transactions: txns,
PrevHash: prevHash,
Difficulty: difficulty,
}
b.Hash, b.Nonce = DifficultHash(mask, b.Timestamp.UnixNano(), calculateTxnsHash(b.Transactions...), b.PrevHash)
b.Hash, b.Nonce = DifficultHash(difficulty, b.Timestamp.UnixNano(), calculateTxnsHash(b.Transactions...), b.PrevHash)

return &b
}

func (b *Block) Serialize() []byte {
var result bytes.Buffer
encoder := gob.NewEncoder(&result)

err := encoder.Encode(b)
if err != nil {
log.Panic(err)
}

return result.Bytes()
}

func DeserializeBlock(d []byte) *Block {
var block Block
decoder := gob.NewDecoder(bytes.NewReader(d))
err := decoder.Decode(&block)
if err != nil {
log.Panic(err)
}
return &block
}
47 changes: 38 additions & 9 deletions cmd/bc/bc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,54 @@ package main

import (
"flag"
"github.com/fzerorubigd/bitacoin"
"github.com/gorilla/mux"
"log"
"net/http"
"os"

"github.com/fzerorubigd/bitacoin"
)

const (
difficulty = 2
)

func main() {

r := mux.NewRouter()

r.HandleFunc("/hash/{hash}", bitacoin.HashDetail)
r.HandleFunc("/", bitacoin.Index)
r.HandleFunc("/transfer", bitacoin.Transfer)
r.HandleFunc("/balance/{owner}", bitacoin.Balance)
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("template/static"))))

http.Handle("/", r)

err := http.ListenAndServe(":9000", nil)
if err != nil {
return
}

//flag.Usage = usage
//flag.Parse()

//Run file base
//runByFile()

//Run db format
//runBoltDB()
}

func runByFile() {
var store string
flag.StringVar(&store, "store", os.Getenv("BC_STORE"), "The store to use")
flag.Usage = usage
flag.Parse()

s := bitacoin.NewFolderStore(store)

if err := dispatch(s, flag.Args()...); err != nil {
log.Fatal(err.Error())
}
}

func runBoltDB() {

d := bitacoin.NewDBStore()
if err := dispatch(d, flag.Args()...); err != nil {
log.Fatal(err.Error())
}
}
2 changes: 1 addition & 1 deletion cmd/bc/cli_balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func balance(store bitacoin.Store, args ...string) error {

fs.Parse(args[1:])

bc, err := bitacoin.OpenBlockChain(difficulty, store)
bc, err := bitacoin.OpenBlockChain(bitacoin.Difficulty, store)
if err != nil {
return fmt.Errorf("open failed: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/bc/cli_initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func initialize(store bitacoin.Store, args ...string) error {

fs.Parse(args[1:])

_, err := bitacoin.NewBlockChain([]byte(genesis), difficulty, store)
_, err := bitacoin.NewBlockChain([]byte(genesis), bitacoin.Difficulty, store)
if err != nil {
return fmt.Errorf("create failed: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/bc/cli_print.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func print(store bitacoin.Store, args ...string) error {

fs.Parse(args[1:])

bc, err := bitacoin.OpenBlockChain(difficulty, store)
bc, err := bitacoin.OpenBlockChain(bitacoin.Difficulty, store)
if err != nil {
return fmt.Errorf("open failed: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/bc/cli_transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func transfer(store bitacoin.Store, args ...string) error {

fs.Parse(args[1:])

bc, err := bitacoin.OpenBlockChain(difficulty, store)
bc, err := bitacoin.OpenBlockChain(bitacoin.Difficulty, store)
if err != nil {
return fmt.Errorf("open failed: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/bc/cli_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func validate(store bitacoin.Store, args ...string) error {

fs.Parse(args[1:])

bc, err := bitacoin.OpenBlockChain(difficulty, store)
bc, err := bitacoin.OpenBlockChain(bitacoin.Difficulty, store)
if err != nil {
return fmt.Errorf("open failed: %w", err)
}
Expand Down
107 changes: 107 additions & 0 deletions cmd/bc/template/balance.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<!DOCTYPE html>
<html lang="en">
{% include "header.html" %}
<body>

<div >
{% include "navbar.html" %}

<header class="bg-white shadow">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold text-gray-900">
Details of hash
</h1>
</div>
</header>
<main>
<div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">

<div class="bg-purple-600 bg-opacity-100 rounded-lg text-white text-center text-3xl p-10">
Balance of {{name}} is {{ acc }} $
</div>
<div class="px-4 py-6 sm:px-0">
{% for i,t in transaction %}
<br><br>
Transaction ID
{{ t.ID |stringformat:"%x" }}
<div class="flex flex-col">
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">

<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">

<tr>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">

</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
</th>
</tr>

</thead>
<tbody class="bg-white divide-y divide-gray-200">
{% for o in t.VOut %}
<tr class=" bg-green-50">
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
Value
</td>
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
{{ o.Value |stringformat:"%d" }} $
</td>
</tr>
<tr class=" bg-green-100">
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
Public Key
</td>
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
<a href="/balance/{{ o.PubKey |stringformat:" %s"}}">
{{ o.PubKey |stringformat:"%s" }}
</a>
</td>
</tr>

{% endfor %}

{% for o in t.VIn %}
<tr class="bg-indigo-50">
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
Transaction ID
</td>
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
{{ o.TXID |stringformat:"%x" }}
</td>
</tr>
<tr class="bg-indigo-50">
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
Index of transaction out:
</td>
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
{{ o.VOut |stringformat:"%d" }}
</td>
</tr>
<tr class="bg-indigo-50">
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
Signiture
</td>
<td class="px-6 py-4 whitespace-nowrap text-left text-sm font-medium">
{{ o.Sig |stringformat:"%x" }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</main>
</div>
</body>
</html>
Loading