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) 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("---") } }