Skip to content

Instantly share code, notes, and snippets.

@vital-edu
Last active November 2, 2021 20:51
Show Gist options
  • Save vital-edu/3099119f8c847c396dbfe2bc08bc7dfe to your computer and use it in GitHub Desktop.
Save vital-edu/3099119f8c847c396dbfe2bc08bc7dfe to your computer and use it in GitHub Desktop.
Bitcoin max supply simulation
// #######################################
// ----- bin/bitcoin_simulation.dart -----
// #######################################
import 'dart:math';
import 'package:intl/intl.dart';
// import 'package:bitcoin_ssimulation/chain_params.dart';
// import 'package:bitcoin_simulation/consensus/params.dart';
// import 'package:bitcoin_simulation/validation.dart';
// import 'package:bitcoin_simulation/consensus/amount.dart';
typedef BlockSubsidyFunction = CAmount Function(int, Params);
/// This programm will simulate the max number of bitcoin that will be mined
/// by the Bitcoin Network.
///
/// Excute with `new` as the first argument to run a modified algorithm that
/// would produce exactly 21 millions of satoshis:
/// ```shell
/// dart bin/bitcoin_simulation.dart new
/// ```
///
/// Without any args, it will be executed the simulation based on the current
/// Bitcoin Core implementation, which will mine 20999999.97690000 bitcoins
/// or less:
/// ```shell
/// dart bin/bitcoin_simulation.dart
/// ```
int main(List<String> args) {
// Uncomment the code below to run the modified version on dartpad.
// args = ["new"];
BlockSubsidyFunction blockSubsidy = args.isNotEmpty && args.first == 'new'
? modifiedGetBlockSubsidy
: getBlockSubsidy;
CAmount satoshis = CAmount.zero;
int blocksMined = 0;
final Params consensusParams = CMainParams().consensus;
while (satoshis < MAX_MONEY) {
CAmount subsidy = blockSubsidy(blocksMined, consensusParams);
if (subsidy == CAmount.zero) break;
satoshis += (subsidy * CAmount.from(consensusParams.nSubsidyHalvingInterval));
blocksMined += consensusParams.nSubsidyHalvingInterval;
}
final lastSubsidizedBlock = blocksMined - 1;
final btc = satoshis / COIN;
final maxHalvings =
lastSubsidizedBlock ~/ consensusParams.nSubsidyHalvingInterval;
final lastSubsidizedBlockMinedAt =
approximateYearOfMinedBlock(lastSubsidizedBlock);
print('Last subsidized block: $lastSubsidizedBlock');
print('Last subsidized block mined on the year: $lastSubsidizedBlockMinedAt');
print('Max quantity of satoshis to be created: ${satoshis.toInt()}');
print('Max quantity of BTC to be created: ${btc.toStringAsFixed(8)}');
print('Max quantity of halvings that will happen: $maxHalvings');
return 0;
}
int approximateYearOfMinedBlock(int blocksMined) {
const firstBlockDate = "January 09, 2009 02:54 AM UTC";
const dateFormat = "MMMM d, yyyy hh:mm a UTC";
const approximateMinutesToMineBlock = 10;
final firstBlockMiningDate =
DateFormat(dateFormat).parse(firstBlockDate, true);
final blockMinedDate = firstBlockMiningDate.add(
Duration(minutes: approximateMinutesToMineBlock * blocksMined),
);
return blockMinedDate.year;
}
CAmount modifiedGetBlockSubsidy(int nHeight, Params consensusParams) {
int halvings = nHeight ~/ consensusParams.nSubsidyHalvingInterval;
// Force block reward to zero when right shift is undefined.
if (halvings >= 64) return CAmount.zero;
double nSubsidy = 50.0 * COIN.toInt();
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
nSubsidy /= pow(2, halvings);
return nSubsidy >= 1
? CAmount.from(nSubsidy.floor())
: CAmount.from(nSubsidy.ceil());
}
// #####################################
// ----- lib/consensus/amount.dart -----
// #####################################
/// This file contains fragments of the source code of the Bitcoin Core rewritten with dart-lang.
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/816e15ee81a2029cde6b4f9fe6fb93e75478c903/src/consensus/amount.h)
// ignore_for_file: constant_identifier_names, non_constant_identifier_names
/// Amount in satoshis (Can be negative)
/// ---
/// [Original implementation](https://github.com/bitcoin/bitcoin/blob/816e15ee81a2029cde6b4f9fe6fb93e75478c903/src/consensus/amount.h#L11-L12):
/// ```cpp
/// typedef int CAmount;
/// ```
///
/// CAmount is defined as BigInt to allow compatibility with dart for web.
typedef CAmount = BigInt;
/// ---
/// [Original implementation](https://github.com/bitcoin/bitcoin/blob/816e15ee81a2029cde6b4f9fe6fb93e75478c903/src/consensus/amount.h#L14):
/// ```cpp
/// static constexpr CAmount COIN = 100000000;
/// ```
final CAmount COIN = CAmount.from(100000000);
/// No amount larger than this (in satoshi) is valid.
///
/// Note that this constant is *not* the total money supply, which in Bitcoin
/// currently happens to be less than 21,000,000 BTC for various reasons, but
/// rather a sanity check. As this sanity check is used by consensus-critical
/// validation code, the exact value of the MAX_MONEY constant is consensus
/// critical; in unusual circumstances like a(nother) overflow bug that allowed
/// for the creation of coins out of thin air modification could lead to a fork.
/// ---
/// [Original implementation](https://github.com/bitcoin/bitcoin/blob/816e15ee81a2029cde6b4f9fe6fb93e75478c903/src/consensus/amount.h#L16-L25):
/// ```cpp
/// static constexpr CAmount MAX_MONEY = 21000000 * COIN;;
/// ```
final CAmount MAX_MONEY = CAmount.from(21000000) * COIN;
// #################################
// ----- lib/chain_params.dart -----
// #################################
/// This file contains fragments of the source code of the Bitcoin Core rewritten with dart-lang.
/// [See original header definition](https://github.com/bitcoin/bitcoin/blob/feedb9c84e72e4fff489810a2bbeec09bcda5763/src/chainparams.h)
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/feedb9c84e72e4fff489810a2bbeec09bcda5763/src/chainparams.cpp)
// import 'consensus/params.dart';
/// CChainParams defines various tweakable parameters of a given instance of the
/// Bitcoin system.
/// ---
/// Only the param `consensus` was keep.
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/7fcf53f7b4524572d1d0c9a5fdc388e87eb02416/src/chainparams.h#L60-L133)
abstract class CChainParams {
final Params consensus;
CChainParams({
required this.consensus,
});
}
/// Main network on which people trade goods and services.
/// ---
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/feedb9c84e72e4fff489810a2bbeec09bcda5763/src/chainparams.cpp#L58-L175)
class CMainParams implements CChainParams {
/// ---
/// The consensus params with the `nSubsidyHalvingInterval` definition.
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/feedb9c84e72e4fff489810a2bbeec09bcda5763/src/chainparams.cpp#L67)
const CMainParams()
: consensus = const Params(210000),
super();
@override
final Params consensus;
}
// ##########################################
// ----- lib/consensus/params.dart.dart -----
// ##########################################
/// This file contains fragments of the source code of the Bitcoin Core rewritten with dart-lang.
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/7fcf53f7b4524572d1d0c9a5fdc388e87eb02416/src/consensus/params.h)
/// Parameters that influence chain consensus.
/// ---
/// Only the param `nSubsidyHalvingInterval` was keep.
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/7fcf53f7b4524572d1d0c9a5fdc388e87eb02416/src/consensus/params.h#L46-L93)
class Params {
/// ---
/// This is used to determine when the halving will happen.
/// Every `nSubsidyHalvingInterval` block mined, happens a new halving.
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/7fcf53f7b4524572d1d0c9a5fdc388e87eb02416/src/consensus/params.h#L48)
final int nSubsidyHalvingInterval;
const Params(this.nSubsidyHalvingInterval);
}
// ###############################
// ----- lib/validation.dart -----
// ###############################
/// This file contains fragments of the source code of the Bitcoin Core rewritten with dart-lang.
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/816e15ee81a2029cde6b4f9fe6fb93e75478c903/src/consensus/amount.h)
// import 'consensus/amount.dart';
// import 'consensus/params.dart';
/// Function defined on Bitcoin Core rewritten with dart-lang.
///
/// [See original implementation](https://github.com/bitcoin/bitcoin/blob/1847ce2d49e13f76824bb6b52985e8ef5fbcd1db/src/validation.cpp#L1068-L1079):
/// ```cpp
/// CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
/// {
/// int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
/// // Force block reward to zero when right shift is undefined.
/// if (halvings >= 64)
/// return 0;
///
/// CAmount nSubsidy = 50 * COIN;
/// // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
/// nSubsidy >>= halvings;
/// return nSubsidy;
/// }
/// ```
CAmount getBlockSubsidy(int nHeight, Params consensusParams) {
int halvings = nHeight ~/ consensusParams.nSubsidyHalvingInterval;
// Force block reward to zero when right shift is undefined.
if (halvings >= 64) return CAmount.zero;
CAmount nSubsidy = CAmount.from(50) * COIN;
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
nSubsidy >>= halvings;
return nSubsidy;
}
// ########################
// ----- pubspec.yaml -----
// ########################
// ```yaml
// name: bitcoin_simulation
// description: Bitcoin max supply simulation
// version: 1.0.0
//
// environment:
// sdk: '>=2.14.2 <3.0.0'
//
// dev_dependencies:
// lints: ^1.0.0
// dependencies:
// intl: ^0.17.0
// ```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment