|
|
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 }
|