Skip to content

Instantly share code, notes, and snippets.

@zak10
Created October 11, 2017 13:28
Show Gist options
  • Save zak10/b76c467f25e25357b9ecbe8452a80d7b to your computer and use it in GitHub Desktop.
Save zak10/b76c467f25e25357b9ecbe8452a80d7b to your computer and use it in GitHub Desktop.
package blockchain
import (
cr "crypto/sha256"
"encoding/hex"
"encoding/json"
"time"
"fmt"
)
// Blockchain is used to store a chain of all already mined blocks and all
// transactions that are waiting to be mined in the next block
type Blockchain struct {
chain []Block
currentTransactions []Transaction
}
// NewBlockChain created a Blockchain and initializes the genesis block
func NewBlockChain() *Blockchain {
b := &Blockchain{}
b.NewBlock(100, "1")
return b
}
// NewTransaction will add a transaction at the end of the currentTransactions slice
// and return the index of the block in which this transaction will be contained (the next
// unmined block)
func (b *Blockchain) NewTransaction(sender string, recipient string, amount int64) int64 {
t := Transaction{
Sender: sender,
Recipient: recipient,
Amount: amount,
}
append(b.currentTransactions, t)
return b.chain[-1].Index + 1
}
// NewBlock creates a new block for the current transactions waiting to be verified
// and clears the current transactions after adding the new block to the chain
func (b *Blockchain) NewBlock(proof int64, prevHash string) Block {
if prevHash == "" {
prevHash = b.hash(b.lastBlock())
}
bl := Block{
Index: len(b.chain) + 1,
Timestamp: time.Now().UnixNano(),
Transactions: b.currentTransactions,
Proof: proof,
PrevHash: prevHash,
}
b.currentTransactions = []Transaction{}
append(b.chain, bl)
return bl
}
// ProofOfWork is the actually mining method. It will start at proof = 0
// and increment this value until the block is a valid proof based on the
// previous proof
func (b *Blockchain) ProofOfWork(lastProof int64) int64 {
proof := 0
for !b.isValidProof(lastProof, proof) {
proof++
}
return proof
}
// isValidProof creates a hex of the SHA-256 value of the concatenation
// of the previous proof and the current proof you are attempted to validate.
// If the value ends in four "0"s, we consider it a valid proof and return true
func (b *Blockchain) isValidProof(lastProof int64, currProof int64) bool {
s := fmt.Sprintf("%s%s", lastProof, currProof)
v := hex.EncodeToString(cr.Sum256([]byte(s)))
return string(v[len(v)-4:]) == "0000"
}
// lastBlock returns the last block in the chain that has been mined
func (b *Blockchain) lastBlock() Block {
return b.chain[len(b.chain)-1]
}
// Convert block to hex hash
func (b *Blockchain) hash(bl Block) string {
raw, _ := json.Marshal(bl)
return hex.EncodeToString(cr.Sum256(raw))
}
// Block contains an index, timestamp (when it was solved), a slice of transactions,
// the proof that mined the block and the hash of the previous block
type Block struct {
Index int64
Timestamp int64
Transactions []Transaction
Proof int64
PrevHash string
}
// Transaction is a proof of concept transaction that only contains a sender, recipient
// and an amount to transfer
type Transaction struct {
Sender string
Recipient string
Amount int64
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment