Skip to content
Snippets Groups Projects
Unverified Commit ba8eeb39 authored by Benjamin Loison's avatar Benjamin Loison
Browse files

Copy `mining_in_logarithmic_space.py` to `mining_in_logarithmic_space_constant_difficulty.py`

parent 5c853272
No related branches found
No related tags found
No related merge requests found
from bcolors import bcolors
import time
import bitcoin
from block import IS_EPSILON_TARGET_DEFINITION
import json
from argparser import get_parser
import config
# Bitcoin parameters
κ = 256
# Minimal target difference
sanityTargetDifferenceThreshold = 0.03408116026637664
def Dissolve(m, k, C, previous_score, previous_ℓ):
CStar = C[:-k]
D = {}
if len(CStar) >= 2 * m:
= getℓ(CStar, previous_ℓ)
while True:
# Could make a single function iterating on `CStar` filling a dict with keys being levels and values being the number of blocks of the associated level and stop once a level value as reached a given number of blocks.
CIndex, μ = getFirstBlockExceedingBlocksPerLevel(CStar, 2 * m, )
if CIndex == None:
break
removed, blockRemoved = llbracket(CStar, μ, CIndex)
isScoreIncreasing = score(CStar, ) + sanityTargetDifferenceThreshold >= previous_score
if not isScoreIncreasing:
if removed:
CStar.insert(CIndex, blockRemoved)
else:
CStar[CIndex].level_min -= 1
break
for μ in range( + 1):
D[μ] = uparrow(CStar, μ)
else:
= 0
D[0] = CStar
CStarScore = score(CStar, )
if (IS_EPSILON_TARGET_DEFINITION and (previous_score - CStarScore) >= sanityTargetDifferenceThreshold) or (not IS_EPSILON_TARGET_DEFINITION and CStarScore < previous_score):
print(f'score decreasing! previous: {previous_score}, newest: {CStarScore}')
exit(2)
χ = C[-k:]
return (D, , χ, CStarScore)
def Compress(m, k, C, previous_score, previous_ℓ):
(D, , χ, new_score) = Dissolve(m, k, C, previous_score, previous_ℓ)
π = U(0, , D)
return π + χ, new_score,
def uparrow(C, μ):
return [block for block in C if block.level >= μ and block.level_min <= μ]
def getFirstBlockExceedingBlocksPerLevel(C, maximumBlocksPerLevel, ):
-= 1
blocksPerLevel = [0] * κ
firstBlockIndexPerLevel = [None] * κ
for CIndex, block in enumerate(C):
for level in range(block.level_min, min(block.level, ) + 1):
blocksPerLevel[level] += 1
if firstBlockIndexPerLevel[level] == None:
firstBlockIndexPerLevel[level] = CIndex
if blocksPerLevel[level] > maximumBlocksPerLevel:
return firstBlockIndexPerLevel[level], level
return None, None
# Proceeding by dichotomy may not be worth it.
# For instance for the first 60 000 blocks, we have in theory 10 levels for the last blocks while log2(256) = 8, so because of first blocks not having a higher than 8 level, it doesn't seem worth it at the beginning at least.
def getℓ(C, previous_ℓ):
previous_ℓ += 1
# Can't use `[0] * previous_ℓ`, as would have to check if the array is long enough below before updating its values.
blocksPerLevel = [0] * κ
for block in C:
for level in range(previous_ℓ, block.level + 1):
blocksPerLevel[level] += 1
for level in range(previous_ℓ, κ):
if blocksPerLevel[level] < 2 * m:
return level - 1
def llbracket(C, μ, CIndex, actually = False):
removed = False
block = C[CIndex]
if block.level == μ:
if actually:
debug('removing', block.height)
del C[CIndex]
removed = True
else:
if actually:
debug(f'increasing {block.height} level_min from {block.level_min} to {μ + 1}')
block.level_min += 1
return removed, block
def score(C, ):
return sum([(min(block.level, ) + 1 - block.level_min) * block.score for block in C])
def U(lowerBound, upperBound, chains):
chains = [chains[μ] for μ in chains]
flattened_chain = [block for chain in chains[lowerBound:upperBound+1] for block in chain]
unique_blocks = {}
for block in flattened_chain:
if not block.height in unique_blocks or block.level_min < unique_blocks[block.height].level_min:
unique_blocks[block.height] = block
unique_blocks = unique_blocks.values()
sorted_blocks = sorted(unique_blocks, key=lambda block: block.height)
return sorted_blocks
lastTimeCheck = None
def printTimeSinceLastTimeCheck(s):
if verifyCorrectness:
return
global lastTimeCheck
currentTime = time.time()
if lastTimeCheck == None:
lastTimeCheck = currentTime
print(s, round((currentTime - lastTimeCheck) * 1_000, 3), 'ms')
lastTimeCheck = currentTime
def debug(*args):
if debugging:
print(*args)
parser = get_parser() # Create a parser
args = parser.parse_args() # Parse arguments
if args.headers != config.HEADERS_FILE_PATH:
args.load_from_headers = True
print(args)
# Mining in Logarithmic Space parameters
k = args.unstable_part_length # TODO: be able to redo Loïc computation
m = 3 * k
debugging = args.debugging
verifyCorrectness = args.verify_correctness
config.HEADERS_FILE_PATH = args.headers
bitcoin.LOAD_FROM_HEADERS_FILE = args.load_from_headers
lvls = {}
targets = []
compressSize = []
compressScore = []
previous_score = 0
previous_ℓ = 0
Π = []
headersNumber = bitcoin.loadHeaders(args.break_at)
for height in range(headersNumber):
lastTimeCheck = time.time()
b = bitcoin.getBlockByHeight(height)
# Not precise at the block scale.
targets += [b.target]
compressSize += [len(Π)]
compressScore += [previous_score]
#printTimeSinceLastTimeCheck('block retrieval')
isLastIteration = height == headersNumber - 1
debugging = debugging or isLastIteration
verifyCorrectness = verifyCorrectness or isLastIteration
debug(f'{height=}')
bLvl = b.level
for lvl in range(bLvl + 1):
if lvl in lvls:
lvls[lvl] += 1
else:
lvls[lvl] = 1
for lvl in lvls:
debug(f'{lvl}: {lvls[lvl]}')
debug(f'Before compress block level {bLvl} {b.score}')
Π, previous_score, previous_ℓ = Compress(m, k, Π + [b], previous_score, previous_ℓ)
printTimeSinceLastTimeCheck(f'compress computation ({height=})')
if verifyCorrectness:
(D, , χ, previous_score) = Dissolve(m, k, Π, previous_score, previous_ℓ)
debug(f'After compress (score: {score(Π[:-k], )}):')
#printTimeSinceLastTimeCheck('dissolve computation')
for μ in D:
debug(bcolors.WARNING + f'μ: {μ}' + bcolors.ENDC + f', len(Π): {len(Π)}, ' + bcolors.OKGREEN + f'len(D[μ]): {len(D[μ])}' + bcolors.ENDC + f' ({[f"{b.height} ({b.level_min} - {b.level}, {round(b.score, 4)})" for b in D[μ]]})')
#if ℓ == 2:
# break
if args.break_at:
if height == args.break_at:
break
if args.step:
input()
data = {
'targets': targets,
'compressSize': compressSize,
'compressScore': compressScore
}
with open('data.json', 'w') as f:
json.dump(data, f)
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment