Created
October 11, 2017 13:28
-
-
Save zak10/b76c467f25e25357b9ecbe8452a80d7b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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