You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

155 lines
3.4 KiB

package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/fatih/color"
)
type Block struct {
Hash string `json:"hash"`
Height int64 `json:"height"`
Date time.Time `json:"date"`
PreviousHash string `json:"previoushash"`
NextHash string `json:"nexthash"`
Data []Address `json:"data"`
Emitter string `json:"emitter"` //the ID of the peer that has emmited the block
}
type Blockchain struct {
GenesisBlock string `json:"genesisblock"`
LastUpdate time.Time `json:"lastupdate"`
Blocks []Block `json:"blocks"`
}
var blockchain Blockchain
func (bc *Blockchain) getBlockByHash(hash string) (Block, error) {
for _, block := range bc.Blocks {
if block.Hash == hash {
return block, nil
}
}
var b Block
return b, errors.New("Block Hash not found")
}
func (bc *Blockchain) createBlock(address Address) Block {
var b Block
b.Height = int64(len(bc.Blocks))
if len(bc.Blocks) == 0 {
b.Height = 0
} else {
b.PreviousHash = bc.Blocks[len(bc.Blocks)-1].Hash
}
b.Date = time.Now()
b.Data = append(b.Data, address)
b.Emitter = runningPeer.ID
b.Hash = hashBlock(b)
return b
}
func (bc *Blockchain) blockExists(block Block) bool {
for _, b := range bc.Blocks {
if b.Hash == block.Hash {
return true
}
}
return false
}
func (bc *Blockchain) addBlock(block Block) error {
if blockchain.blockExists(block) {
return errors.New("[Error adding Block]: Block already exists in the Blockchain")
}
if len(bc.Blocks) > 0 {
bc.Blocks[len(bc.Blocks)-1].NextHash = block.Hash
} else {
bc.GenesisBlock = block.Hash
}
bc.Blocks = append(bc.Blocks, block)
bc.saveToDisk()
return nil
}
func reconstructBlockchainFromBlock(urlAPI string, h string) {
color.Yellow("reconstructing the blockchain from last block in memory")
var block Block
var err error
block, err = blockchain.getBlockByHash(h)
check(err)
if h == "" {
//no genesis block yet
color.Green(urlAPI + "/blocks/genesis")
res, err := http.Get(urlAPI + "/blocks/genesis")
check(err)
body, err := ioutil.ReadAll(res.Body)
check(err)
err = json.Unmarshal(body, &block)
check(err)
color.Yellow("[New Block]: " + block.Hash)
err = blockchain.addBlock(block)
check(err)
} else {
block.NextHash = h
}
for block.NextHash != "" && block.Hash != "" {
res, err := http.Get(urlAPI + "/blocks/next/" + block.Hash)
check(err)
body, err := ioutil.ReadAll(res.Body)
check(err)
err = json.Unmarshal(body, &block)
check(err)
if block.Hash != "" {
color.Yellow("[New Block]: " + block.Hash)
err = blockchain.addBlock(block)
check(err)
}
}
blockchain.print()
}
func (bc *Blockchain) print() {
color.Green("Printing Blockchain stored in memory")
color.Green("Genesis Block: " + bc.GenesisBlock)
for _, b := range bc.Blocks {
color.Green("Block height:")
fmt.Println(b.Height)
color.Green("Hash: " + b.Hash)
color.Green("Date: " + b.Date.String())
color.Green("---")
}
}
func (bc *Blockchain) readFromDisk() error {
file, err := ioutil.ReadFile("blockchain.data")
if err != nil {
return err
}
content := string(file)
json.Unmarshal([]byte(content), &bc)
return nil
}
func (bc *Blockchain) saveToDisk() error {
bytesBlockchain, err := json.Marshal(blockchain)
if err != nil {
return err
}
err = ioutil.WriteFile("blockchain.data", bytesBlockchain, 0644)
if err != nil {
return err
}
return nil
}