Skip to content
Snippets Groups Projects
Commit 40a9fa4e authored by ROUSSET Noemie's avatar ROUSSET Noemie
Browse files

hardship calculation

parent 952e2b7e
Branches
No related tags found
No related merge requests found
defmodule BMA.Blockchain.Hardship do
@moduledoc """
Module to calculate the hardship for a specific issuer.
Implementation based on https://duniter.org//wiki/duniter/2018-11-27-duniter-proof-of-work/
"""
@doc """
Calculate and return the hardship of the issuer given in search with its public key
"""
def get(search) do
Poison.encode!("#TODO")
{:ok, :block} = :dets.open_file(:block, [{:file, 'data/block'}, {:type, :set}])
case :dets.match(:block, {:"$1", %{issuer: search}}) do
[{_key,block_searched}] ->
#last block of the blockchain
{:ok, :global_bindex} = :dets.open_file(:global_bindex, [{:file, 'data/global_bindex'}, {:type, :set}])
last_block = :ets.match(:global_bindex, {:last_block, :"$1"})
#exclusion factor calculation
nbPreviousIssuers = last_block.issuersCount
nbBlocksSince = last_block.number - block_searched.number
exFact = Enum.max([1, Float.floor(0.67 * nbPreviousIssuers / (1 + nbBlocksSince)) ])
#handicap calculation
handicap = getHandicap(last_block, search)
Poison.encode!(getHardship(exFact, last_block[:powMin], handicap, last_block))
_ ->
#last block of the blockchain
{:ok, :global_bindex} = :dets.open_file(:global_bindex, [{:file, 'data/global_bindex'}, {:type, :set}])
last_block = :ets.match(:global_bindex, {:last_block, :"$1"})
exFact = 1
powMin = last_block[:powMin]
handicap = getHandicap(last_block, search)
Poison.encode!(getHardship(exFact, powMin, handicap, last_block))
end
end
#return the hardship map
def getHardship(exFact, powMin, handicap, last_block) do
#level of the member
level = powMin * exFact + handicap
%{
block: last_block[:number],
level: level
}
end
#return the handicap value with the last block of the blockchain (last_block) and the issuer (pubKey)
def getHandicap(last_block, pubKey) do
window_size = last_block.issuersFrame
blocks_frame = getBlocksFrame(window_size, last_block.number)
nbPersonalBlocksFrame = nbBlocksWithPubKey(blocks_frame, pubKey)
medianPubKeyFrame = calculateMedianPubKey(blocks_frame)
Float.floor(:math.log2(Enum.max([1, (nbPersonalBlocksFrame + 1) / medianPubKeyFrame])) / :math.log2(1.189))
end
#return a list of blocks in a specified window size (count) from from_key, the key of the first block
def getBlocksFrame(window_size, from_key) do
Enum.map(from_key..(from_key - window_size + 1), fn n ->
case :dets.lookup(:block, n) do
[] -> nil
[{_n, block}] -> block
end
end)
end
#return the number of occurrences the public key (pubkey) appears in the list of blocks (blocks)
def nbBlocksWithPubKey(blocks, pubkey) do
Enum.reduce(blocks, 0, fn block, acc ->
if(block.issuer == pubkey) do
acc + 1
else
acc
end
end)
end
#calculate the occurence number of the different public keys and return the median number
def calculateMedianPubKey(blocks) do
nbBlocksByKey = Enum.reduce(blocks, %{}, fn block, acc ->
{_old_value, new_acc} = Map.get_and_update(acc, block.issuer, fn current_value ->
if current_value == nil do
{current_value, 1}
else
{current_value, current_value + 1}
end
end)
new_acc
end)
#pubKey list structure :
#[
# {"public key value 1", number of occurences} ,
# {"public key value 2", number of occurences}
#]
pubKeyList = Map.to_list(nbBlocksByKey)
#sort the list by ascending number of occurences
sorted_list = Enum.sort(pubKeyList, &(elem(&1,1)<=elem(&2,1)))
nbElt = Enum.count(sorted_list)
if(rem(nbElt, 2) == 0) do
#if the number of elements in the list of occurences is even
#return the average of the 2 central element occurence of the list
first = Enum.at(sorted_list, trunc(nbElt/2)-1)
sec = Enum.at(sorted_list, trunc(nbElt/2))
(1/2)*(elem(first, 1) + elem(sec, 1))
else
#if the number of elements in the list of occurences is odd
#return the central element occurence of the list
indice = trunc((nbElt+1)/2)
elem(Enum.at(sorted_list, indice), 1)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment