Quantcast
Channel: AFPy's Planet
Viewing all articles
Browse latest Browse all 3409

Évolution de la difficulté du minage de Bitcoin

$
0
0

Le Bitcoin est une monnaie cryptographique dont la validation des transactions est faite par une preuve de travail. La preuve de travail consiste à trouver un condensat (hash) commençant par un certain nombre de zéros.

Nombre de zéro au début du hash d’une transaction

Un hash de transaction (Transaction Hash ID) ressemble, par exemple, à 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f. Dans ce cas, 10 zéros débutent le hash.

Plus le nombre de zéro exigé est élevé, plus il est difficile de trouver une solution. Ce nombre évolue au fil du temps : si une solution est trouvée rapidement, le nombre de zéro augmente pour les transactions suivantes (et inversement).

Évolution jusqu’à aujourd’hui

Croissance du nombre de zéros requis au fil du temps

En bleu, les statistiques de l’ensemble des transactions contenues dans la chaîne. En orange, la moyenne des transactions de chaque journée. Les points noirs représentent les moyennes mensuelles.

La difficulté est croissante, avec parfois des plateaux. Cela montre indirectement l’augmentation de la puissance de calcul au fil du temps (le nombre de machines minant augmente, les processeurs sont plus performants, etc.).

Cela mesure encore plus imparfaitement la pollution générée par l’utilisation :

  • d’énergies renouvelables : à une période où le prix du Bitcoin était faible, une stratégie de minimisation des coûts a poussé certains à se limiter à la consommation d’excédents d’énergie hydroélectrique ou éolienne.
  • d’énergie fossile : le prix actuel pousse à la relance de centrales à gaz ou à charbon.

Production du graphique

Il est possible de voir les informations d’une transaction sur des services web mais autant extraire les informations à partir de la chaîne Bitcoin avec le client grâce à un script shell suivant :

#! /bin/sh
MAX_BLOCK=$(./bin/bitcoin-cli getblockcount)

for i in $(seq 1 $MAX_BLOCK); do {
HASH=$(./bin/bitcoin-cli getblockhash $i)
./bin/bitcoin-cli getblock $HASH | jq '[.time, .hash] | @csv' | sed 's/[\"]//g' >> stats_brutes.csv
}
done

Le script nécessite que la chaîne complète soit disponible sur la machine. La chaîne consomme presque 400 Go d’espace disque. La version du client et serveur était la 0.21.1.
Les commandes du binaire bitcoin-cli sont documentées sur https://developer.bitcoin.org/reference/rpc/index.html.
La production des statistiques au format .csv est très loooongue car le client bitcoin met du temps à répondre.

Une fois les données extraites au format .csv, un script python utilise la bibliothèque matplotlib pour produire le graphique :

import csv
import datetime
import time

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np

def draw_graph(csv_path):
    SIZE = 0.5
    stats_completes, stats_quotidiennes, stats_mensuelles = stats(csv_path)
    fig, ax = plt.subplots()
    ax.plot_date(stats_completes["x"], stats_completes["y"], markersize=SIZE, label="Tous", color="blue")
    ax.plot_date(stats_quotidiennes["x"], stats_quotidiennes["y"], markersize=SIZE*2, label="Quotidien", color="orangered")
    ax.plot_date(stats_mensuelles["x"], stats_mensuelles["y"], markersize=SIZE*2, label="Mensuel", color="black")
    fmt_year = mdates.YearLocator()
    ax.xaxis.set_major_locator(fmt_year)
    fmt_month = mdates.MonthLocator()
    ax.xaxis.set_minor_locator(fmt_month)
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
    ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d %H:%M:%S')
    fig.autofmt_xdate()

    ax.grid(True)
    plt.xlabel("Temps")    
    plt.ylabel("Nombre de zéros")
    plt.legend(loc="upper left", markerscale=4)
    plt.savefig("./graph_bitcoin_zeros.png", dpi=150)

def stats(path):
    x_toutes, y_toutes = [], []
    with open(path, newline='') as csv_file:
        stats_reader = csv.reader(csv_file)
        for ligne in stats_reader:
            date = _from_timestamp(ligne[0])
            nb_zeros = _nb_zeros(ligne[1])
            x_toutes.append(date)
            y_toutes.append(nb_zeros)
    stats_quotidiennes = _stats_quotidiennes(x_toutes, y_toutes)
    stats_mensuelles = _stats_mensuelles(x_toutes, y_toutes)
    return {"x": x_toutes, "y": y_toutes}, stats_quotidiennes, stats_mensuelles

def _stats_quotidiennes(x_toutes, y_toutes):
    dates_possibles = set([(date.year, date.month, date.day) for date in x_toutes])
    stats_quot = {date: [] for date in dates_possibles}
    for index, x in enumerate(x_toutes):
        stats_quot[x.year, x.month, x.day].append(y_toutes[index])
    x, y = [], []
    for mois in sorted(dates_possibles):
        x.append(datetime.datetime(mois[0], mois[1], mois[2]))
        y.append(_moyenne(stats_quot[mois]))
    return {"x": x, "y": y}

def _stats_mensuelles(x_toutes, y_toutes):
    dates_possibles = set([(date.year, date.month) for date in x_toutes])
    stats_mois = {date: [] for date in dates_possibles}
    for index, x in enumerate(x_toutes):
        stats_mois[x.year, x.month].append(y_toutes[index])
    x, y = [], []
    for date in sorted(dates_possibles):
        x.append(datetime.datetime(date[0], date[1], 15))
        y.append(_moyenne(stats_mois[date]))
    return {"x": x, "y": y}

def _moyenne(valeurs):
    return sum(valeurs) / len(valeurs)

def _from_timestamp(data):
    return datetime.datetime.fromtimestamp(int(data))

def _nb_zeros(data):
    count = 0
    for lettre in data:
        if lettre == "0":
            count += 1
        else:
            return count

        
if __name__ == "__main__":
    draw_graph("stats_brutes.csv")

Le script python utilise un type de graphique idéal pour le besoin, déjà inclus dans Matplotlib. 🙂


Viewing all articles
Browse latest Browse all 3409

Trending Articles