diff --git a/internal/blockchain/block.go b/internal/blockchain/block.go index 090775c..e27243d 100644 --- a/internal/blockchain/block.go +++ b/internal/blockchain/block.go @@ -4,32 +4,38 @@ import ( "bytes" "crypto/sha256" "strconv" + "time" ) type Block struct { Timestamp int64 Data []byte // Transactions - prevBlockHash []byte + PrevBlockHash []byte Hash []byte Counter int // Nonce } func (b *Block) SetHash() { timestamp := []byte(strconv.FormatInt(b.Timestamp, 10)) - headers := bytes.Join([][]byte{b.prevBlockHash, b.Data, timestamp}, []byte{}) + headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{}) hash := sha256.Sum256(headers) b.Hash = hash[:] } +// NewBlock creates and returns a new block. func NewBlock(data string, prevBlockHash []byte) *Block { block := &Block{ - Timestamp: 0, + Timestamp: time.Now().Unix(), Data: []byte(data), - prevBlockHash: prevBlockHash, + PrevBlockHash: prevBlockHash, Hash: []byte{}, Counter: 0, } - block.SetHash() + pow := NewProofOfWork(block) + hash, nonce := pow.Run() + block.Hash = hash[:] + block.Counter = nonce + return block } diff --git a/internal/blockchain/blockchain.go b/internal/blockchain/blockchain.go index a768754..e0b3f06 100644 --- a/internal/blockchain/blockchain.go +++ b/internal/blockchain/blockchain.go @@ -1,13 +1,15 @@ package blockchain +import "bytes" + type Blockchain struct { - blocks []*Block + Blocks []*Block } func (bc *Blockchain) AddBlock(data string) { - prevBlock := bc.blocks[len(bc.blocks)-1] + prevBlock := bc.Blocks[len(bc.Blocks)-1] newBlock := NewBlock(data, prevBlock.Hash) - bc.blocks = append(bc.blocks, newBlock) + bc.Blocks = append(bc.Blocks, newBlock) } func NewGenesisBlock() *Block { @@ -17,3 +19,22 @@ func NewGenesisBlock() *Block { func NewBlockchain() *Blockchain { return &Blockchain{[]*Block{NewGenesisBlock()}} } + +// IsValid validates the blockchain. +func (bc *Blockchain) IsValid() bool { + for i := 1; i < len(bc.Blocks); i++ { + currentBlock := bc.Blocks[i] + prevBlock := bc.Blocks[i-1] + + if !bytes.Equal(currentBlock.PrevBlockHash, prevBlock.Hash) { + return false + } + + pow := NewProofOfWork(currentBlock) + if !pow.Validate() { + return false + } + } + + return true +} diff --git a/internal/blockchain/proof_of_work.go b/internal/blockchain/proof_of_work.go index dcdbc05..9a4094a 100644 --- a/internal/blockchain/proof_of_work.go +++ b/internal/blockchain/proof_of_work.go @@ -8,26 +8,34 @@ import ( "strconv" ) -const targetBits = 24 +const Difficulty = 16 var maxNonce = math.MaxInt64 -const Difficulty = 16 - +// ProofOfWork represents a proof-of-work. type ProofOfWork struct { block *Block T big.Int } -// Prepare pow data, this function hashes the data and returns it +// NewProofOfWork creates and returns a ProofOfWork. +func NewProofOfWork(b *Block) *ProofOfWork { + target := big.NewInt(1) + target.Lsh(target, uint(256-Difficulty)) + + pow := &ProofOfWork{b, *target} + + return pow +} +// prepareData prepares data for hashing. func (pow *ProofOfWork) prepareData(nonce int) []byte { data := bytes.Join( [][]byte{ - pow.block.prevBlockHash, + pow.block.PrevBlockHash, pow.block.Data, []byte(strconv.FormatInt(pow.block.Timestamp, 10)), - []byte(strconv.FormatInt(targetBits, 10)), + []byte(strconv.FormatInt(int64(Difficulty), 10)), []byte(strconv.FormatInt(int64(nonce), 10)), }, []byte{}, @@ -36,24 +44,17 @@ func (pow *ProofOfWork) prepareData(nonce int) []byte { return data } -func (pow *ProofOfWork) RunProofOfWork() (int, []byte) { +// Run performs the proof-of-work algorithm. +func (pow *ProofOfWork) Run() ([]byte, int) { var hashInt big.Int var hash [32]byte nonce := 0 - if pow.block == nil { - pow.block.Data = NewGenesisBlock().Data - } else { - temp_block := pow.block - temp_block.SetHash() - pow.block = temp_block - } - for nonce < maxNonce { data := pow.prepareData(nonce) hash = sha256.Sum256(data) - hashInt.SetBytes(hash[:]) + if hashInt.Cmp(&pow.T) == -1 { break } else { @@ -61,14 +62,16 @@ func (pow *ProofOfWork) RunProofOfWork() (int, []byte) { } } - return nonce, hash[:] + return hash[:], nonce } -func NewProofOfWork(b *Block) *ProofOfWork { - target := big.NewInt(1) - target.Lsh(target, uint(256-Difficulty)) +// Validate checks if the block's proof-of-work is valid. +func (pow *ProofOfWork) Validate() bool { + var hashInt big.Int + data := pow.prepareData(pow.block.Counter) - pow := &ProofOfWork{b, *target} + hash := sha256.Sum256(data) + hashInt.SetBytes(hash[:]) - return pow + return hashInt.Cmp(&pow.T) == -1 } diff --git a/internal/blockchain/validantions.go b/internal/blockchain/validantions.go index 2252c2a..a1b274e 100644 --- a/internal/blockchain/validantions.go +++ b/internal/blockchain/validantions.go @@ -11,100 +11,100 @@ import ( type Receive func() string type Input func() string +// ValidateBlockPredicate validates a block using Proof of Work func ValidateBlockPredicate(pow *ProofOfWork) bool { var hashInt big.Int - data := pow.prepareData(pow.block.Counter) hash := sha256.Sum256(data) hashInt.SetBytes(hash[:]) - validation := hashInt.Cmp(&pow.T) == -1 - return validation + return hashInt.Cmp(&pow.T) == -1 } -// Simple Content Validation Predicate implementation from backbone protocol -func ContentValidatePredicate(x *Blockchain) bool { - - if len(x.blocks) == 0 { +// ContentValidatePredicate validates the content of the blockchain +func ContentValidatePredicate(chain *Blockchain) bool { + if len(chain.Blocks) == 0 { return false } - for i := range x.blocks { - if i == 0 { - continue - } - if reflect.DeepEqual(x.blocks[i].Hash, x.blocks[i-1].Hash) { + for i := 1; i < len(chain.Blocks); i++ { + if reflect.DeepEqual(chain.Blocks[i].Hash, chain.Blocks[i-1].Hash) { return false } } return true } -func InputContributionFunction(data []byte, cr *Blockchain, round int, input Input, receive Receive) { - - input_data := input() - receive_data := receive() - - concat_data := input_data + receive_data - // creating new block +// InputContributionFunction processes input and adds a new block to the blockchain +func InputContributionFunction(data []byte, chain *Blockchain, round int, input Input, receive Receive) { + inputData := input() + receiveData := receive() + concatData := inputData + receiveData + + newBlock := &Block{ + Timestamp: time.Now().Unix(), + Data: []byte(concatData), + PrevBlockHash: chain.Blocks[len(chain.Blocks)-1].Hash, + Counter: round, + } - newBlock := &Block{time.Now().Unix(), []byte(concat_data), cr.blocks[len(cr.blocks)-1].Hash, []byte{}, round} - cr.blocks = append(cr.blocks, newBlock) + chain.Blocks = append(chain.Blocks, newBlock) - if !ContentValidatePredicate(cr) { + if !ContentValidatePredicate(chain) { fmt.Println("Content Validation Failed") - cr.blocks = cr.blocks[:len(cr.blocks)-1] + chain.Blocks = chain.Blocks[:len(chain.Blocks)-1] } else { fmt.Println("Content Validation Passed") } } -// Function to read the chain -func ChainReadFunction(c *Blockchain) string { - data := "" - for i := range c.blocks { - data += string(c.blocks[i].Data) +// ChainReadFunction returns the data of the blockchain as a string +func ChainReadFunction(chain *Blockchain) string { + var data string + for _, block := range chain.Blocks { + data += string(block.Data) } return data } -// Function to validate the chain -func ChainValidationPredicate(c *Blockchain) bool { - b := ContentValidatePredicate(c) - - if b { - temp_chain := c.blocks[len(c.blocks)-1] - s_ := sha256.Sum256(temp_chain.Data) - proof_ := &ProofOfWork{temp_chain, *big.NewInt(1)} - - for i := true; i; b = false || c == nil { - if ValidateBlockPredicate(proof_) && reflect.DeepEqual(temp_chain.Hash, s_) { - s_ = [32]byte{} - copy(s_[:], temp_chain.Data) - c.blocks = c.blocks[:len(c.blocks)-1] - } else { - b = false - } +// ChainValidationPredicate validates the blockchain +func ChainValidationPredicate(chain *Blockchain) bool { + if !ContentValidatePredicate(chain) { + return false + } + + for len(chain.Blocks) > 0 { + lastBlock := chain.Blocks[len(chain.Blocks)-1] + hash := sha256.Sum256(lastBlock.Data) + proof := &ProofOfWork{block: lastBlock, T: *big.NewInt(1)} + + if !ValidateBlockPredicate(proof) || !reflect.DeepEqual(lastBlock.Hash, hash) { + return false } + + // Prepare the hash for the next iteration + hash = [32]byte{} + copy(hash[:], lastBlock.Data) + chain.Blocks = chain.Blocks[:len(chain.Blocks)-1] } - return b -} -// Function to find the best chain + return true +} -func MaxChain(c [][]Blockchain) []*Block { - temp_chain := []*Block{} +// MaxChain finds the best chain among multiple chains +func MaxChain(chains [][]Blockchain) []*Block { + var bestChain []*Block - for i := 1; i < len(c); i++ { - if ChainValidationPredicate(&c[i][0]) { - temp_chain = maxBlocks(temp_chain, c[i][0].blocks) + for i := 1; i < len(chains); i++ { + if ChainValidationPredicate(&chains[i][0]) { + bestChain = maxBlocks(bestChain, chains[i][0].Blocks) } } - return temp_chain + return bestChain } -// compare blockchains length +// maxBlocks returns the longer of two block slices func maxBlocks(a, b []*Block) []*Block { if len(a) > len(b) { return a