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

cli: show timestamp of the block #3

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c0accf3
cli: show timestamp of the block
RichardWeiYang Oct 11, 2017
5e43c77
merkle tree: fix the implementation and add a test case
RichardWeiYang Oct 16, 2017
cee6700
base58: fix Base58Decode on calculating the zeroBytes
RichardWeiYang Oct 16, 2017
f9935da
base58_test: add test case for Base58
RichardWeiYang Oct 16, 2017
782db48
cli: add three cli command for exploring
RichardWeiYang Oct 16, 2017
42b9dbb
version: display the addree when a new node is connected
RichardWeiYang Oct 18, 2017
8ea4bc8
Use View instead of Update in NewBlockchain()
RichardWeiYang Oct 18, 2017
29099f0
check wallet before sending
RichardWeiYang Oct 18, 2017
009fda2
display the number of tx mined
RichardWeiYang Oct 18, 2017
2974ee8
cli: print PubKeyHash in getAddress
RichardWeiYang Oct 18, 2017
5f4f2f5
cli: add command getPubKeyHash
RichardWeiYang Oct 18, 2017
36cfffc
cli: add getBlock command
RichardWeiYang Oct 19, 2017
01d18ce
add Address in TXOut
RichardWeiYang Oct 19, 2017
5c88b24
display the addresse in TXIn and optmize getAddress command
RichardWeiYang Oct 19, 2017
c410eb2
display the private key
RichardWeiYang Oct 20, 2017
9f6ac35
update gitignore
RichardWeiYang Oct 21, 2017
64cf474
fix private key display
RichardWeiYang Oct 21, 2017
04318d7
cli: generatePrivKey
RichardWeiYang Oct 21, 2017
b415f08
make it a package bc
RichardWeiYang Oct 22, 2017
c72ff7f
Change README for bc package
RichardWeiYang Oct 22, 2017
cb4ae18
export DB in blockchain
RichardWeiYang Oct 22, 2017
9b2f73b
add PrintHTML method to chain
RichardWeiYang Oct 22, 2017
56c9e3f
add GetBalance to chain
RichardWeiYang Oct 22, 2017
db3fe41
more detail explanation
RichardWeiYang Oct 31, 2017
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
*.db
*.dat
cscope.*
.*.swp
blockchain_go
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,29 @@ A blockchain implementation in Go, as described in these articles:
5. [Addresses](https://jeiwan.cc/posts/building-blockchain-in-go-part-5/)
6. [Transactions 2](https://jeiwan.cc/posts/building-blockchain-in-go-part-6/)
7. [Network](https://jeiwan.cc/posts/building-blockchain-in-go-part-7/)

# Quick Start

## Download and install

go get github.com/richardweiyang/blockchain_go

## Create file `main.go`

source code

```go
package main

import "github.com/richardweiyang/blockchain_go"

func main() {
cli := bc.CLI{}
cli.Run()
}
```
#### Build and run

go build main.go
./main

6 changes: 4 additions & 2 deletions base58.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package bc
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid this is against the idea of the project: it should be a standalone app, not a package. Why did you decide to make this change?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, this is up to you. I just add it for my purpose.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, actually, I am not comfortable with the GitHub pull request.

Since what I want you to take is the fix on Decoder and merkle tree, the #2 - #4 commit.

While GitHub automatically create the pull request with all my new commits on master branch.

How could I send a pull request just with dedicated commit? or you could pick up the one you want? or I have to make a clean master branch so that you can pull?


import (
"bytes"
Expand Down Expand Up @@ -40,8 +40,10 @@ func Base58Decode(input []byte) []byte {
zeroBytes := 0

for _, b := range input {
if b == 0x00 {
if b == b58Alphabet[0] {
zeroBytes++
} else {
break
}
}

Expand Down
27 changes: 27 additions & 0 deletions base58_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package bc

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestBase58(t *testing.T) {
for i := 0; i < 100; i++ {
_, public := newKeyPair()
pubKeyHash := HashPubKey(public)

versionedPayload := append([]byte{version}, pubKeyHash...)
checksum := checksum(versionedPayload)

fullPayload := append(versionedPayload, checksum...)
address := Base58Encode(fullPayload)

assert.Equal(
t,
ValidateAddress(string(address[:])),
true,
"Address: %s is invalid", address,
)
}
}
22 changes: 21 additions & 1 deletion block.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package main
package bc

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

Expand Down Expand Up @@ -71,3 +74,20 @@ func DeserializeBlock(d []byte) *Block {

return &block
}

func (b *Block) PrintHTML(detail bool) string {
var lines []string
lines = append(lines, fmt.Sprintf("<h2>Block <a href=\"/block/%x\">%x</a> </h2>", b.Hash, b.Hash))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to do this via 'html/template', and this should be a separate package, because it's not directly related to the logic of the blockchain.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, I just learn go, so...

lines = append(lines, fmt.Sprintf("Height: %d</br>", b.Height))
lines = append(lines, fmt.Sprintf("Prev. block: <a href=\"/block/%x\">%x</a></br>", b.PrevBlockHash, b.PrevBlockHash))
lines = append(lines, fmt.Sprintf("Created at : %s</br>", time.Unix(b.Timestamp, 0)))
pow := NewProofOfWork(b)
lines = append(lines, fmt.Sprintf("PoW: %s</br></br>", strconv.FormatBool(pow.Validate())))
if detail {
for _, tx := range b.Transactions {
lines = append(lines, tx.PrintHTML())
}
}
lines = append(lines, fmt.Sprintf("</br></br>"))
return strings.Join(lines, "\n")
}
49 changes: 40 additions & 9 deletions blockchain.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package bc

import (
"bytes"
Expand All @@ -8,6 +8,7 @@ import (
"fmt"
"log"
"os"
"strings"

"github.com/boltdb/bolt"
)
Expand All @@ -19,7 +20,7 @@ const genesisCoinbaseData = "The Times 03/Jan/2009 Chancellor on brink of second
// Blockchain implements interactions with a DB
type Blockchain struct {
tip []byte
db *bolt.DB
DB *bolt.DB
}

// CreateBlockchain creates a new blockchain DB
Expand Down Expand Up @@ -82,7 +83,7 @@ func NewBlockchain(nodeID string) *Blockchain {
log.Panic(err)
}

err = db.Update(func(tx *bolt.Tx) error {
err = db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blocksBucket))
tip = b.Get([]byte("l"))

Expand All @@ -99,7 +100,7 @@ func NewBlockchain(nodeID string) *Blockchain {

// AddBlock saves the block into the blockchain
func (bc *Blockchain) AddBlock(block *Block) {
err := bc.db.Update(func(tx *bolt.Tx) error {
err := bc.DB.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blocksBucket))
blockInDb := b.Get(block.Hash)

Expand Down Expand Up @@ -199,7 +200,7 @@ func (bc *Blockchain) FindUTXO() map[string]TXOutputs {

// Iterator returns a BlockchainIterat
func (bc *Blockchain) Iterator() *BlockchainIterator {
bci := &BlockchainIterator{bc.tip, bc.db}
bci := &BlockchainIterator{bc.tip, bc.DB}

return bci
}
Expand All @@ -208,7 +209,7 @@ func (bc *Blockchain) Iterator() *BlockchainIterator {
func (bc *Blockchain) GetBestHeight() int {
var lastBlock Block

err := bc.db.View(func(tx *bolt.Tx) error {
err := bc.DB.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blocksBucket))
lastHash := b.Get([]byte("l"))
blockData := b.Get(lastHash)
Expand All @@ -227,7 +228,7 @@ func (bc *Blockchain) GetBestHeight() int {
func (bc *Blockchain) GetBlock(blockHash []byte) (Block, error) {
var block Block

err := bc.db.View(func(tx *bolt.Tx) error {
err := bc.DB.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blocksBucket))

blockData := b.Get(blockHash)
Expand Down Expand Up @@ -277,7 +278,7 @@ func (bc *Blockchain) MineBlock(transactions []*Transaction) *Block {
}
}

err := bc.db.View(func(tx *bolt.Tx) error {
err := bc.DB.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blocksBucket))
lastHash = b.Get([]byte("l"))

Expand All @@ -294,7 +295,7 @@ func (bc *Blockchain) MineBlock(transactions []*Transaction) *Block {

newBlock := NewBlock(transactions, lastHash, lastHeight+1)

err = bc.db.Update(func(tx *bolt.Tx) error {
err = bc.DB.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blocksBucket))
err := b.Put(newBlock.Hash, newBlock.Serialize())
if err != nil {
Expand Down Expand Up @@ -358,3 +359,33 @@ func dbExists(dbFile string) bool {

return true
}

func (bc *Blockchain) PrintHTML() string {
var lines []string
bci := bc.Iterator()

for {
block := bci.Next()

lines = append(lines, block.PrintHTML(false))

if len(block.PrevBlockHash) == 0 {
break
}
}
return strings.Join(lines, "\n")

}

func (bc *Blockchain) GetBalance(address string) int {
UTXOSet := UTXOSet{bc}
balance := 0
pubKeyHash := Base58Decode([]byte(address))
pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-4]
UTXOs := UTXOSet.FindUTXO(pubKeyHash)

for _, out := range UTXOs {
balance += out.Value
}
return balance
}
2 changes: 1 addition & 1 deletion blockchain_iterator.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package bc

import (
"log"
Expand Down
100 changes: 99 additions & 1 deletion cli.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package bc

import (
"flag"
Expand All @@ -21,6 +21,14 @@ func (cli *CLI) printUsage() {
fmt.Println(" reindexutxo - Rebuilds the UTXO set")
fmt.Println(" send -from FROM -to TO -amount AMOUNT -mine - Send AMOUNT of coins from FROM address to TO. Mine on the same node, when -mine is set.")
fmt.Println(" startnode -miner ADDRESS - Start a node with ID specified in NODE_ID env. var. -miner enables mining")
fmt.Println()
fmt.Println("Exploring cmds:")
fmt.Println(" generatePrivKey - generate KeyPair for exploring")
fmt.Println(" getPubKey -privKey PRIKEY - generate PubKey from privateKey")
fmt.Println(" getAddress -pubKey PUBKEY - convert pubKey to address")
fmt.Println(" getPubKeyHash -address Address - get pubKeyHash of an address")
fmt.Println(" validateAddress -addr Address - validate an address")
fmt.Println(" getBlock -hash BlockHash - get a block with BlockHash")
}

func (cli *CLI) validateArgs() {
Expand Down Expand Up @@ -48,6 +56,12 @@ func (cli *CLI) Run() {
reindexUTXOCmd := flag.NewFlagSet("reindexutxo", flag.ExitOnError)
sendCmd := flag.NewFlagSet("send", flag.ExitOnError)
startNodeCmd := flag.NewFlagSet("startnode", flag.ExitOnError)
generatePrivKeyCmd := flag.NewFlagSet("generatePrivKey", flag.ExitOnError)
getPubKeyCmd := flag.NewFlagSet("getPubKey", flag.ExitOnError)
getAddressCmd := flag.NewFlagSet("getAddress", flag.ExitOnError)
getPubKeyHashCmd := flag.NewFlagSet("getPubKeyHash", flag.ExitOnError)
validateAddrCmd := flag.NewFlagSet("validateAddress", flag.ExitOnError)
getBlockCmd := flag.NewFlagSet("getBlock", flag.ExitOnError)

getBalanceAddress := getBalanceCmd.String("address", "", "The address to get balance for")
createBlockchainAddress := createBlockchainCmd.String("address", "", "The address to send genesis block reward to")
Expand All @@ -56,6 +70,11 @@ func (cli *CLI) Run() {
sendAmount := sendCmd.Int("amount", 0, "Amount to send")
sendMine := sendCmd.Bool("mine", false, "Mine immediately on the same node")
startNodeMiner := startNodeCmd.String("miner", "", "Enable mining mode and send reward to ADDRESS")
privateKey := getPubKeyCmd.String("privKey", "", "generate PubKey based on this")
pubKey := getAddressCmd.String("pubKey", "", "the key where address generated")
pubKeyAddress := getPubKeyHashCmd.String("address", "", "the pub address")
address := validateAddrCmd.String("addr", "", "the public address")
blockHash := getBlockCmd.String("hash", "", "the block hash")

switch os.Args[1] {
case "getbalance":
Expand Down Expand Up @@ -98,6 +117,36 @@ func (cli *CLI) Run() {
if err != nil {
log.Panic(err)
}
case "validateAddress":
err := validateAddrCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "generatePrivKey":
err := generatePrivKeyCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "getPubKey":
err := getPubKeyCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "getPubKeyHash":
err := getPubKeyHashCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "getAddress":
err := getAddressCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "getBlock":
err := getBlockCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
default:
cli.printUsage()
os.Exit(1)
Expand Down Expand Up @@ -152,4 +201,53 @@ func (cli *CLI) Run() {
}
cli.startNode(nodeID, *startNodeMiner)
}

if generatePrivKeyCmd.Parsed() {
cli.generatePrivKey()
}

if getPubKeyCmd.Parsed() {
if *privateKey == "" {
getPubKeyCmd.Usage()
os.Exit(1)
}
cli.getPubKey(*privateKey)
}

if getAddressCmd.Parsed() {
if *pubKey == "" {
getAddressCmd.Usage()
os.Exit(1)
}

cli.getAddress(*pubKey)
}

if getPubKeyHashCmd.Parsed() {
if *pubKeyAddress == "" {
getPubKeyHashCmd.Usage()
os.Exit(1)
}

cli.getPubKeyHash(*pubKeyAddress)
}

if validateAddrCmd.Parsed() {
if *address == "" {
validateAddrCmd.Usage()
os.Exit(1)
}

cli.validateAddr(*address)
}

if getBlockCmd.Parsed() {
if *blockHash == "" {
getBlockCmd.Usage()
os.Exit(1)
}

cli.printBlock(*blockHash, nodeID)
}

}
4 changes: 2 additions & 2 deletions cli_createblockchain.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package bc

import (
"fmt"
Expand All @@ -10,7 +10,7 @@ func (cli *CLI) createBlockchain(address, nodeID string) {
log.Panic("ERROR: Address is not valid")
}
bc := CreateBlockchain(address, nodeID)
defer bc.db.Close()
defer bc.DB.Close()

UTXOSet := UTXOSet{bc}
UTXOSet.Reindex()
Expand Down
Loading