Skip to content
Snippets Groups Projects
Commit f67b77a0 authored by Augustin Jaujay's avatar Augustin Jaujay
Browse files

Merge branch 'noemie' into dev

parents aa1ec724 5b421ec1
No related branches found
No related tags found
No related merge requests found
Pipeline #4084 failed
defmodule BMA.Blockchain.Hardship do
def get(search) do
Poison.encode!("#TODO")
@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, db_block \\ 'data/block', db_global_bindex \\ 'data/global_bindex') do
#last block of the blockchain
{:ok, :global_bindex} = :dets.open_file(:global_bindex, [{:file, db_global_bindex}, {:type, :set}])
last_block_id = :dets.match(:global_bindex, {:last_block, :"$1"})
last_block = :dets.match(:block, {last_block_id, :"$1"})
{:ok, :block} = :dets.open_file(:block, [{:file, db_block}, {:type, :set}])
case :dets.match(:block, {:"$1", %{issuer: search}}) do
[{_key,block_searched}] ->
#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
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment