diff --git a/block.go b/block.go index dd0afd1..8e87b8b 100644 --- a/block.go +++ b/block.go @@ -1,9 +1,6 @@ package main import ( - "bytes" - "crypto/sha256" - "strconv" "time" ) @@ -13,21 +10,21 @@ type Block struct { Data []byte PrevBlockHash []byte Hash []byte + Nonce int } -// SetHash calculates and sets block hash -func (b *Block) SetHash() { - timestamp := []byte(strconv.FormatInt(b.Timestamp, 10)) - headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{}) - hash := sha256.Sum256(headers) +// Prove obtains proof of work +func (b *Block) Prove() { + nonce, hash := Prove(b) b.Hash = hash[:] + b.Nonce = nonce } // NewBlock creates and returns Block func NewBlock(data string, prevBlockHash []byte) *Block { - block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}} - block.SetHash() + block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}, 0} + block.Prove() return block } diff --git a/main.go b/main.go index 68e4642..02948e9 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,6 @@ package main -import ( - "fmt" -) +import "fmt" func main() { bc := NewBlockchain() diff --git a/proofofwork.go b/proofofwork.go new file mode 100644 index 0000000..6d17ced --- /dev/null +++ b/proofofwork.go @@ -0,0 +1,86 @@ +package main + +import ( + "bytes" + "crypto/sha256" + "encoding/binary" + "log" + "math" + "math/big" +) + +var ( + target big.Int + maxNonce = math.MaxInt64 +) + +const targetBits = 12 + +func setTarget() { + targetBytes := make([]byte, 32) + numOfZeros := targetBits / 4 + targetBytes[numOfZeros-1] = 1 + target.SetBytes(targetBytes) +} + +func prepareData(block *Block, nonce int) []byte { + data := bytes.Join( + [][]byte{ + block.PrevBlockHash, + block.Data, + intToHex(block.Timestamp), + intToHex(int64(targetBits)), + intToHex(int64(nonce)), + }, + []byte{}, + ) + + return data +} + +func intToHex(num int64) []byte { + buff := new(bytes.Buffer) + err := binary.Write(buff, binary.BigEndian, num) + if err != nil { + log.Panic(err) + } + + return buff.Bytes() +} + +// Prove ... +func Prove(block *Block) (int, []byte) { + setTarget() + var hashInt big.Int + var hash [32]byte + nonce := 0 + + for nonce < maxNonce { + data := prepareData(block, nonce) + + hash = sha256.Sum256(data) + hashInt.SetBytes(hash[:]) + + if hashInt.Cmp(&target) == -1 { + break + } else { + nonce++ + } + } + + return nonce, hash[:] +} + +// ConfirmProof .. +func ConfirmProof(block *Block, nonce int) bool { + setTarget() + var hashInt big.Int + + data := prepareData(block, nonce) + hash := sha256.Sum256(data) + hashInt.SetBytes(hash[:]) + + confirmation := hashInt.Cmp(&target) == -1 + + return confirmation +}