defmodule Miner do # Elixir actor to capture all incoming transactions to mine def miningNode(blockChainPID, verificationAccumulatorPID, blockChainEndIndex, resultRetrieverPID) do receive do {:ok, [newTransactionData, signedMessage, senderPID, minersList]} -> blockChain = GenServer.call(blockChainPID, {:getBlockChain}) latestBlock = Enum.at(blockChain, blockChainEndIndex) hash = Map.get(latestBlock, :hash) mining(blockChainPID, newTransactionData, signedMessage, hash, blockChainEndIndex, senderPID, verificationAccumulatorPID, minersList, self(), resultRetrieverPID) Miner.miningNode(blockChainPID, verificationAccumulatorPID, blockChainEndIndex, resultRetrieverPID) {:incrementPointer} -> blockChainEndIndex = blockChainEndIndex + 1 Miner.miningNode(blockChainPID, verificationAccumulatorPID, blockChainEndIndex, resultRetrieverPID) {:decrementPointer} -> blockChainEndIndex = blockChainEndIndex - 1 Miner.miningNode(blockChainPID, verificationAccumulatorPID, blockChainEndIndex, resultRetrieverPID) end end # Recursively calls itself and calls the hashing function untill a hash with the specific number of 0's is found, after which it creates and adds a new block to the blockchain def mining(blockChainPID, transactionData, signature, hash, blockChainEndIndex, senderPID, verificationAccumulatorPID, minersList, selfPID, resultRetrieverPID) do blockChain = GenServer.call(blockChainPID, {:getBlockChain}) cond do length(blockChain) - 1 > blockChainEndIndex -> send selfPID, {:incrementPointer} length(blockChain) - 1 == blockChainEndIndex -> msgt_hash = Helpers.hash(transactionData, hash) if(String.slice(msgt_hash, 0, 4) === String.duplicate("0", 4)) do IO.puts "Hash found: #{inspect(msgt_hash)}" send resultRetrieverPID, {:hash, msgt_hash} IO.puts "Transaction successful" newBlock = %{ transactionData: transactionData, prevHash: hash, hash: msgt_hash, signedMessage: signature, timestamp: NaiveDateTime.utc_now, sendersPublicKey: Map.get(transactionData, "sendersPublicKey") } GenServer.cast(blockChainPID, {:addBlock, newBlock}) send verificationAccumulatorPID, {:ok, senderPID, minersList} send selfPID, {:incrementPointer} else Miner.mining(blockChainPID, transactionData, signature, hash, blockChainEndIndex, senderPID, verificationAccumulatorPID, minersList, selfPID, resultRetrieverPID) end end end end