diff --git a/block.go b/block.go index 8e87b8b..fd3d07c 100644 --- a/block.go +++ b/block.go @@ -13,18 +13,15 @@ type Block struct { Nonce int } -// 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{}, 0} - block.Prove() + pow := NewProofOfWork(block) + nonce, hash := pow.Run() + + block.Hash = hash[:] + block.Nonce = nonce + return block } diff --git a/proofofwork.go b/proofofwork.go index c9958f9..21fa91a 100644 --- a/proofofwork.go +++ b/proofofwork.go @@ -3,35 +3,45 @@ package main import ( "bytes" "crypto/sha256" - "encoding/binary" "fmt" - "log" "math" "math/big" ) var ( - target big.Int maxNonce = math.MaxInt64 ) const targetBits = 12 -func setTarget() { +// ProofOfWork represents a proof-of-work +type ProofOfWork struct { + block *Block + target big.Int +} + +// NewProofOfWork builds and returns a ProofOfWork +func NewProofOfWork(b *Block) *ProofOfWork { targetBytes := make([]byte, 32) + target := big.Int{} + numOfZeros := targetBits / 4 targetBytes[numOfZeros-1] = 1 target.SetBytes(targetBytes) + + pow := &ProofOfWork{b, target} + + return pow } -func prepareData(block *Block, nonce int) []byte { +func (pow *ProofOfWork) prepareData(nonce int) []byte { data := bytes.Join( [][]byte{ - block.PrevBlockHash, - block.Data, - intToHex(block.Timestamp), - intToHex(int64(targetBits)), - intToHex(int64(nonce)), + pow.block.PrevBlockHash, + pow.block.Data, + IntToHex(pow.block.Timestamp), + IntToHex(int64(targetBits)), + IntToHex(int64(nonce)), }, []byte{}, ) @@ -39,32 +49,21 @@ func prepareData(block *Block, nonce int) []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() +// Run performs a proof-of-work +func (pow *ProofOfWork) Run() (int, []byte) { var hashInt big.Int var hash [32]byte nonce := 0 - fmt.Printf("Mining the block containing \"%s\"\n", block.Data) + fmt.Printf("Mining the block containing \"%s\"\n", pow.block.Data) for nonce < maxNonce { - data := prepareData(block, nonce) + data := pow.prepareData(nonce) hash = sha256.Sum256(data) fmt.Printf("\r%x", hash) hashInt.SetBytes(hash[:]) - if hashInt.Cmp(&target) == -1 { + if hashInt.Cmp(&pow.target) == -1 { break } else { nonce++ @@ -75,16 +74,15 @@ func Prove(block *Block) (int, []byte) { return nonce, hash[:] } -// ConfirmProof .. -func ConfirmProof(block *Block, nonce int) bool { - setTarget() +// ConfirmProof confirms that the proof is correct +func (pow *ProofOfWork) ConfirmProof(nonce int) bool { var hashInt big.Int - data := prepareData(block, nonce) + data := pow.prepareData(nonce) hash := sha256.Sum256(data) hashInt.SetBytes(hash[:]) - confirmation := hashInt.Cmp(&target) == -1 + confirmation := hashInt.Cmp(&pow.target) == -1 return confirmation } diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..7f5e727 --- /dev/null +++ b/utils.go @@ -0,0 +1,18 @@ +package main + +import ( + "bytes" + "encoding/binary" + "log" +) + +// IntToHex converts an int64 to a byte array +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() +}