├── .gitignore ├── BlockSim.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── BlockSim ├── arithmetic_type │ ├── License.md │ ├── Readme.md │ ├── arithmetic_istream.hpp │ ├── arithmetic_ostream.hpp │ ├── arithmetic_to_string.hpp │ ├── arithmetic_type.hpp │ ├── enable_if.hpp │ ├── primitive_cast.hpp │ ├── returns.hpp │ └── traits.hpp ├── block.cpp ├── block.hpp ├── blockchain.cpp ├── blockchain.hpp ├── blockchain_settings.cpp ├── blockchain_settings.hpp ├── clever_selfish_miner.cpp ├── clever_selfish_miner.hpp ├── default_miner.cpp ├── default_miner.hpp ├── default_selfish_miner.cpp ├── default_selfish_miner.hpp ├── function_fork_miner.cpp ├── function_fork_miner.hpp ├── function_fork_selfish_miner.cpp ├── function_fork_selfish_miner.hpp ├── game.cpp ├── game.hpp ├── game_result.cpp ├── game_result.hpp ├── gap_miner.cpp ├── gap_miner.hpp ├── lazy_fork_miner.cpp ├── lazy_fork_miner.hpp ├── logging.h ├── miner.cpp ├── miner.hpp ├── minerGroup.cpp ├── minerGroup.hpp ├── minerParameters.h ├── minerStrategies.h ├── miner_result.cpp ├── miner_result.hpp ├── mining_style.cpp ├── mining_style.hpp ├── petty_miner.cpp ├── petty_miner.hpp ├── picky_mining_style.cpp ├── picky_mining_style.hpp ├── publishing_strategy.cpp ├── publishing_strategy.hpp ├── selfish_miner.cpp ├── selfish_miner.hpp ├── simple_mining_style.cpp ├── simple_mining_style.hpp ├── simple_publisher.cpp ├── simple_publisher.hpp ├── strategy.cpp ├── strategy.hpp ├── typeDefs.cpp ├── typeDefs.hpp ├── utils.cpp ├── utils.hpp ├── withholding_publisher.cpp └── withholding_publisher.hpp ├── LICENSE.txt ├── Makefile ├── Readme.md ├── SelfishSim └── main.cpp └── StratSim ├── exp3_learning_model.cpp ├── exp3_learning_model.hpp ├── learning_model.cpp ├── learning_model.hpp ├── learning_strategy.cpp ├── learning_strategy.hpp ├── main.cpp ├── multiplicative_weights_learning_model.cpp └── multiplicative_weights_learning_model.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | 3 | -------------------------------------------------------------------------------- /BlockSim.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/License.md: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/Readme.md: -------------------------------------------------------------------------------- 1 | ## Arithmetic types 2 | 3 | ### Provides 4 | 5 | `Arithmetic` where `T` models the `Arithmetic` concept is a `T` wrapper that: 6 | - disables _any_ implicit conversions between `T` and other types, and 7 | - can be made opaque by passing it a unique tag as second template parameter 8 | `Arithmetic`. 9 | 10 | ### Why is this useful? 11 | 12 | It let's you easily specify strongly typed interfaces when Arithmetic types are 13 | involved! 14 | 15 | ### Example 1: disabling implicit conversions 16 | 17 | ```c++ 18 | int a{2}; 19 | long b{3}; 20 | b = a; // works: the implicit conversion is safe 21 | 22 | Arithmetic a{2}; 23 | Arithmetic b{3}; 24 | b = a; // fails: implicit assignment requires implicit conversion 25 | b = Arithmetic{a}; // works: explicit construction 26 | b = static_cast>(a); // works: explicit conversion 27 | ``` 28 | 29 | ### Example 2: opaque type-defs 30 | 31 | ```c++ 32 | struct Tag1 {}; 33 | struct Tag2 {}; 34 | 35 | using Type1 = Arithmetic; 36 | using Type2 = Arithmetic; 37 | Type1 a{2}; 38 | Type2 b{3}; 39 | a = b; // fails: Type1 != Type2 even tho both wrap an int 40 | b = Type2{a}; // works: explicit construction 41 | b = static_cast(a); // works: explicit conversion 42 | ``` 43 | 44 | See the [tests](https://github.com/gnzlbg/arithmetic_type/blob/master/test/all_test.cpp) 45 | for more examples. 46 | 47 | ### Other facilities 48 | - `to_string` function is provided in 49 | `arithmetic_type/arithmetic_to_string.hpp` 50 | - i/o stream operators are provided in 51 | `arithmetic_type/arithmetic_istream.hpp` and 52 | `arithmetic_type/arithmetic_ostream.hpp` 53 | - when writing generic code one sometimes need to deal with both `Arithmetic` 54 | and `T`. The function `primitive_cast(T t)` does the right thing. 55 | 56 | ### Dependencies: 57 | - C++11/14 compiler (currently tested with clang 3.5 only) 58 | 59 | ### License 60 | - Boost Software License Version 1.0 61 | 62 | ### Comparison with BOOST_STRONG_TYPEDEF 63 | 64 | `Arithmetic` supports C++1y `constexpr`, move semantics, and disables 65 | implicit conversions. 66 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/arithmetic_istream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_ISTREAM_ 2 | #define ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_ISTREAM_ 3 | //////////////////////////////////////////////////////////////////////////////// 4 | #include 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | namespace arithmetic { 8 | 9 | /// \brief istream operator 10 | template 11 | inline auto operator>>(std::basic_istream& i, Arithmetic& v) 12 | -> decltype(i >> v()) { 13 | return i >> v(); 14 | } 15 | 16 | } // namespace arithmetic 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | #endif // ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_ISTREAM_ 20 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/arithmetic_ostream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_OSTREAM_ 2 | #define ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_OSTREAM_ 3 | //////////////////////////////////////////////////////////////////////////////// 4 | #include 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | namespace arithmetic { 8 | 9 | /// \brief ostream operator 10 | template 11 | inline auto operator<<(std::basic_ostream& o, const Arithmetic& v) 12 | -> decltype(o << v()) { 13 | return o << v(); 14 | } 15 | 16 | } // namespace arithmetic 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | #endif // ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_OSTREAM_ 20 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/arithmetic_to_string.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_TO_STRING_ 2 | #define ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_TO_STRING_ 3 | //////////////////////////////////////////////////////////////////////////////// 4 | #include 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | namespace arithmetic { 8 | 9 | /// \brief to_string 10 | template 11 | inline std::string to_string(const Arithmetic a) { 12 | return std::to_string(a()); 13 | } 14 | 15 | } // namespace arithmetic 16 | 17 | //////////////////////////////////////////////////////////////////////////////// 18 | #endif // ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_TO_STRING_ 19 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/arithmetic_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_TYPE_ 2 | #define ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_TYPE_ 3 | //////////////////////////////////////////////////////////////////////////////// 4 | #include 5 | #include 6 | #include "returns.hpp" 7 | #include "enable_if.hpp" 8 | //////////////////////////////////////////////////////////////////////////////// 9 | namespace arithmetic { 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | /// \name Index types 13 | ///@{ 14 | /// \brief Implements an integer type 15 | template struct Arithmetic { 16 | using value_type = T; 17 | using type = T; 18 | 19 | /// \name Asignment operators 20 | ///@{ 21 | constexpr Arithmetic() = default; 22 | constexpr Arithmetic(const Arithmetic& other) = default; 23 | constexpr Arithmetic(Arithmetic&& other) = default; 24 | constexpr Arithmetic& operator=(const Arithmetic& other) = default; 25 | constexpr Arithmetic& operator=(Arithmetic&& other) = default; 26 | 27 | constexpr explicit Arithmetic(const T& other) noexcept( 28 | std::is_nothrow_constructible::value) 29 | : value{other} {} 30 | template 31 | constexpr explicit Arithmetic(const Arithmetic& other) noexcept( 32 | std::is_nothrow_constructible::value) 33 | : value(other.value) {} 34 | constexpr Arithmetic& operator=(const T& other) noexcept { 35 | value = other; 36 | return *this; 37 | } 38 | ///@} 39 | 40 | /// \name Conversion operators 41 | ///@{ 42 | explicit constexpr operator T() noexcept { return value; } 43 | explicit constexpr operator const T() const noexcept { return value; } 44 | 45 | template 46 | explicit constexpr operator Arithmetic() noexcept { 47 | return value; 48 | } 49 | 50 | template 51 | explicit constexpr operator const Arithmetic() const noexcept { 52 | return value; 53 | } 54 | ///@} 55 | 56 | /// \name Compound assignment +=, -=, *=, /= 57 | ///@{ 58 | constexpr Arithmetic& operator+=(const Arithmetic& other) noexcept { 59 | value += other.value; 60 | return *this; 61 | } 62 | constexpr Arithmetic& operator-=(const Arithmetic& other) noexcept { 63 | value -= other.value; 64 | return *this; 65 | } 66 | constexpr Arithmetic& operator*=(const Arithmetic& other) noexcept { 67 | value *= other.value; 68 | return *this; 69 | } 70 | constexpr Arithmetic& operator/=(const Arithmetic& other) noexcept { 71 | value /= other.value; 72 | return *this; 73 | } 74 | ///@} 75 | 76 | /// \name Prefix increment operators ++(),--() 77 | ///@{ 78 | constexpr Arithmetic& operator++() noexcept { 79 | ++value; 80 | return *this; 81 | } 82 | constexpr Arithmetic& operator--() noexcept { 83 | --value; 84 | return *this; 85 | } 86 | ///@} 87 | 88 | /// \name Postfix increment operators ()++,()-- 89 | ///@{ 90 | constexpr Arithmetic operator++(int) noexcept { 91 | Arithmetic tmp(*this); 92 | ++(*this); 93 | return tmp; 94 | } 95 | constexpr Arithmetic operator--(int) noexcept { 96 | Arithmetic tmp(*this); 97 | --(*this); 98 | return tmp; 99 | } 100 | ///@} 101 | 102 | /// \name Access operator 103 | ///@{ 104 | constexpr T& operator()() & noexcept { return value; } 105 | constexpr T operator()() && noexcept { return value; } 106 | constexpr T operator()() const& noexcept { return value; } 107 | ///@} 108 | 109 | /// Data (wrapped value): 110 | T value; 111 | }; 112 | ///@} 113 | 114 | /// \brief swap 115 | /// \relates Arithmetic 116 | template 117 | constexpr void swap(Arithmetic&& a, Arithmetic&& b) noexcept { 118 | using std::swap; 119 | swap(a.value, b.value); 120 | } 121 | 122 | /// \name Arithmetic operators +,-,*,/,unary - 123 | /// \relates Arithmetic 124 | ///@{ 125 | template 126 | constexpr Arithmetic operator+(Arithmetic a, 127 | const Arithmetic& b) noexcept { 128 | return a += b; 129 | } 130 | template 131 | constexpr Arithmetic operator-(Arithmetic a, 132 | const Arithmetic& b) noexcept { 133 | return a -= b; 134 | } 135 | template 136 | constexpr Arithmetic operator*(Arithmetic a, 137 | const Arithmetic& b) noexcept { 138 | return a *= b; 139 | } 140 | template 141 | constexpr Arithmetic operator/(Arithmetic a, 142 | const Arithmetic& b) noexcept { 143 | return a /= b; 144 | } 145 | 146 | template 147 | constexpr Arithmetic operator-(Arithmetic const& other) noexcept { 148 | return Arithmetic{-other.value}; 149 | } 150 | ///@} 151 | 152 | /// \name Comparison operators ==, !=, <, >, <=, >= 153 | /// \relates Arithmetic 154 | ///@{ 155 | template 156 | constexpr bool operator==(const Arithmetic& a, 157 | const Arithmetic& b) noexcept { 158 | return a.value == b.value; 159 | } 160 | template 161 | constexpr bool operator<(const Arithmetic& a, 162 | const Arithmetic& b) noexcept { 163 | return a.value < b.value; 164 | } 165 | template 166 | constexpr bool operator<=(const Arithmetic& a, 167 | const Arithmetic& b) noexcept { 168 | return a < b || a == b; 169 | } 170 | template 171 | constexpr bool operator!=(const Arithmetic& a, 172 | const Arithmetic& b) noexcept { 173 | return !(a == b); 174 | } 175 | template 176 | constexpr bool operator>(const Arithmetic& a, 177 | const Arithmetic& b) noexcept { 178 | return !(a <= b); 179 | } 180 | template 181 | constexpr bool operator>=(const Arithmetic& a, 182 | const Arithmetic& b) noexcept { 183 | return !(a < b); 184 | } 185 | ///@} 186 | 187 | /// \name Pointer arithmetic 188 | ///@{ 189 | 190 | template> = detail_::dummy> 192 | constexpr auto operator+(T a, const Arithmetic& i) 193 | RETURNS(a + i()); 194 | 195 | template> = detail_::dummy> 197 | constexpr auto operator+(T a, const Arithmetic& i) 198 | RETURNS(a + i()); 199 | 200 | template> = detail_::dummy> 202 | constexpr auto operator-(T a, const Arithmetic& i) 203 | RETURNS(a - i()); 204 | 205 | template> = detail_::dummy> 207 | constexpr auto operator-(T a, const Arithmetic& i) 208 | RETURNS(a - i()); 209 | 210 | ///@} 211 | 212 | //////////////////////////////////////////////////////////////////////////////// 213 | } // namespace arithmetic 214 | //////////////////////////////////////////////////////////////////////////////// 215 | 216 | /// \name Arithmetic types are numeric types 217 | /// \relates Arithmetic 218 | ///@{ 219 | namespace std { 220 | 221 | template 222 | class numeric_limits> : public numeric_limits { 223 | public: 224 | static constexpr bool is_specialized = true; 225 | }; 226 | 227 | } // namespace std 228 | ///@} 229 | 230 | //////////////////////////////////////////////////////////////////////////////// 231 | #endif // ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_ARITHMETIC_TYPE_ 232 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/enable_if.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Martinho Fernandes (see below) 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | /// \brief EnableIf / DisableIf as proposed by Martinho Fernandes in 7 | /// http://flamingdangerzone.com/cxx11/2012/06/01/almost-static-if.html 8 | 9 | #if !defined(ARITHMETIC_TYPE_DETAIL_ENABLE_IF_HPP_) 10 | #define ARITHMETIC_TYPE_DETAIL_ENABLE_IF_HPP_ 11 | 12 | #include 13 | 14 | namespace detail_ { 15 | enum class enabler {}; 16 | constexpr enabler dummy = {}; 17 | 18 | template 19 | using EnableIf = std::enable_if_t; 20 | 21 | template 22 | using DisableIf = std::enable_if_t; 23 | 24 | } // namespace detail_ 25 | 26 | #endif // ARITHMETIC_TYPE_ENABLE_IF_HPP_ 27 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/primitive_cast.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_PRIMITIVE_CAST_ 2 | #define ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_PRIMITIVE_CAST_ 3 | //////////////////////////////////////////////////////////////////////////////// 4 | #include "traits.hpp" 5 | #include "enable_if.hpp" 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | namespace arithmetic { 9 | 10 | template > = detail_::dummy> 11 | constexpr inline auto&& primitive_cast(T&& t) { 12 | static_assert(is_arithmetic::value, "T must be an integer!"); 13 | return t(); 14 | } 15 | 16 | template > = detail_::dummy> 17 | constexpr inline auto primitive_cast(const T& t) -> decltype(t()) { 18 | static_assert(is_arithmetic::value, "T must be an integer!"); 19 | return t(); 20 | } 21 | 22 | template > = detail_::dummy> 23 | constexpr inline auto& primitive_cast(T& t) { 24 | static_assert(is_arithmetic::value, "T must be an integer!"); 25 | return t(); 26 | } 27 | 28 | template > = detail_::dummy> 29 | constexpr inline auto&& primitive_cast(T&& t) { 30 | static_assert(!is_arithmetic::value, "T can't be an integer!"); 31 | return std::forward(t); 32 | } 33 | 34 | template > = detail_::dummy> 35 | constexpr inline auto primitive_cast(const T& t) -> decltype(t) { 36 | static_assert(!is_arithmetic::value, "T can't be an integer!"); 37 | return t; 38 | } 39 | 40 | template > = detail_::dummy> 41 | constexpr inline auto& primitive_cast(T& t) { 42 | static_assert(!is_arithmetic::value, "T can't be an integer!"); 43 | return t; 44 | } 45 | 46 | } // namespace arithmetic 47 | 48 | //////////////////////////////////////////////////////////////////////////////// 49 | #endif // ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_PRIMITIVE_CAST_ 50 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/returns.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Dave Abrahams and Eric Niebler (see below) 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | /// \brief Returns macro 7 | 8 | #if !defined(ARITHMETIC_TYPE_DETAIL_RETURNS_HPP_) 9 | #define ARITHMETIC_TYPE_DETAIL_RETURNS_HPP_ 10 | 11 | #include 12 | 13 | /// \brief RETURNS() is used to avoid writing boilerplate 14 | /// "->decltype(x) { return x; }" phrases. 15 | // 16 | /// USAGE: auto function() RETURNS(); 17 | /// 18 | /// Note: we end with a unique typedef so the function can be followed 19 | /// by a semicolon. If we omit the semicolon, editors get confused and 20 | /// think we haven't completed the function declaration. 21 | /// 22 | /// Author: Dave Abrahams, see 23 | /// https://groups.google.com/forum/#!msg/boost-devel-archive/OzJ5Ft3pSnU\ 24 | /// /b_Ter9bgNqAJ . 25 | /// 26 | /// \todo Eric Niebler discusses how to improve errors messages when combining 27 | /// the RETURNS macro with SFINAE for expressions here: 28 | /// https://groups.google.com/forum/#!topic/boost-developers-archive\ 29 | /// /Ipn1bF24STc%5B1-25-false%5D . 30 | /// 31 | #define RETURNS(...) \ 32 | noexcept(noexcept(decltype(__VA_ARGS__)(std::move(__VA_ARGS__)))) \ 33 | ->decltype(__VA_ARGS__) { \ 34 | return (__VA_ARGS__); \ 35 | } \ 36 | using RETURNS_CAT(RETURNS_, __LINE__) = int 37 | // Standard PP concatenation formula 38 | #define RETURNS_CAT_0(x, y) x##y 39 | #define RETURNS_CAT(x, y) RETURNS_CAT_0(x, y) 40 | 41 | #endif // ARITHMETIC_TYPE_RETURNS_HPP_ 42 | -------------------------------------------------------------------------------- /BlockSim/arithmetic_type/traits.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_TRAITS_ 2 | #define ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_TRAITS_ 3 | //////////////////////////////////////////////////////////////////////////////// 4 | #include "arithmetic_type.hpp" 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | namespace arithmetic { 8 | 9 | template struct is_arithmetic_ { 10 | static const bool value = false; 11 | }; 12 | template struct is_arithmetic_> { 13 | static const bool value = true; 14 | }; 15 | 16 | template struct is_arithmetic { 17 | static const bool value 18 | = is_arithmetic_>>::value; 19 | }; 20 | 21 | } // namespace arithmetic 22 | 23 | //////////////////////////////////////////////////////////////////////////////// 24 | #endif // ARITHMETIC_UTILITIES_ARITHMETIC_TYPE_TRAITS_ 25 | -------------------------------------------------------------------------------- /BlockSim/block.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // block.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "block.hpp" 10 | #include "miner.hpp" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | constexpr auto timeMax = std::numeric_limits::max(); 17 | 18 | Block::Block(BlockValue blockReward_) : Block(nullptr, nullptr, BlockTime(0), Value(0), BlockHeight(0), Value(0), Value(0), Value(rawValue(blockReward_))) {} 19 | 20 | Block::Block(const Block *parent_, const Miner *miner_, BlockTime timeSeconds_, Value txFees, BlockHeight height_, Value txFeesInChain_, Value valueInChain_, Value blockReward_) : timeBroadcast(timeMax), parent(parent_), miner(miner_), height(height_), timeMined(timeSeconds_), value(txFees + blockReward_), txFeesInChain(txFeesInChain_), valueInChain(valueInChain_), blockReward(blockReward_) {} 21 | 22 | Block::Block(const Block *parent_, const Miner *miner_, BlockTime timeSeconds_, Value txFees) : 23 | Block(parent_, miner_, timeSeconds_, txFees, parent_->height + BlockHeight(1), parent_->txFeesInChain + txFees, parent_->valueInChain + parent_->blockReward + txFees, parent_->nextBlockReward()) {} 24 | 25 | void Block::reset(const Block *parent_, const Miner *miner_, BlockTime timeSeconds_, Value txFees) { 26 | height = parent_->height + BlockHeight(1); 27 | timeMined = timeSeconds_; 28 | timeBroadcast = timeMax; 29 | value = txFees + parent_->nextBlockReward(); 30 | txFeesInChain = txFees + parent_->txFeesInChain; 31 | valueInChain = txFees + parent_->valueInChain + parent_->nextBlockReward(); 32 | blockReward = parent_->nextBlockReward(); 33 | parent = parent_; 34 | miner = miner_; 35 | } 36 | 37 | Value Block::nextBlockReward() const { 38 | return blockReward; 39 | } 40 | 41 | void Block::broadcast(BlockTime timePub) { 42 | timeBroadcast = timePub; 43 | } 44 | 45 | bool Block::isBroadcast() const { 46 | return timeBroadcast < timeMax; 47 | } 48 | 49 | BlockTime Block::getTimeBroadcast() const { 50 | return timeBroadcast; 51 | } 52 | 53 | std::ostream& operator<< (std::ostream& out, const Block& mc) { 54 | mc.print(out, true); 55 | return out; 56 | } 57 | 58 | std::vector Block::getChain() const { 59 | std::vector chain; 60 | const Block *current = this; 61 | while (current) { 62 | chain.push_back(current); 63 | current = current->parent; 64 | } 65 | return chain; 66 | } 67 | 68 | void Block::print(std::ostream& os, bool isPublished) const { 69 | if (height == BlockHeight(0)) { 70 | os << "[h:0, m:gen]"; 71 | return; 72 | } 73 | if (isPublished) { 74 | os << "{"; 75 | } 76 | else { 77 | os << "["; 78 | } 79 | 80 | os << "h:" << height << ", m:" << miner->params.name << ", v:" << value << ", t:" << timeMined; 81 | 82 | if (isPublished) { 83 | os << "}->"; 84 | } 85 | else { 86 | os << "]->"; 87 | } 88 | } 89 | 90 | bool Block::minedBy(const Miner *miner_) const { 91 | return miner == miner_; 92 | } 93 | -------------------------------------------------------------------------------- /BlockSim/block.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // block.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef block_hpp 10 | #define block_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | #include 16 | 17 | class Miner; 18 | 19 | class Block { 20 | protected: 21 | BlockTime timeBroadcast; 22 | public: 23 | const Block *parent; 24 | const Miner *miner; 25 | BlockHeight height; 26 | BlockTime timeMined; 27 | Value value; 28 | Value txFeesInChain; 29 | Value valueInChain; 30 | Value blockReward; 31 | 32 | Block(const Block *parent_, const Miner *miner_, BlockTime timeSeconds, Value txFees, BlockHeight height, Value txFeesInChain, Value valueInChain, Value blockReward); 33 | 34 | Block(BlockValue blockReward); 35 | Block(const Block *parent_, const Miner *miner_, BlockTime timeSeconds_, Value txFees); 36 | 37 | void reset(const Block *parent, const Miner *miner, BlockTime timeSeconds, Value txFees); 38 | 39 | void broadcast(BlockTime timePub); 40 | BlockTime getTimeBroadcast() const; 41 | bool isBroadcast() const; 42 | 43 | Value nextBlockReward() const; 44 | 45 | bool minedBy(const Miner *miner) const; 46 | void print(std::ostream& where, bool isPublished) const; 47 | std::vector getChain() const; 48 | 49 | }; 50 | 51 | std::ostream& operator<< (std::ostream& out, const Block& mc); 52 | 53 | #endif /* block_hpp */ 54 | -------------------------------------------------------------------------------- /BlockSim/blockchain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // blockchain.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "blockchain.hpp" 10 | #include "utils.hpp" 11 | #include "block.hpp" 12 | #include "blockchain_settings.hpp" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | Blockchain::Blockchain(BlockchainSettings blockchainSettings) : 21 | valueNetworkTotal(0), 22 | timeInSecs(0), 23 | secondsPerBlock(blockchainSettings.secondsPerBlock), 24 | transactionFeeRate(blockchainSettings.transactionFeeRate), 25 | _maxHeightPub(0) 26 | { 27 | _blocks.reserve(rawCount(blockchainSettings.numberOfBlocks) * 2); 28 | _blocksIndex.resize(rawCount(blockchainSettings.numberOfBlocks) * 2); 29 | _smallestBlocks.resize(rawCount(blockchainSettings.numberOfBlocks) * 2); 30 | reset(blockchainSettings); 31 | } 32 | 33 | std::unique_ptr Blockchain::createBlock(const Block *parent, const Miner *miner, Value value) { 34 | Value txFees = value - parent->nextBlockReward(); 35 | if (_oldBlocks.size() == 0) { 36 | return std::make_unique(parent, miner, getTime(), txFees); 37 | } 38 | 39 | auto block = std::move(_oldBlocks.back()); 40 | _oldBlocks.pop_back(); 41 | block->reset(parent, miner, getTime(), txFees); 42 | return block; 43 | } 44 | 45 | void Blockchain::reset(BlockchainSettings blockchainSettings) { 46 | valueNetworkTotal = 0; 47 | timeInSecs = BlockTime(0); 48 | secondsPerBlock = blockchainSettings.secondsPerBlock; 49 | transactionFeeRate = blockchainSettings.transactionFeeRate; 50 | _maxHeightPub = BlockHeight(0); 51 | _oldBlocks.reserve(_oldBlocks.size() + _blocks.size()); 52 | for (auto &block : _blocks) { 53 | _oldBlocks.push_back(std::move(block)); 54 | } 55 | _blocks.clear(); 56 | _smallestBlocks[0].clear(); 57 | _blocksIndex[0].clear(); 58 | auto genesis = std::make_unique(blockchainSettings.blockReward); 59 | _smallestBlocks[0].push_back(genesis.get()); 60 | _blocksIndex[0].push_back(_blocks.size()); 61 | _blocks.push_back(std::move(genesis)); 62 | } 63 | 64 | void Blockchain::publishBlock(std::unique_ptr block) { 65 | assert(block); 66 | assert(block->height <= _maxHeightPub + BlockHeight(1)); 67 | 68 | HeightType height = rawHeight(block->height); 69 | 70 | if (block->height > _maxHeightPub) { 71 | _blocksIndex[height].clear(); 72 | _smallestBlocks[height].clear(); 73 | _smallestBlocks[height].push_back(block.get()); 74 | _maxHeightPub = block->height; 75 | } else { 76 | std::vector &smallestVector = _smallestBlocks[height]; 77 | 78 | if (block->value < smallestVector.front()->value) { 79 | smallestVector.clear(); 80 | smallestVector.push_back(block.get()); 81 | } else if (block->value == smallestVector.front()->value) { 82 | smallestVector.push_back(block.get()); 83 | } 84 | } 85 | 86 | _blocksIndex[height].push_back(_blocks.size()); 87 | _blocks.push_back(std::move(block)); 88 | } 89 | 90 | BlockCount Blockchain::blocksOfHeight(BlockHeight height) const { 91 | return BlockCount(_blocksIndex[rawHeight(height)].size()); 92 | } 93 | 94 | const std::vector Blockchain::oldestBlocks(BlockHeight height) const { 95 | BlockTime minTimePublished(std::numeric_limits::max()); 96 | for (size_t index : _blocksIndex[rawHeight(height)]) { 97 | minTimePublished = std::min(_blocks[index]->getTimeBroadcast(), minTimePublished); 98 | } 99 | 100 | std::vector possiblities; 101 | for (size_t index : _blocksIndex[rawHeight(height)]) { 102 | if (_blocks[index]->getTimeBroadcast() == minTimePublished) { 103 | possiblities.push_back(_blocks[index].get()); 104 | } 105 | } 106 | assert(possiblities.size() > 0); 107 | return possiblities; 108 | } 109 | 110 | Block &Blockchain::oldest(BlockHeight height) const { 111 | auto possiblities = oldestBlocks(height); 112 | return *possiblities[selectRandomIndex(possiblities.size())]; 113 | } 114 | 115 | Block &Blockchain::most(BlockHeight height) const { 116 | auto &smallestBlocks = _smallestBlocks[rawHeight(height)]; 117 | size_t index = selectRandomIndex(smallestBlocks.size()); 118 | Block *block = smallestBlocks[index]; 119 | return *block; 120 | } 121 | 122 | const Block &Blockchain::winningHead() const { 123 | Value largestValue(0); 124 | for (size_t index : _blocksIndex[rawHeight(getMaxHeightPub())]) { 125 | largestValue = std::max(largestValue, _blocks[index]->valueInChain); 126 | } 127 | 128 | std::vector possiblities; 129 | for (size_t index : _blocksIndex[rawHeight(getMaxHeightPub())]) { 130 | if (_blocks[index]->valueInChain == largestValue) { 131 | possiblities.push_back(_blocks[index].get()); 132 | } 133 | } 134 | std::uniform_int_distribution vectorDis(0, possiblities.size() - 1); 135 | return *possiblities[selectRandomIndex(possiblities.size())]; 136 | } 137 | 138 | void Blockchain::advanceToTime(BlockTime time) { 139 | assert(time >= timeInSecs); 140 | valueNetworkTotal += transactionFeeRate * (time - timeInSecs); 141 | timeInSecs = time; 142 | } 143 | 144 | BlockValue Blockchain::expectedBlockSize() const { 145 | return transactionFeeRate * secondsPerBlock + BlockValue(_smallestBlocks[rawHeight(getMaxHeightPub())].front()->nextBlockReward()); 146 | } 147 | 148 | TimeRate Blockchain::chanceToWin(HashRate hashRate) const { 149 | return hashRate / secondsPerBlock; 150 | } 151 | 152 | Block *Blockchain::blockByMinerAtHeight(BlockHeight height, const Miner &miner) const { 153 | for (size_t index : _blocksIndex[rawHeight(height)]) { 154 | if (_blocks[index]->minedBy(&miner)) { 155 | return _blocks[index].get(); 156 | } 157 | } 158 | return nullptr; 159 | } 160 | 161 | Block &Blockchain::most(BlockHeight height, const Miner &miner) const { 162 | Block *block = blockByMinerAtHeight(height, miner); 163 | if (block) { 164 | return *block; 165 | } 166 | 167 | return most(height); 168 | } 169 | 170 | Block &Blockchain::oldest(BlockHeight height, const Miner &miner) const { 171 | Block *block = blockByMinerAtHeight(height, miner); 172 | if (block) { 173 | return *block; 174 | } 175 | 176 | return oldest(height); 177 | } 178 | 179 | Value Blockchain::gap(BlockHeight height) const { 180 | return rem(most(height - BlockHeight(1))) - rem(most(height)); 181 | } 182 | 183 | Value Blockchain::rem(const Block &block) const { 184 | return valueNetworkTotal - block.txFeesInChain; 185 | } 186 | 187 | const std::vector Blockchain::getHeads() const { 188 | std::unordered_set nonHeadBlocks; 189 | std::unordered_set possibleHeadBlocks; 190 | for (auto &block : _blocks) { 191 | if (block->parent != nullptr) { 192 | nonHeadBlocks.insert(block->parent); 193 | possibleHeadBlocks.erase(block->parent); 194 | } 195 | if (nonHeadBlocks.find(block.get()) == end(nonHeadBlocks)) { 196 | possibleHeadBlocks.insert(block.get()); 197 | } 198 | } 199 | return std::vector(std::begin(possibleHeadBlocks), std::end(possibleHeadBlocks)); 200 | } 201 | 202 | void Blockchain::printBlockchain() const { 203 | std::unordered_set printedBlocks; 204 | for (auto ¤t : getHeads()) { 205 | auto chain = current->getChain(); 206 | for (auto block : chain) { 207 | if (printedBlocks.find(block) == end(printedBlocks)) { 208 | std::cout << *block; 209 | printedBlocks.insert(block); 210 | } else { 211 | break; 212 | } 213 | } 214 | std::cout << std::endl; 215 | } 216 | } 217 | 218 | void Blockchain::printHeads() const { 219 | std::cout << "heads:" << std::endl; 220 | for (auto current : getHeads()) { 221 | std::cout << *current << std::endl; 222 | } 223 | std::cout << "end heads." << std::endl; 224 | } 225 | 226 | 227 | -------------------------------------------------------------------------------- /BlockSim/blockchain.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // blockchain.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef blockchain_hpp 10 | #define blockchain_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | class Block; 19 | class GenesisBlock; 20 | class Miner; 21 | struct BlockchainSettings; 22 | 23 | class Blockchain { 24 | Value valueNetworkTotal; 25 | BlockTime timeInSecs; 26 | BlockRate secondsPerBlock; 27 | ValueRate transactionFeeRate; 28 | 29 | 30 | BlockHeight _maxHeightPub; 31 | std::vector> _blocksIndex; 32 | std::vector> _smallestBlocks; // cache smallest blocks of a given height 33 | std::vector> _blocks; 34 | 35 | std::vector> _oldBlocks; 36 | 37 | Block *blockByMinerAtHeight(BlockHeight height, const Miner &miner) const; 38 | 39 | public: 40 | Blockchain(BlockchainSettings blockchainSettings); 41 | 42 | std::unique_ptr createBlock(const Block *parent, const Miner *miner, Value value); 43 | void reset(BlockchainSettings blockchainSettings); 44 | 45 | void publishBlock(std::unique_ptr block); 46 | 47 | const std::vector getHeads() const; 48 | void printBlockchain() const; 49 | void printHeads() const; 50 | 51 | const Block &winningHead() const; 52 | 53 | BlockCount blocksOfHeight(BlockHeight height) const; 54 | 55 | const std::vector oldestBlocks(BlockHeight height) const; 56 | Block &oldest(BlockHeight height) const; 57 | Block &most(BlockHeight age) const; 58 | 59 | void advanceToTime(BlockTime time); 60 | 61 | inline BlockHeight getMaxHeightPub() const { 62 | return _maxHeightPub; 63 | } 64 | 65 | inline BlockTime getTime() const { 66 | return timeInSecs; 67 | } 68 | 69 | inline Value getTotalFees() const { 70 | return valueNetworkTotal; 71 | } 72 | 73 | BlockValue expectedBlockSize() const; 74 | TimeRate chanceToWin(HashRate hashRate) const; 75 | 76 | Value gap(BlockHeight i) const; 77 | Value rem(const Block &block) const; 78 | 79 | Block &most(BlockHeight age, const Miner &miner) const; 80 | Block &oldest(BlockHeight age, const Miner &miner) const; 81 | }; 82 | 83 | #endif /* blockchain_hpp */ 84 | -------------------------------------------------------------------------------- /BlockSim/blockchain_settings.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // blockchain_settings.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/26/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "blockchain_settings.hpp" 10 | -------------------------------------------------------------------------------- /BlockSim/blockchain_settings.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // blockchain_settings.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/26/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef blockchain_settings_hpp 10 | #define blockchain_settings_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | struct BlockchainSettings { 15 | BlockRate secondsPerBlock; 16 | ValueRate transactionFeeRate; 17 | BlockValue blockReward; 18 | BlockCount numberOfBlocks; 19 | }; 20 | 21 | #endif /* blockchain_settings_hpp */ 22 | -------------------------------------------------------------------------------- /BlockSim/clever_selfish_miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // clevel_selfish_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/6/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "clever_selfish_miner.hpp" 10 | 11 | #include "block.hpp" 12 | #include "blockchain.hpp" 13 | #include "logging.h" 14 | #include "minerParameters.h" 15 | #include "miner.hpp" 16 | #include "default_miner.hpp" 17 | #include "strategy.hpp" 18 | 19 | #include 20 | #include 21 | 22 | using std::placeholders::_1; 23 | using std::placeholders::_2; 24 | 25 | std::unique_ptr createCleverSelfishStrategy(bool noiseInTransactions, Value cutoff) { 26 | auto valueFunc = std::bind(defaultValueInMinedChild, _1, _2, noiseInTransactions); 27 | 28 | return std::make_unique("clever-selfish", selfishBlockToMineOn, valueFunc, std::make_unique(cutoff)); 29 | } 30 | 31 | CleverSelfishPublishingStyle::CleverSelfishPublishingStyle(Value cutoff_) : SelfishPublishingStyle(), cutoff(cutoff_) {} 32 | 33 | BlockHeight CleverSelfishPublishingStyle::heightToPublish(const Blockchain &blockchain, const Miner &me, std::vector> &unpublishedBlocks) const { 34 | assert(unpublishedBlocks.back()); 35 | if(unpublishedBlocks.back()->height == blockchain.getMaxHeightPub() + BlockHeight(1) && 36 | unpublishedBlocks.back()->value >= cutoff && 37 | unpublishedBlocks.size() == 1) { 38 | //finding a block. Normally hide (point of selfish mining) Might decide to normal mine if big block 39 | //(not worth the risk of using it to selfish mine) 40 | COMMENTARY("Miner " << me.params.name << " publishes selfish chain. Too large a block to selfishly mine." << std::endl); 41 | return unpublishedBlocks.back()->height; 42 | } else { 43 | return SelfishPublishingStyle::heightToPublish(blockchain, me, unpublishedBlocks); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /BlockSim/clever_selfish_miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // clevel_selfish_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/6/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef clevel_selfish_miner_hpp 10 | #define clevel_selfish_miner_hpp 11 | 12 | #include "selfish_miner.hpp" 13 | 14 | class CleverSelfishPublishingStyle : public SelfishPublishingStyle { 15 | private: 16 | const Value cutoff; 17 | BlockHeight heightToPublish(const Blockchain &blockchain, const Miner &me, std::vector> &unpublishedBlocks) const override; 18 | public: 19 | CleverSelfishPublishingStyle(Value cutoff); 20 | }; 21 | 22 | std::unique_ptr createCleverSelfishStrategy(bool noiseInTransactions, Value cutoff); 23 | 24 | #endif /* clevel_selfish_miner_hpp */ 25 | -------------------------------------------------------------------------------- /BlockSim/default_miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // default_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "default_miner.hpp" 10 | #include "block.hpp" 11 | #include "blockchain.hpp" 12 | #include "utils.hpp" 13 | #include "miner.hpp" 14 | #include "publishing_strategy.hpp" 15 | #include "strategy.hpp" 16 | 17 | #include 18 | #include 19 | 20 | using std::placeholders::_1; 21 | using std::placeholders::_2; 22 | 23 | std::unique_ptr createDefaultStrategy(bool atomic, bool noiseInTransactions) { 24 | ParentSelectorFunc mineFunc; 25 | 26 | if (atomic) { 27 | mineFunc = defaultBlockToMineOnAtomic; 28 | } else { 29 | mineFunc = defaultBlockToMineOnNonAtomic; 30 | } 31 | 32 | auto valueFunc = std::bind(defaultValueInMinedChild, _1, _2, noiseInTransactions); 33 | 34 | return std::make_unique("default-honest", mineFunc, valueFunc); 35 | } 36 | 37 | Block &defaultBlockToMineOnAtomic(const Miner &me, const Blockchain &chain) { 38 | return chain.oldest(chain.getMaxHeightPub(), me); 39 | } 40 | 41 | Block &defaultBlockToMineOnNonAtomic(const Miner &, const Blockchain &chain) { 42 | return chain.oldest(chain.getMaxHeightPub()); 43 | } 44 | 45 | Value defaultValueInMinedChild(const Blockchain &chain, const Block &mineHere, bool noiseInTransactions) { 46 | auto minVal = mineHere.nextBlockReward(); 47 | auto maxVal = chain.rem(mineHere) + mineHere.nextBlockReward(); 48 | //this represents some noise-- no noise, value would = valueMax 49 | //value = ((valueMax - valueMin)*((dis(gen)+.7)/1.7)) + valueMin; 50 | auto value = maxVal; 51 | if (noiseInTransactions) { 52 | value = valWithNoise(minVal, maxVal); 53 | } 54 | return value; 55 | } 56 | -------------------------------------------------------------------------------- /BlockSim/default_miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // default_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef default_miner_hpp 10 | #define default_miner_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | 16 | class Miner; 17 | class Block; 18 | class Blockchain; 19 | class Strategy; 20 | 21 | std::unique_ptr createDefaultStrategy(bool atomic, bool noiseInTransactions); 22 | 23 | Value defaultValueInMinedChild(const Blockchain &blockchain, const Block &mineHere, bool noiseInTransactions); 24 | 25 | Block &defaultBlockToMineOnAtomic(const Miner &me, const Blockchain &chain); 26 | Block &defaultBlockToMineOnNonAtomic(const Miner &me, const Blockchain &chain); 27 | 28 | #endif /* default_miner_hpp */ 29 | -------------------------------------------------------------------------------- /BlockSim/default_selfish_miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // default_selfish_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/6/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "default_selfish_miner.hpp" 10 | #include "block.hpp" 11 | #include "blockchain.hpp" 12 | #include "miner.hpp" 13 | #include "selfish_miner.hpp" 14 | #include "default_miner.hpp" 15 | #include "logging.h" 16 | #include "utils.hpp" 17 | #include "strategy.hpp" 18 | 19 | #include 20 | #include 21 | 22 | 23 | using std::placeholders::_1; 24 | using std::placeholders::_2; 25 | 26 | Block &blockToMineOn(const Miner &me, const Blockchain &blockchain, double gamma); 27 | 28 | std::unique_ptr createDefaultSelfishStrategy(bool noiseInTransactions, double gamma) { 29 | auto mineFunc = std::bind(blockToMineOn, _1, _2, gamma); 30 | auto valueFunc = std::bind(defaultValueInMinedChild, _1, _2, noiseInTransactions); 31 | 32 | return std::make_unique("default-selfish", mineFunc, valueFunc); 33 | } 34 | 35 | Block &blockToMineOn(const Miner &me, const Blockchain &chain, double gamma) { 36 | 37 | std::vector possiblities = chain.oldestBlocks(chain.getMaxHeightPub()); 38 | if (possiblities.size() == 1) { //no forking 39 | return *possiblities[0]; 40 | } 41 | else if (possiblities.size() == 2) { //fork between the selfish miner and the rest of the network 42 | //mineHere should already be set to the side of the fork not the selfish miner 43 | Block *selfishBlock = nullptr; 44 | Block *defaultBlock = nullptr; 45 | if (ownBlock(&me, possiblities[0])) { 46 | defaultBlock = possiblities[0]; 47 | selfishBlock = possiblities[1]; 48 | } else { 49 | defaultBlock = possiblities[1]; 50 | selfishBlock = possiblities[0]; 51 | } 52 | 53 | assert(ownBlock(&me, defaultBlock)); 54 | 55 | //with chance gamma, mine on the selfish miner's block, otherwise not 56 | if (selectRandomChance() < gamma) { 57 | return *selfishBlock; 58 | 59 | } else { 60 | COMMENTARY("Having to mine on selfish block due to gamma. "); 61 | return *defaultBlock; 62 | } 63 | } else { //lolwut 64 | ERROR("\n#####ERROR UNFORSEEN CIRCUMSTANCES IN LOGIC FOR SELFISH MINING SIM###\n\n" << std::endl); 65 | return *possiblities[0]; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /BlockSim/default_selfish_miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // default_selfish_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/6/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef default_selfish_miner_hpp 10 | #define default_selfish_miner_hpp 11 | 12 | #include 13 | 14 | class Strategy; 15 | 16 | std::unique_ptr createDefaultSelfishStrategy(bool noiseInTransactions, double gamma); 17 | 18 | #endif /* default_selfish_miner_hpp */ 19 | -------------------------------------------------------------------------------- /BlockSim/function_fork_miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // function_fork_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "function_fork_miner.hpp" 10 | #include "block.hpp" 11 | #include "blockchain.hpp" 12 | #include "miner.hpp" 13 | #include "publishing_strategy.hpp" 14 | #include "strategy.hpp" 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | using std::placeholders::_1; 24 | using std::placeholders::_2; 25 | 26 | Block &blockToMineOnNonAtomic(const Miner &, const Blockchain &chain, ForkFunc f); 27 | Block &blockToMineOnAtomic(const Miner &me, const Blockchain &chain, ForkFunc f); 28 | 29 | Value valCont(const Blockchain &chain, ForkFunc f, const Block &block); 30 | Value valUnder(const Blockchain &chain, ForkFunc f, const Block &block); 31 | 32 | std::unique_ptr createFunctionForkStrategy(bool atomic, ForkFunc f, std::string type) { 33 | ParentSelectorFunc mineFunc; 34 | 35 | if (atomic) { 36 | mineFunc = std::bind(blockToMineOnAtomic, _1, _2, f); 37 | } else { 38 | mineFunc = std::bind(blockToMineOnNonAtomic, _1, _2, f); 39 | } 40 | auto valueFunc = std::bind(functionForkValueInMinedChild, _1, _2, f); 41 | 42 | return std::make_unique("function-fork-" + type, mineFunc, valueFunc); 43 | } 44 | 45 | Block &blockToMineOnNonAtomic(const Miner &, const Blockchain &chain, ForkFunc f) { 46 | Block &contBlock = chain.most(chain.getMaxHeightPub()); 47 | if (chain.getMaxHeightPub() == BlockHeight(0)) { 48 | return contBlock; 49 | } 50 | Block &underBlock = chain.most(chain.getMaxHeightPub() - BlockHeight(1)); 51 | 52 | if (valCont(chain, f, contBlock) >= valUnder(chain, f, underBlock)) { 53 | return contBlock; 54 | } else { 55 | return underBlock; 56 | } 57 | } 58 | 59 | Block &blockToMineOnAtomic(const Miner &me, const Blockchain &chain, ForkFunc f) { 60 | Block &contBlock = chain.most(chain.getMaxHeightPub(), me); 61 | if (chain.getMaxHeightPub() == BlockHeight(0)) { 62 | return contBlock; 63 | } 64 | 65 | Block &underBlock = chain.most(chain.getMaxHeightPub() - BlockHeight(1), me); 66 | if (contBlock.minedBy(&me) || valCont(chain, f, contBlock) >= valUnder(chain, f, underBlock)) { 67 | return contBlock; 68 | } else { 69 | return underBlock; 70 | } 71 | } 72 | 73 | Value functionForkValueInMinedChild(const Blockchain &chain, const Block &block, ForkFunc f) { 74 | if (block.height == chain.getMaxHeightPub()) { 75 | return valCont(chain, f, block); 76 | } else { 77 | return valUnder(chain, f, block); 78 | } 79 | } 80 | 81 | Value valCont(const Blockchain &chain, ForkFunc f, const Block &contBlock) { 82 | return f(chain, chain.rem(contBlock)) + contBlock.nextBlockReward(); 83 | } 84 | 85 | Value valUnder(const Blockchain &chain, ForkFunc f, const Block &underBlock) { 86 | return std::min(f(chain, chain.rem(underBlock)), chain.gap(chain.getMaxHeightPub()) - UNDERCUT_VALUE) + underBlock.nextBlockReward(); 87 | } 88 | 89 | Value functionForkPercentage(const Blockchain &, Value maxVal, double funcCoeff) { 90 | double coeff = 1.0 / funcCoeff; 91 | double newValue = rawValue(maxVal) * coeff; 92 | return Value(static_cast(newValue)); 93 | } 94 | 95 | Value functionForkLambert(const Blockchain &blockchain, Value maxVal, double lambertCoeff) { 96 | //don't include B-- this is about the expected portion form tx fees 97 | auto expectedBlockSize = blockchain.expectedBlockSize(); 98 | auto expectedSizeRaw = rawValue(expectedBlockSize); 99 | auto blockRatio = valuePercentage(maxVal, Value(expectedBlockSize)); 100 | if (blockRatio <= lambertCoeff) { 101 | return maxVal; 102 | } else if (blockRatio < 2*lambertCoeff - std::log(lambertCoeff) - 1) { 103 | 104 | double argToLambertFunct0 = -lambertCoeff*std::exp(blockRatio-2*lambertCoeff); 105 | double lambertRes = gsl_sf_lambert_W0(argToLambertFunct0); 106 | 107 | double newValue = -expectedSizeRaw * lambertRes; 108 | return Value(static_cast(newValue)); 109 | } else { 110 | return Value(expectedBlockSize); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /BlockSim/function_fork_miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // function_fork_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef function_fork_miner_hpp 10 | #define function_fork_miner_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | #include 16 | 17 | class Strategy; 18 | class Blockchain; 19 | class Block; 20 | 21 | using ForkFunc = std::function; 22 | 23 | std::unique_ptr createFunctionForkStrategy(bool atomic, ForkFunc f, std::string type); 24 | 25 | Value functionForkValueInMinedChild(const Blockchain &blockchain, const Block &block, ForkFunc f); 26 | 27 | Value functionForkPercentage(const Blockchain &blockchain, Value maxVal, double funcCoeff); 28 | Value functionForkLambert(const Blockchain &blockchain, Value maxVal, double lambertCoeff); 29 | 30 | #endif /* function_fork_miner_hpp */ 31 | -------------------------------------------------------------------------------- /BlockSim/function_fork_selfish_miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // function_fork_selfish_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 11/4/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "function_fork_selfish_miner.hpp" 10 | #include "clever_selfish_miner.hpp" 11 | #include "strategy.hpp" 12 | #include "block.hpp" 13 | 14 | using std::placeholders::_1; 15 | using std::placeholders::_2; 16 | 17 | std::unique_ptr createFunctionForkSelfishStrategy(Value cutoff, ForkFunc func) { 18 | auto valueFunc = std::bind(functionForkValueInMinedChild, _1, _2, func); 19 | 20 | return std::make_unique("function-selfish", selfishBlockToMineOn, valueFunc, std::make_unique(cutoff)); 21 | } 22 | -------------------------------------------------------------------------------- /BlockSim/function_fork_selfish_miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // function_fork_selfish_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 11/4/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef function_fork_selfish_miner_hpp 10 | #define function_fork_selfish_miner_hpp 11 | 12 | #include "function_fork_miner.hpp" 13 | 14 | 15 | std::unique_ptr createFunctionForkSelfishStrategy(Value cutoff, ForkFunc func); 16 | 17 | #endif /* function_fork_selfish_miner_hpp */ 18 | -------------------------------------------------------------------------------- /BlockSim/game.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // game.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/6/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "game.hpp" 10 | #include "blockchain.hpp" 11 | #include "block.hpp" 12 | #include "miner.hpp" 13 | #include "logging.h" 14 | #include "minerGroup.hpp" 15 | #include "miner_result.hpp" 16 | #include "game_result.hpp" 17 | 18 | #include "minerStrategies.h" 19 | #include "strategy.hpp" 20 | 21 | #include 22 | #include 23 | 24 | GameResult runGame(MinerGroup &minerGroup, Blockchain &blockchain, GameSettings gameSettings) { 25 | 26 | GAMEINFO("Players:" << std::endl << minerGroup); 27 | 28 | //mining loop 29 | 30 | BlockTime totalSeconds = gameSettings.blockchainSettings.numberOfBlocks * gameSettings.blockchainSettings.secondsPerBlock; 31 | 32 | while (blockchain.getTime() < totalSeconds) { 33 | BlockTime nextTime = minerGroup.nextEventTime(blockchain); 34 | 35 | assert(blockchain.getTime() <= nextTime); 36 | 37 | blockchain.advanceToTime(nextTime); 38 | 39 | assert(blockchain.getTime() == nextTime); 40 | 41 | //steps through in second intervals 42 | //on each step each miner gets a turn 43 | COMMENTARY("Round " << blockchain.getTime() << " of the game..." << std::endl); 44 | 45 | minerGroup.nextMineRound(blockchain); 46 | 47 | minerGroup.nextBroadcastRound(blockchain); 48 | 49 | COMMENTARY("Publish phase:" << std::endl); 50 | 51 | minerGroup.nextPublishRound(blockchain); 52 | 53 | COMMENTARY("Round " << blockchain.getTime() << " over. Current blockchain:" << std::endl); 54 | COMMENTARYBLOCK ( 55 | blockchain.printBlockchain(); 56 | blockchain.printHeads(); 57 | ) 58 | } 59 | 60 | minerGroup.finalize(blockchain); 61 | 62 | std::vector minerResults; 63 | minerResults.resize(minerGroup.miners.size()); 64 | 65 | auto &winningBlock = blockchain.winningHead(); 66 | auto winningChain = winningBlock.getChain(); 67 | int parentCount = 0; 68 | Value totalValue(0); 69 | for (auto mined : winningChain) { 70 | if (mined->height == BlockHeight(0)) { 71 | break; 72 | } 73 | if (mined->parent->minedBy(mined->miner)) { 74 | parentCount++; 75 | } 76 | auto miner = mined->miner; 77 | size_t minerIndex = minerGroup.miners.size(); 78 | for (size_t ind = 0; ind < minerGroup.miners.size(); ind++) { 79 | if (minerGroup.miners[ind].get() == miner) { 80 | minerIndex = ind; 81 | break; 82 | } 83 | } 84 | 85 | minerResults[minerIndex].addBlock(mined); 86 | totalValue += mined->value; 87 | } 88 | 89 | // std::cout << parentCount << " block mined over parent" << std::endl; 90 | 91 | 92 | //calculate the score at the end 93 | BlockCount totalBlocks(0); 94 | BlockCount finalBlocks(0); 95 | 96 | for (size_t i = 0; i < minerGroup.miners.size(); i++) { 97 | const auto &miner = minerGroup.miners[i]; 98 | GAMEINFO(*miner << " earned:" << minerResults[i].totalProfit << " mined " << miner->getBlocksMinedTotal() <<" total, of which " << minerResults[i].blocksInWinningChain << " made it into the final chain" << std::endl); 99 | totalBlocks += miner->getBlocksMinedTotal(); 100 | finalBlocks += minerResults[i].blocksInWinningChain; 101 | } 102 | 103 | Value moneyLeftAtEnd = blockchain.rem(*winningChain[0]); 104 | 105 | GameResult result(minerResults, totalBlocks, finalBlocks, moneyLeftAtEnd, totalValue); 106 | 107 | assert(winningBlock.valueInChain == totalValue); 108 | for (size_t i = 0; i < minerGroup.miners.size(); i++) { 109 | assert(minerResults[i].totalProfit <= totalValue); 110 | } 111 | 112 | 113 | GAMEINFO("Total blocks mined:" << totalBlocks << " with " << finalBlocks << " making it into the final chain" << std::endl); 114 | return result; 115 | } 116 | -------------------------------------------------------------------------------- /BlockSim/game.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // game.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/6/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef game_hpp 10 | #define game_hpp 11 | 12 | #include "blockchain_settings.hpp" 13 | #include "typeDefs.hpp" 14 | 15 | class Blockchain; 16 | struct GameResult; 17 | class MinerGroup; 18 | struct BlockchainSettings; 19 | 20 | struct GameSettings { 21 | BlockchainSettings blockchainSettings; 22 | }; 23 | 24 | GameResult runGame(MinerGroup &minerGroup, Blockchain &blockchain, GameSettings gameSettings); 25 | 26 | #endif /* game_hpp */ 27 | -------------------------------------------------------------------------------- /BlockSim/game_result.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // game_result.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 7/1/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "game_result.hpp" 10 | 11 | #include "miner_result.hpp" 12 | 13 | GameResult::GameResult(std::vector minerResults_, BlockCount totalBlocksMined_, BlockCount blocksInLongestChain_, Value moneyLeftAtEnd_, Value moneyInLongestChain_) : minerResults(minerResults_), totalBlocksMined(totalBlocksMined_), blocksInLongestChain(blocksInLongestChain_), moneyLeftAtEnd(moneyLeftAtEnd_), moneyInLongestChain(moneyInLongestChain_) {} 14 | -------------------------------------------------------------------------------- /BlockSim/game_result.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // game_result.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 7/1/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef game_result_hpp 10 | #define game_result_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | 16 | struct MinerResult; 17 | class Miner; 18 | 19 | struct GameResult { 20 | std::vector minerResults; 21 | BlockCount totalBlocksMined; 22 | BlockCount blocksInLongestChain; 23 | Value moneyLeftAtEnd; 24 | Value moneyInLongestChain; 25 | 26 | GameResult(std::vector minerResults, BlockCount totalBlocksMined, BlockCount blocksInLongestChain, Value moneyLeftAtEnd, Value moneyInLongestChain); 27 | }; 28 | 29 | #endif /* game_result_hpp */ 30 | -------------------------------------------------------------------------------- /BlockSim/gap_miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // gap_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "gap_miner.hpp" 10 | 11 | #include "blockchain.hpp" 12 | #include "block.hpp" 13 | #include "logging.h" 14 | #include "miner.hpp" 15 | #include "default_miner.hpp" 16 | #include "publishing_strategy.hpp" 17 | #include "strategy.hpp" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | using std::placeholders::_1; 24 | using std::placeholders::_2; 25 | 26 | bool shouldMine(const Miner &me, const Blockchain &blockchain, const Block &block); 27 | 28 | std::unique_ptr createGapStrategy(bool atomic, bool noiseInTransactions) { 29 | ParentSelectorFunc mineFunc; 30 | if (atomic) { 31 | mineFunc = defaultBlockToMineOnAtomic; 32 | } else { 33 | mineFunc = defaultBlockToMineOnNonAtomic; 34 | } 35 | 36 | auto valueFunc = std::bind(defaultValueInMinedChild, _1, _2, noiseInTransactions); 37 | 38 | return std::make_unique("gap", mineFunc, valueFunc, shouldMine); 39 | } 40 | 41 | bool shouldMine(const Miner &me, const Blockchain &blockchain, const Block &block) { 42 | auto expectedValue = blockchain.chanceToWin(me.params.hashRate) * block.value; //chance to win * value won 43 | auto shouldMine = me.params.costPerSecond < expectedValue || ownBlock(&me, block.parent); 44 | if (!shouldMine) { 45 | COMMENTARY("\n Miner " << me.params.name << " declines to mine. (cost:" << me.params.costPerSecond); 46 | COMMENTARY(" expected payout:" << expectedValue << ")"); 47 | } 48 | return shouldMine; 49 | } 50 | -------------------------------------------------------------------------------- /BlockSim/gap_miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // gap_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef gap_miner_hpp 10 | #define gap_miner_hpp 11 | 12 | #include 13 | 14 | class Strategy; 15 | 16 | std::unique_ptr createGapStrategy(bool atomic, bool noiseInTransactions); 17 | 18 | #endif /* gap_miner_hpp */ 19 | -------------------------------------------------------------------------------- /BlockSim/lazy_fork_miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // lazy_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "lazy_fork_miner.hpp" 10 | 11 | #include "block.hpp" 12 | #include "blockchain.hpp" 13 | #include "miner.hpp" 14 | #include "default_miner.hpp" 15 | #include "publishing_strategy.hpp" 16 | #include "strategy.hpp" 17 | 18 | #include 19 | 20 | using std::placeholders::_1; 21 | using std::placeholders::_2; 22 | 23 | Value lazyValueInMinedChild(const Blockchain &blockchain, const Block &mineHere); 24 | Block &lazyBlockToMineOnAtomic(const Miner &me, const Blockchain &chain); 25 | Block &lazyBlockToMineOnNonAtomic(const Miner &me, const Blockchain &chain); 26 | 27 | std::unique_ptr createLazyForkStrategy(bool atomic) { 28 | 29 | ParentSelectorFunc mineFunc; 30 | 31 | if (atomic) { 32 | mineFunc = lazyBlockToMineOnAtomic; 33 | } else { 34 | mineFunc = lazyBlockToMineOnNonAtomic; 35 | } 36 | auto valueFunc = lazyValueInMinedChild; 37 | 38 | return std::make_unique("lazy-fork", mineFunc, valueFunc); 39 | } 40 | 41 | Block &lazyBlockToMineOnAtomic(const Miner &me, const Blockchain &chain) { 42 | if (chain.getMaxHeightPub() == BlockHeight(0)) { 43 | return chain.most(chain.getMaxHeightPub(), me); 44 | } 45 | 46 | if (chain.rem(chain.most(chain.getMaxHeightPub(), me)) >= chain.gap(chain.getMaxHeightPub())) { 47 | return chain.most(chain.getMaxHeightPub(), me); 48 | } else { 49 | return chain.most(chain.getMaxHeightPub() - BlockHeight(1), me); 50 | } 51 | } 52 | 53 | Block &lazyBlockToMineOnNonAtomic(const Miner &, const Blockchain &chain) { 54 | if (chain.getMaxHeightPub() == BlockHeight(0)) { 55 | return chain.most(chain.getMaxHeightPub()); 56 | } 57 | 58 | if (chain.rem(chain.most(chain.getMaxHeightPub())) >= chain.gap(chain.getMaxHeightPub())) { 59 | return chain.most(chain.getMaxHeightPub()); 60 | } else { 61 | return chain.most(chain.getMaxHeightPub() - BlockHeight(1)); 62 | } 63 | } 64 | 65 | Value lazyValueInMinedChild(const Blockchain &chain, const Block &mineHere) { 66 | return chain.rem(mineHere) / Value(2.0) + mineHere.nextBlockReward(); 67 | } 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /BlockSim/lazy_fork_miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // undercut_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef undercut_miner_hpp 10 | #define undercut_miner_hpp 11 | 12 | #include 13 | 14 | class Strategy; 15 | 16 | std::unique_ptr createLazyForkStrategy(bool atomic); 17 | 18 | #endif /* undercut_miner_hpp */ 19 | -------------------------------------------------------------------------------- /BlockSim/logging.h: -------------------------------------------------------------------------------- 1 | // 2 | // simulationState.h 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/6/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef logging_h 10 | #define logging_h 11 | 12 | 13 | 14 | #define _ERROROUTPUT 1 15 | //#define _GAMEINFO 1 16 | //#define _COMMENTARY 1 17 | 18 | #ifdef _GAMEINFO 19 | #define GAMEINFO(arg) std::cout << arg 20 | #define GAMEINFOBLOCK(arg) arg 21 | #else 22 | #define GAMEINFO(arg) 23 | #define GAMEINFOBLOCK(arg) 24 | #endif 25 | 26 | #ifdef _COMMENTARY 27 | #define COMMENTARY_ON true 28 | #define COMMENTARY(arg) std::cout << arg 29 | #define COMMENTARYBLOCK(arg) arg 30 | #else 31 | #define COMMENTARY_ON false 32 | #define COMMENTARY(arg) 33 | #define COMMENTARYBLOCK(arg) 34 | #endif 35 | 36 | #ifdef _ERROROUTPUT 37 | #define ERROR(arg) std::cout << arg 38 | #else 39 | #define ERROR(arg) 40 | #endif 41 | 42 | 43 | #endif /* logging_h */ 44 | -------------------------------------------------------------------------------- /BlockSim/miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "miner.hpp" 10 | #include "block.hpp" 11 | #include "blockchain.hpp" 12 | #include "logging.h" 13 | #include "minerParameters.h" 14 | #include "mining_style.hpp" 15 | #include "simple_mining_style.hpp" 16 | #include "picky_mining_style.hpp" 17 | #include "publishing_strategy.hpp" 18 | #include "simple_publisher.hpp" 19 | #include "utils.hpp" 20 | #include "strategy.hpp" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | Miner::Miner(MinerParameters params_, const Strategy &strategy_) : strategy(strategy_), params(params_) { } 32 | 33 | Miner::~Miner() = default; 34 | 35 | void Miner::reset(const Blockchain &blockchain) { 36 | blocksMinedTotal = BlockCount(0); 37 | unbroadcastBlocks.clear(); 38 | _nextPublishTime = BlockTime(std::numeric_limits::max()); 39 | _lastCostUpdate = BlockTime(0); 40 | _nextMiningTime = strategy.get().miningStyle->nextMiningTime(blockchain, *this); 41 | totalMiningCost = 0; 42 | waitingForBroadcast = false; 43 | } 44 | 45 | void Miner::changeStrategy(const Strategy &strategy_, const Blockchain &chain) { 46 | totalMiningCost += strategy.get().miningStyle->resetMiningCost(*this, chain, _lastCostUpdate); 47 | strategy = strategy_; 48 | _lastCostUpdate = chain.getTime(); 49 | _nextMiningTime = strategy.get().miningStyle->nextMiningTime(chain, *this); 50 | } 51 | 52 | void Miner::finalize(Blockchain &blockchain) { 53 | totalMiningCost += strategy.get().miningStyle->resetMiningCost(*this, blockchain, _lastCostUpdate); 54 | _lastCostUpdate = blockchain.getTime(); 55 | 56 | for (auto &block : unbroadcastBlocks) { 57 | blockchain.publishBlock(std::move(block)); 58 | } 59 | } 60 | 61 | std::unique_ptr Miner::miningPhase(Blockchain &chain) { 62 | assert(chain.getTime() == nextMiningTime()); 63 | COMMENTARY("\tMiner " << params.name << "'s turn. " << strategy.get().name << ". "); 64 | 65 | auto miningPair = strategy.get().miningStyle->attemptToMine(chain, this, _lastCostUpdate); 66 | _lastCostUpdate = chain.getTime(); 67 | auto &block = miningPair.first; 68 | 69 | totalMiningCost += miningPair.second; 70 | 71 | assert(nextMiningTime() == chain.getTime()); 72 | 73 | COMMENTARYBLOCK ( 74 | if (block) { 75 | COMMENTARY("\n### Miner " << params.name << " found a block: " << *block << " on top of " << *block->parent << " with value " << block->value << " ###\n"); 76 | } 77 | ) 78 | 79 | _nextMiningTime = strategy.get().miningStyle->nextMiningTime(chain, *this); 80 | 81 | if (block) { 82 | blocksMinedTotal++; 83 | if (strategy.get().publisher->withholdsBlocks()) { 84 | waitingForBroadcast = true; 85 | unbroadcastBlocks.push_back(std::move(block)); 86 | } else { 87 | block->broadcast(chain.getTime() + params.networkDelay); 88 | return std::move(block); 89 | } 90 | } 91 | 92 | return nullptr; 93 | } 94 | 95 | std::vector> Miner::broadcastPhase(const Blockchain &chain) { 96 | assert(unbroadcastBlocks.size() > 0); 97 | std::vector> blocks; 98 | auto &publisher = strategy.get().publisher; 99 | auto blocksToPublish = publisher->publishBlocks(chain, *this, unbroadcastBlocks); 100 | waitingForBroadcast = !unbroadcastBlocks.empty(); 101 | for (auto &block : blocksToPublish) { 102 | block->broadcast(chain.getTime() + params.networkDelay); 103 | COMMENTARY("Miner " << params.name << " publishes " << *block << "\n"); 104 | } 105 | return blocksToPublish; 106 | } 107 | 108 | Block *Miner::newestUnpublishedBlock() const { 109 | if (unbroadcastBlocks.empty()) { 110 | return nullptr; 111 | } 112 | 113 | Block *block = unbroadcastBlocks[0].get(); 114 | for (auto &unpublishedBlock : unbroadcastBlocks) { 115 | if (unpublishedBlock->height > block->height) { 116 | block = unpublishedBlock.get(); 117 | } 118 | } 119 | return block; 120 | } 121 | 122 | void Miner::updateNextPublishTime(BlockTime newTime, const Blockchain &chain) { 123 | assert(newTime >= chain.getTime()); 124 | _nextPublishTime = newTime; 125 | } 126 | 127 | std::ostream& operator<<(std::ostream& os, const Miner& miner) { 128 | miner.print(os); 129 | return os; 130 | } 131 | 132 | void Miner::print(std::ostream& os) const { 133 | os << "[" << strategy.get().name << "] miner " << params.name; 134 | } 135 | 136 | bool ownBlock(const Miner *miner, const Block *block) { 137 | return block->minedBy(miner); 138 | } 139 | 140 | bool Miner::publishesNextRound() const { 141 | return unbroadcastBlocks.size() > 0; 142 | } 143 | -------------------------------------------------------------------------------- /BlockSim/miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef miner_hpp 10 | #define miner_hpp 11 | 12 | #include "minerParameters.h" 13 | 14 | #include 15 | #include 16 | 17 | class Block; 18 | class Blockchain; 19 | class Strategy; 20 | 21 | class Miner { 22 | 23 | private: 24 | BlockCount blocksMinedTotal; 25 | std::vector> unbroadcastBlocks; 26 | std::reference_wrapper strategy; 27 | 28 | Value totalMiningCost; 29 | BlockTime _lastCostUpdate; 30 | BlockTime _nextMiningTime; 31 | BlockTime _nextPublishTime; 32 | bool waitingForBroadcast; 33 | 34 | bool findsBlock(const Blockchain &blockchain); 35 | void updateNextPublishTime(BlockTime newTime, const Blockchain &chain); 36 | 37 | protected: 38 | virtual void print(std::ostream& where) const; 39 | public: 40 | const MinerParameters params; 41 | 42 | Miner(MinerParameters parameters, const Strategy &strategy); 43 | virtual ~Miner(); 44 | 45 | void changeStrategy(const Strategy &strategy, const Blockchain &blockchain); 46 | 47 | Block *newestUnpublishedBlock() const; 48 | 49 | void finalize(Blockchain &blockchain); 50 | void reset(const Blockchain &blockchain); 51 | bool wantsToBroadcast() const { return waitingForBroadcast; } 52 | 53 | inline BlockCount getBlocksMinedTotal() const { return blocksMinedTotal; } 54 | BlockTime nextMiningTime() const { return _nextMiningTime; } 55 | 56 | bool publishesNextRound() const; 57 | 58 | std::unique_ptr miningPhase(Blockchain &blockchain); 59 | std::vector> broadcastPhase(const Blockchain &chain); 60 | 61 | friend std::ostream& operator<<(std::ostream& os, const Miner& miner); 62 | }; 63 | 64 | bool ownBlock(const Miner *miner, const Block *block); 65 | 66 | 67 | #endif /* miner_hpp */ 68 | -------------------------------------------------------------------------------- /BlockSim/minerGroup.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // minerGroup.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/9/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "minerGroup.hpp" 10 | 11 | #include "miner.hpp" 12 | #include "blockchain.hpp" 13 | #include "block.hpp" 14 | #include "logging.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | constexpr auto maxTime = BlockTime(std::numeric_limits::max()); 21 | 22 | bool miningSort(const Miner *miner1, const Miner *miner2); 23 | bool miningSort(const Miner *miner1, const Miner *miner2) { 24 | 25 | auto miner1Time = miner1->nextMiningTime(); 26 | auto miner2Time = miner2->nextMiningTime(); 27 | return miner1Time > miner2Time; 28 | } 29 | 30 | bool broadcastSort(const std::unique_ptr &block1, const std::unique_ptr &block2); 31 | bool broadcastSort(const std::unique_ptr &block1, const std::unique_ptr &block2) { 32 | return block1->getTimeBroadcast() > block2->getTimeBroadcast(); 33 | } 34 | 35 | 36 | MinerGroup::MinerGroup(std::vector> miners_) : modifiedSinceLastPublish(false), miners(std::move(miners_)) { 37 | for (auto &miner : miners) { 38 | miningQueue.push_back(miner.get()); 39 | sleepingPublishers.insert(miner.get()); 40 | } 41 | } 42 | 43 | void MinerGroup::reset(const Blockchain &chain) { 44 | for (auto &miner : miners) { 45 | miner->reset(chain); 46 | } 47 | broadcastQueue.clear(); 48 | 49 | std::make_heap(begin(miningQueue), end(miningQueue), miningSort); 50 | } 51 | 52 | void MinerGroup::finalize(Blockchain &chain) { 53 | for (auto &miner : miners) { 54 | miner->finalize(chain); 55 | } 56 | } 57 | 58 | BlockTime MinerGroup::nextBroadcastTime() const { 59 | if (!broadcastQueue.empty()) { 60 | return broadcastQueue.front()->getTimeBroadcast(); 61 | } else { 62 | return maxTime; 63 | } 64 | } 65 | 66 | BlockTime MinerGroup::nextEventTime(const Blockchain &chain) { 67 | 68 | auto nextMining = miningQueue.front()->nextMiningTime(); 69 | 70 | if (modifiedSinceLastPublish) { 71 | return chain.getTime() + BlockTime(1); 72 | } else { 73 | return std::min(nextBroadcastTime(), nextMining); 74 | } 75 | } 76 | 77 | void MinerGroup::nextMineRound(Blockchain &blockchain) { 78 | assert(miningQueue.front()->nextMiningTime() >= blockchain.getTime()); 79 | 80 | while (miningQueue.front()->nextMiningTime() == blockchain.getTime()) { 81 | std::pop_heap(begin(miningQueue), end(miningQueue), miningSort); 82 | Miner *miner = miningQueue.back(); 83 | auto wantedBroadcast = miner->wantsToBroadcast(); 84 | auto block = miner->miningPhase(blockchain); 85 | if (block) { 86 | COMMENTARY("Miner " << miner->params.name << " publishes " << *block << "\n"); 87 | broadcastQueue.push_back(std::move(block)); 88 | std::push_heap(begin(broadcastQueue), end(broadcastQueue), broadcastSort); 89 | } 90 | if (miner->wantsToBroadcast() && !wantedBroadcast) { 91 | sleepingPublishers.erase(miner); 92 | activePublishers.insert(miner); 93 | } 94 | 95 | std::push_heap(begin(miningQueue), end(miningQueue), miningSort); 96 | } 97 | modifiedSinceLastPublish = true; 98 | } 99 | 100 | void MinerGroup::nextBroadcastRound(Blockchain &blockchain) { 101 | while (!broadcastQueue.empty() && broadcastQueue.front()->getTimeBroadcast() == blockchain.getTime()) { 102 | std::pop_heap(begin(broadcastQueue), end(broadcastQueue), broadcastSort); 103 | blockchain.publishBlock(std::move(broadcastQueue.back())); 104 | broadcastQueue.pop_back(); 105 | } 106 | } 107 | 108 | void MinerGroup::nextPublishRound(Blockchain &blockchain) { 109 | if (modifiedSinceLastPublish) { 110 | bool wasModified = true; 111 | while (wasModified) { 112 | wasModified = false; 113 | for (auto it = begin(activePublishers); it != end(activePublishers); ) { 114 | auto blocksToBroadcast = (*it)->broadcastPhase(blockchain); 115 | for (auto &block : blocksToBroadcast) { 116 | broadcastQueue.push_back(std::move(block)); 117 | std::push_heap(begin(broadcastQueue), end(broadcastQueue), broadcastSort); 118 | wasModified = true; 119 | } 120 | if (!(*it)->wantsToBroadcast()) { 121 | sleepingPublishers.insert(*it); 122 | it = activePublishers.erase(it); 123 | } else { 124 | ++it; 125 | } 126 | } 127 | nextBroadcastRound(blockchain); 128 | } 129 | } 130 | 131 | modifiedSinceLastPublish = false; 132 | } 133 | 134 | std::ostream& operator<<(std::ostream& os, const MinerGroup& minerGroup) { 135 | for (const auto &miner : minerGroup.miners) { 136 | os << *miner << std::endl; 137 | } 138 | return os; 139 | } 140 | 141 | void MinerGroup::resetOrder() { 142 | std::make_heap(begin(miningQueue), end(miningQueue), miningSort); 143 | activePublishers.clear(); 144 | sleepingPublishers.clear(); 145 | for (auto &miner : miners) { 146 | if (miner->wantsToBroadcast()) { 147 | activePublishers.insert(miner.get()); 148 | } else { 149 | sleepingPublishers.insert(miner.get()); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /BlockSim/minerGroup.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // minerGroup.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/9/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef minerGroup_hpp 10 | #define minerGroup_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | class Miner; 20 | class Blockchain; 21 | class Block; 22 | 23 | class MinerGroup { 24 | private: 25 | bool modifiedSinceLastPublish; 26 | BlockTime nextBroadcastTime() const; 27 | public: 28 | MinerGroup(std::vector> miners); 29 | 30 | void finalize(Blockchain &chain); 31 | void reset(const Blockchain &chain); 32 | 33 | const std::vector> miners; 34 | 35 | std::vector miningQueue; 36 | std::vector> broadcastQueue; 37 | 38 | std::unordered_set activePublishers; 39 | std::unordered_set sleepingPublishers; 40 | 41 | friend std::ostream& operator<<(std::ostream& os, const MinerGroup& minerGroup); 42 | 43 | BlockTime nextEventTime(const Blockchain &chain); 44 | void nextMineRound(Blockchain &blockchain); 45 | void nextPublishRound(Blockchain &blockchain); 46 | void nextBroadcastRound(Blockchain &blockchain); 47 | 48 | void resetOrder(); 49 | }; 50 | 51 | #endif /* MinerGroup_hpp */ 52 | -------------------------------------------------------------------------------- /BlockSim/minerParameters.h: -------------------------------------------------------------------------------- 1 | // 2 | // minerParameters.h 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/7/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef minerParameters_h 10 | #define minerParameters_h 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | 16 | struct MinerParameters { 17 | const unsigned int number; 18 | const std::string name; 19 | const HashRate hashRate; 20 | const BlockTime networkDelay; 21 | const ValueRate costPerSecond; 22 | }; 23 | 24 | #endif /* minerParameters_h */ 25 | -------------------------------------------------------------------------------- /BlockSim/minerStrategies.h: -------------------------------------------------------------------------------- 1 | // 2 | // minerStrategies.h 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef minerStrategies_h 10 | #define minerStrategies_h 11 | 12 | #include "default_miner.hpp" 13 | #include "petty_miner.hpp" 14 | #include "function_fork_miner.hpp" 15 | #include "selfish_miner.hpp" 16 | #include "clever_selfish_miner.hpp" 17 | #include "lazy_fork_miner.hpp" 18 | #include "gap_miner.hpp" 19 | #include "default_selfish_miner.hpp" 20 | #include "function_fork_selfish_miner.hpp" 21 | 22 | #endif /* minerStrategies_h */ 23 | -------------------------------------------------------------------------------- /BlockSim/miner_result.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // miner_result.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/18/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "miner_result.hpp" 10 | 11 | #include "block.hpp" 12 | 13 | MinerResult::MinerResult() : blocksInWinningChain(BlockCount(0)), totalProfit(Value(0)) {} 14 | 15 | void MinerResult::addBlock(const Block *block) { 16 | totalProfit += block->value; 17 | blocksInWinningChain++; 18 | } 19 | -------------------------------------------------------------------------------- /BlockSim/miner_result.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // miner_result.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/18/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef miner_result_hpp 10 | #define miner_result_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | class Block; 15 | 16 | struct MinerResult { 17 | BlockCount blocksInWinningChain; 18 | Value totalProfit; 19 | 20 | MinerResult(); 21 | void addBlock(const Block *block); 22 | }; 23 | 24 | #endif /* miner_result_hpp */ 25 | -------------------------------------------------------------------------------- /BlockSim/mining_style.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // mining.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "mining_style.hpp" 10 | 11 | #include "blockchain.hpp" 12 | #include "miner.hpp" 13 | #include "block.hpp" 14 | 15 | #include 16 | 17 | MiningStyle::MiningStyle(ParentSelectorFunc parentSelectorFunc_, BlockValueFunc blockValueFunc_) : 18 | parentSelectorFunc(parentSelectorFunc_), blockValueFunc(blockValueFunc_) {} 19 | 20 | MiningStyle::~MiningStyle() = default; 21 | 22 | std::unique_ptr MiningStyle::createBlock(Blockchain &blockchain, const Miner &miner) { 23 | auto &parent = parentSelectorFunc(miner, blockchain); 24 | auto value = blockValueFunc(blockchain, parent); 25 | 26 | assert(value >= parent.nextBlockReward()); 27 | assert(value <= parent.nextBlockReward() + blockchain.rem(parent)); 28 | 29 | auto newBlock = blockchain.createBlock(&parent, &miner, value); 30 | 31 | return newBlock; 32 | } 33 | -------------------------------------------------------------------------------- /BlockSim/mining_style.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // mining.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef mining_hpp 10 | #define mining_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | #include 16 | 17 | class Blockchain; 18 | class Miner; 19 | class Block; 20 | 21 | using ParentSelectorFunc = std::function; 22 | using BlockValueFunc = std::function; 23 | 24 | class MiningStyle { 25 | 26 | private: 27 | const ParentSelectorFunc parentSelectorFunc; 28 | const BlockValueFunc blockValueFunc; 29 | 30 | protected: 31 | MiningStyle(ParentSelectorFunc parentSelectorFunc, BlockValueFunc blockValueFunc); 32 | 33 | std::unique_ptr createBlock(Blockchain &blockchain, const Miner &me); 34 | 35 | public: 36 | 37 | virtual ~MiningStyle(); 38 | 39 | virtual std::pair, Value> attemptToMine(Blockchain &blockchain, Miner *miner, BlockTime lastTimePaid) = 0; 40 | virtual BlockTime nextMiningTime(const Blockchain &chain, const Miner &miner) const = 0; 41 | virtual Value resetMiningCost(const Miner &miner, const Blockchain &chain, BlockTime lastTimePaid) = 0; 42 | }; 43 | 44 | #endif /* mining_hpp */ 45 | -------------------------------------------------------------------------------- /BlockSim/petty_miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // petty_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "petty_miner.hpp" 10 | #include "block.hpp" 11 | #include "blockchain.hpp" 12 | #include "miner.hpp" 13 | #include "default_miner.hpp" 14 | #include "publishing_strategy.hpp" 15 | #include "strategy.hpp" 16 | 17 | #include 18 | 19 | using std::placeholders::_1; 20 | using std::placeholders::_2; 21 | 22 | Block &blockToMineOnAtomic(const Miner &me, const Blockchain &chain); 23 | Block &blockToMineOnNonAtomic(const Miner &me, const Blockchain &chain); 24 | 25 | std::unique_ptr createPettyStrategy(bool atomic, bool noiseInTransactions) { 26 | 27 | ParentSelectorFunc mineFunc; 28 | 29 | if (atomic) { 30 | mineFunc = blockToMineOnAtomic; 31 | } else { 32 | mineFunc = blockToMineOnNonAtomic; 33 | } 34 | auto valueFunc = std::bind(defaultValueInMinedChild, _1, _2, noiseInTransactions); 35 | 36 | return std::make_unique("petty-honest", mineFunc, valueFunc); 37 | } 38 | 39 | Block &blockToMineOnAtomic(const Miner &me, const Blockchain &chain) { 40 | return chain.most(chain.getMaxHeightPub(), me); 41 | } 42 | 43 | Block &blockToMineOnNonAtomic(const Miner &, const Blockchain &chain) { 44 | return chain.most(chain.getMaxHeightPub()); 45 | } 46 | -------------------------------------------------------------------------------- /BlockSim/petty_miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // petty_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef petty_miner_hpp 10 | #define petty_miner_hpp 11 | 12 | #include 13 | 14 | class Strategy; 15 | 16 | std::unique_ptr createPettyStrategy(bool atomic, bool noiseInTransactions); 17 | 18 | #endif /* petty_miner_hpp */ 19 | -------------------------------------------------------------------------------- /BlockSim/picky_mining_style.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // picky_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/12/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "picky_mining_style.hpp" 10 | #include "utils.hpp" 11 | #include "blockchain.hpp" 12 | #include "block.hpp" 13 | #include "miner.hpp" 14 | 15 | #include 16 | #include 17 | 18 | PickyMiningStyle::PickyMiningStyle(ParentSelectorFunc parentSelectorFunc_, BlockValueFunc blockValueFunc_, ShouldMineFunc shouldMineFunc_) : MiningStyle(parentSelectorFunc_, blockValueFunc_), shouldMineFunc(shouldMineFunc_) {} 19 | 20 | BlockTime PickyMiningStyle::nextMiningTime(const Blockchain &chain, const Miner &) const { 21 | return chain.getTime() + BlockTime(1); 22 | } 23 | 24 | std::pair, Value> PickyMiningStyle::attemptToMine(Blockchain &blockchain, Miner *miner, BlockTime) { 25 | auto block = createBlock(blockchain, *miner); 26 | if (shouldMineFunc(*miner, blockchain, *block)) { 27 | Value cost = miner->params.costPerSecond * BlockTime(1); 28 | if (TimeRate(selectRandomChance()) < blockchain.chanceToWin(miner->params.hashRate)) { 29 | return std::make_pair(std::move(block), cost); 30 | } else { 31 | return std::make_pair(nullptr, cost); 32 | } 33 | } 34 | 35 | return std::make_pair(nullptr, Value(0)); 36 | } 37 | 38 | Value PickyMiningStyle::resetMiningCost(const Miner &, const Blockchain &, BlockTime) { 39 | return Value(0); 40 | } 41 | -------------------------------------------------------------------------------- /BlockSim/picky_mining_style.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // picky_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/12/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef picky_miner_hpp 10 | #define picky_miner_hpp 11 | 12 | #include "mining_style.hpp" 13 | 14 | using ShouldMineFunc = std::function; 15 | 16 | class PickyMiningStyle : public MiningStyle { 17 | 18 | private: 19 | const ShouldMineFunc shouldMineFunc; 20 | 21 | BlockTime nextMiningTime(const Blockchain &chain, const Miner &miner) const override; 22 | std::pair, Value> attemptToMine(Blockchain &blockchain, Miner *miner, BlockTime lastTimePaid) override; 23 | Value resetMiningCost(const Miner &miner, const Blockchain &chain, BlockTime lastTimePaid) override; 24 | public: 25 | PickyMiningStyle(ParentSelectorFunc parentSelectorFunc, BlockValueFunc blockValueFunc, ShouldMineFunc shouldMineFunc); 26 | }; 27 | 28 | #endif /* picky_miner_hpp */ 29 | -------------------------------------------------------------------------------- /BlockSim/publishing_strategy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // publisher.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "publishing_strategy.hpp" 10 | 11 | #include "blockchain.hpp" 12 | #include "miner.hpp" 13 | #include "block.hpp" 14 | 15 | #include 16 | 17 | PublishingStrategy::~PublishingStrategy() = default; 18 | -------------------------------------------------------------------------------- /BlockSim/publishing_strategy.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // publisher.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef publisher_hpp 10 | #define publisher_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | #include 16 | 17 | class Block; 18 | class Blockchain; 19 | class Miner; 20 | 21 | class PublishingStrategy { 22 | public: 23 | virtual std::vector> publishBlocks(const Blockchain &blockchain, const Miner &me, std::vector> &unpublishedBlocks) = 0; 24 | virtual ~PublishingStrategy(); 25 | 26 | virtual bool withholdsBlocks() const = 0; 27 | }; 28 | 29 | #endif /* publisher_hpp */ 30 | -------------------------------------------------------------------------------- /BlockSim/selfish_miner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // selfish_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "selfish_miner.hpp" 10 | #include "block.hpp" 11 | #include "blockchain.hpp" 12 | #include "logging.h" 13 | #include "miner.hpp" 14 | #include "default_miner.hpp" 15 | #include "strategy.hpp" 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | using std::placeholders::_1; 22 | using std::placeholders::_2; 23 | 24 | std::unique_ptr createSelfishStrategy(bool noiseInTransactions) { 25 | auto valueFunc = std::bind(defaultValueInMinedChild, _1, _2, noiseInTransactions); 26 | 27 | return std::make_unique("selfish", selfishBlockToMineOn, valueFunc, std::make_unique()); 28 | } 29 | 30 | Block &selfishBlockToMineOn(const Miner &me, const Blockchain &chain) { 31 | Block *newest = me.newestUnpublishedBlock(); 32 | if (newest && newest->height >= chain.getMaxHeightPub()) { 33 | return *newest; 34 | } else { 35 | return chain.oldest(chain.getMaxHeightPub(), me); 36 | } 37 | } 38 | 39 | std::vector> SelfishPublishingStyle::publishBlocks(const Blockchain &chain, const Miner &me, std::vector> &unpublishedBlocks) { 40 | assert(!unpublishedBlocks.empty()); 41 | BlockHeight height = heightToPublish(chain, me, unpublishedBlocks); 42 | 43 | std::vector heights; 44 | heights.resize(unpublishedBlocks.size()); 45 | std::transform(begin(unpublishedBlocks), end(unpublishedBlocks), heights.begin(), [&](auto &block) { return block->height; }); 46 | auto splitPoint = std::upper_bound(std::begin(heights), std::end(heights), height, [](auto first, auto second) { return first < second; }); 47 | auto offset = std::distance(std::begin(heights), splitPoint); 48 | std::vector> split_lo(std::make_move_iterator(std::begin(unpublishedBlocks)), std::make_move_iterator(std::begin(unpublishedBlocks) + offset)); 49 | 50 | unpublishedBlocks.erase(begin(unpublishedBlocks), std::begin(unpublishedBlocks) + offset); 51 | 52 | return split_lo; 53 | } 54 | 55 | BlockHeight SelfishPublishingStyle::getPrivateHeadHeight(std::vector> &unpublishedBlocks) const { 56 | return unpublishedBlocks.back()->height; 57 | } 58 | 59 | BlockHeight SelfishPublishingStyle::heightToPublish(const Blockchain &chain, const Miner &me, std::vector> &unpublishedBlocks) const { 60 | assert(!unpublishedBlocks.empty()); 61 | auto privateHeight = getPrivateHeadHeight(unpublishedBlocks); 62 | auto publicHeight = chain.getMaxHeightPub(); 63 | BlockHeight heightToPublish(publicHeight); 64 | // If private chain is one block ahead of the public chain and there is a race for the public head then publish 65 | if (privateHeight == publicHeight + BlockHeight(1) && chain.blocksOfHeight(publicHeight) > BlockCount(1)) { 66 | heightToPublish = privateHeight; 67 | } 68 | return heightToPublish; 69 | } 70 | -------------------------------------------------------------------------------- /BlockSim/selfish_miner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // selfish_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef selfish_miner_hpp 10 | #define selfish_miner_hpp 11 | 12 | #include "publishing_strategy.hpp" 13 | 14 | #include 15 | 16 | class Block; 17 | class Strategy; 18 | 19 | class SelfishPublishingStyle : public PublishingStrategy { 20 | private: 21 | std::vector> publishBlocks(const Blockchain &blockchain, const Miner &me, std::vector> &unpublishedBlocks) override; 22 | bool withholdsBlocks() const override { return true; } 23 | 24 | BlockHeight getPrivateHeadHeight(std::vector> &unpublishedBlocks) const; 25 | 26 | protected: 27 | virtual BlockHeight heightToPublish(const Blockchain &blockchain, const Miner &me, std::vector> &unpublishedBlocks) const; 28 | }; 29 | 30 | std::unique_ptr createSelfishStrategy(bool noiseInTransactions); 31 | Block &selfishBlockToMineOn(const Miner &me, const Blockchain &blockchain); 32 | 33 | #endif /* selfish_miner_hpp */ 34 | -------------------------------------------------------------------------------- /BlockSim/simple_mining_style.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // simple_miner.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "simple_mining_style.hpp" 10 | #include "blockchain.hpp" 11 | #include "utils.hpp" 12 | #include "block.hpp" 13 | #include "miner.hpp" 14 | 15 | #include 16 | #include 17 | 18 | SimpleMiningStyle::SimpleMiningStyle(ParentSelectorFunc parentSelectorFunc_, BlockValueFunc blockValueFunc_) : MiningStyle(parentSelectorFunc_, blockValueFunc_) {} 19 | 20 | std::pair, Value> SimpleMiningStyle::attemptToMine(Blockchain &blockchain, Miner *miner, BlockTime lastTimePaid) { 21 | auto block = createBlock(blockchain, *miner); 22 | 23 | Value cost = resetMiningCost(*miner, blockchain, lastTimePaid); 24 | 25 | return std::make_pair(std::move(block), cost); 26 | } 27 | 28 | BlockTime SimpleMiningStyle::nextMiningTime(const Blockchain &chain, const Miner &miner) const { 29 | return chain.getTime() + BlockTime(1) + selectMiningOffset(chain.chanceToWin(miner.params.hashRate)); 30 | } 31 | 32 | Value SimpleMiningStyle::resetMiningCost(const Miner &miner, const Blockchain &chain, BlockTime lastTimePaid) { 33 | return miner.params.costPerSecond * (chain.getTime() - lastTimePaid); 34 | } 35 | -------------------------------------------------------------------------------- /BlockSim/simple_mining_style.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // simple_miner.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef simple_miner_hpp 10 | #define simple_miner_hpp 11 | 12 | #include "mining_style.hpp" 13 | 14 | class SimpleMiningStyle : public MiningStyle { 15 | 16 | private: 17 | std::pair, Value> attemptToMine(Blockchain &blockchain, Miner *miner, BlockTime lastTimePaid) override; 18 | BlockTime nextMiningTime(const Blockchain &chain, const Miner &miner) const override; 19 | Value resetMiningCost(const Miner &miner, const Blockchain &chain, BlockTime lastTimePaid) override; 20 | 21 | public: 22 | SimpleMiningStyle(ParentSelectorFunc parentSelectorFunc, BlockValueFunc blockValueFunc); 23 | }; 24 | 25 | #endif /* simple_miner_hpp */ 26 | -------------------------------------------------------------------------------- /BlockSim/simple_publisher.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // simple_publisher.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "simple_publisher.hpp" 10 | #include "block.hpp" 11 | #include "blockchain.hpp" 12 | 13 | #include 14 | 15 | SimplePublisher::SimplePublisher() : PublishingStrategy() {} 16 | 17 | std::vector> SimplePublisher::publishBlocks(const Blockchain &, const Miner &, std::vector> &unpublishedBlocks) { 18 | std::vector> blocks = std::move(unpublishedBlocks); 19 | unpublishedBlocks.clear(); 20 | return blocks; 21 | } 22 | -------------------------------------------------------------------------------- /BlockSim/simple_publisher.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // simple_publisher.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef simple_publisher_hpp 10 | #define simple_publisher_hpp 11 | 12 | #include "publishing_strategy.hpp" 13 | 14 | class SimplePublisher : public PublishingStrategy { 15 | 16 | private: 17 | std::vector> publishBlocks(const Blockchain &, const Miner &, std::vector> &) override; 18 | 19 | bool withholdsBlocks() const override { return false; } 20 | public: 21 | SimplePublisher(); 22 | }; 23 | 24 | #endif /* simple_publisher_hpp */ 25 | -------------------------------------------------------------------------------- /BlockSim/strategy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // strategy.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/31/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "strategy.hpp" 10 | #include "publishing_strategy.hpp" 11 | #include "simple_publisher.hpp" 12 | #include "simple_mining_style.hpp" 13 | #include "block.hpp" 14 | 15 | #include 16 | 17 | Strategy::Strategy(std::string name_, ParentSelectorFunc parentSelFunc_, BlockValueFunc blockValFunc_) : 18 | Strategy(name_, parentSelFunc_, blockValFunc_, std::make_unique()) {} 19 | 20 | Strategy::Strategy(std::string name_, ParentSelectorFunc parentSelFunc_, BlockValueFunc blockValFunc_, ShouldMineFunc shouldMineFunc_) : 21 | Strategy(name_, parentSelFunc_, blockValFunc_, shouldMineFunc_, std::make_unique()) {} 22 | 23 | Strategy::Strategy(std::string name_, ParentSelectorFunc parentSelFunc_, BlockValueFunc blockValFunc_, ShouldMineFunc shouldMineFunc_, std::unique_ptr publisher_) : 24 | Strategy(name_, std::make_unique(parentSelFunc_, blockValFunc_, shouldMineFunc_), std::move(publisher_)) {} 25 | 26 | Strategy::Strategy(std::string name_, ParentSelectorFunc parentSelectorFunc, BlockValueFunc blockValueFunc, std::unique_ptr publisher_) : 27 | Strategy(name_, std::make_unique(parentSelectorFunc, blockValueFunc), std::move(publisher_)) {} 28 | 29 | Strategy::Strategy(std::string name_, std::unique_ptr miningStyle_, std::unique_ptr publisher_) : name(name_), miningStyle(std::move(miningStyle_)), publisher(std::move(publisher_)) {} 30 | -------------------------------------------------------------------------------- /BlockSim/strategy.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // strategy.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/31/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef strategy_hpp 10 | #define strategy_hpp 11 | 12 | #include "mining_style.hpp" 13 | #include "picky_mining_style.hpp" 14 | #include "publishing_strategy.hpp" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | class MiningStyle; 21 | 22 | class Strategy { 23 | public: 24 | 25 | Strategy(std::string name, ParentSelectorFunc parentSelectorFunc, BlockValueFunc blockValueFunc); 26 | Strategy(std::string name, ParentSelectorFunc parentSelectorFunc, BlockValueFunc blockValueFunc, ShouldMineFunc shouldMineFunc); 27 | Strategy(std::string name, ParentSelectorFunc parentSelectorFunc_, BlockValueFunc blockValueFunc_, ShouldMineFunc shouldMineFunc_, std::unique_ptr publisher_); 28 | Strategy(std::string name, ParentSelectorFunc parentSelectorFunc, BlockValueFunc blockValueFunc, std::unique_ptr publisher); 29 | Strategy(std::string name, std::unique_ptr miningStyle, std::unique_ptr publisher); 30 | 31 | const std::string name; 32 | const std::unique_ptr miningStyle; 33 | const std::unique_ptr publisher; 34 | 35 | }; 36 | 37 | #endif /* strategy_hpp */ 38 | -------------------------------------------------------------------------------- /BlockSim/typeDefs.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // typeDefs.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/15/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "typeDefs.hpp" 10 | 11 | #include "arithmetic_type/primitive_cast.hpp" 12 | 13 | #ifdef DEBUG_TYPES 14 | 15 | TimeType rawTime(BlockTime time) { 16 | return arithmetic::primitive_cast(time); 17 | } 18 | 19 | HeightType rawHeight(BlockHeight height) { 20 | return arithmetic::primitive_cast(height); 21 | } 22 | 23 | ValueType rawValue(Value value) { 24 | return arithmetic::primitive_cast(value); 25 | } 26 | 27 | ValueType rawValue(BlockValue value) { 28 | return arithmetic::primitive_cast(value); 29 | } 30 | 31 | ValueType rawValue(ValueRate value) { 32 | return arithmetic::primitive_cast(value); 33 | } 34 | 35 | CountType rawCount(MinerCount count) { 36 | return arithmetic::primitive_cast(count); 37 | } 38 | 39 | CountType rawCount(BlockCount count) { 40 | return arithmetic::primitive_cast(count); 41 | } 42 | 43 | TimeType rawBlockRate(BlockRate rate) { 44 | return arithmetic::primitive_cast(rate); 45 | } 46 | 47 | RateType rawRate(TimeRate rate) { 48 | return arithmetic::primitive_cast(rate); 49 | } 50 | 51 | RateType rawRate(HashRate rate) { 52 | return arithmetic::primitive_cast(rate); 53 | } 54 | 55 | WeightType rawWeight(StratWeight weight) { 56 | return arithmetic::primitive_cast(weight); 57 | } 58 | 59 | BlockTime operator% (BlockTime x, const BlockTime& y) { 60 | return BlockTime(rawTime(x) % rawTime(y)); 61 | } 62 | 63 | // (money / second) * seconds = money 64 | Value operator* (ValueRate x, const BlockTime& y) { 65 | return Value(rawTime(y) * rawValue(x)); 66 | } 67 | 68 | // (1 / block) / (seconds / block) = (1 / second) 69 | TimeRate operator/ (const HashRate& y, BlockRate x) { 70 | return TimeRate(rawRate(y) / rawBlockRate(x)); 71 | } 72 | 73 | // (1 / block) * money = (money / block) 74 | ValueRate operator* (TimeRate x, const Value& y) { 75 | return ValueRate(static_cast(rawValue(y) * rawRate(x))); 76 | } 77 | 78 | // (money / second) * (seconds / block) = (money / block) 79 | BlockValue operator* (const ValueRate& y, BlockRate x) { 80 | return BlockValue(rawValue(y) * rawBlockRate(x)); 81 | } 82 | 83 | // (money / block) / (seconds / block) = (money / second) 84 | ValueRate operator/ (const BlockValue& y, BlockRate x) { 85 | return ValueRate(rawValue(y) / rawBlockRate(x)); 86 | } 87 | 88 | // blocks * (seconds / block) = seconds 89 | BlockTime operator* (const BlockCount& y, BlockRate x) { 90 | return BlockTime(rawCount(y) * rawBlockRate(x)); 91 | } 92 | 93 | double operator/ (const Value& y, StratWeight x) { 94 | return rawValue(y) / rawWeight(x); 95 | } 96 | 97 | Value operator/ (const Value& y, MinerCount x) { 98 | return Value(rawValue(y) / rawCount(x)); 99 | } 100 | 101 | #else 102 | 103 | TimeType rawTime(BlockTime time) { 104 | return time; 105 | } 106 | HeightType rawHeight(BlockHeight height) { 107 | return height; 108 | } 109 | 110 | ValueType rawValue(Value value) { 111 | return value; 112 | } 113 | 114 | CountType rawCount(MinerCount count) { 115 | return count; 116 | } 117 | 118 | TimeType rawBlockRate(BlockRate rate) { 119 | return rate; 120 | } 121 | 122 | RateType rawRate(TimeRate rate) { 123 | return rate; 124 | } 125 | 126 | WeightType rawWeight(StratWeight weight) { 127 | return weight; 128 | } 129 | 130 | #endif 131 | 132 | double valuePercentage(Value a, Value b) { 133 | return static_cast(rawValue(a)) / static_cast(rawValue(b)); 134 | } 135 | -------------------------------------------------------------------------------- /BlockSim/typeDefs.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // typeDefs.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/15/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef typeDefs_hpp 10 | #define typeDefs_hpp 11 | 12 | typedef unsigned long long ValueType; 13 | typedef unsigned long TimeType; 14 | typedef unsigned int HeightType; 15 | typedef unsigned int CountType; 16 | typedef double RateType; 17 | typedef double WeightType; 18 | 19 | //#define DEBUG_TYPES 20 | 21 | #ifdef DEBUG_TYPES 22 | 23 | #include "arithmetic_type/arithmetic_type.hpp" 24 | #include "arithmetic_type/arithmetic_ostream.hpp" 25 | 26 | struct Tag1 {}; 27 | struct Tag2 {}; 28 | struct Tag3 {}; 29 | struct Tag4 {}; 30 | struct Tag5 {}; 31 | struct Tag6 {}; 32 | struct Tag7 {}; 33 | struct Tag8 {}; 34 | struct Tag9 {}; 35 | struct Tag10 {}; 36 | struct Tag11 {}; 37 | 38 | using HashRate = arithmetic::Arithmetic; // 1 / Block 39 | using TimeRate = arithmetic::Arithmetic; // 1 / second 40 | 41 | using Value = arithmetic::Arithmetic; // block 42 | using ValueRate = arithmetic::Arithmetic; // money / second 43 | using BlockValue = arithmetic::Arithmetic; // money / block 44 | 45 | using BlockHeight = arithmetic::Arithmetic; // block 46 | using BlockTime = arithmetic::Arithmetic; // seconds 47 | using BlockRate = arithmetic::Arithmetic; // seconds / block 48 | using BlockCount = arithmetic::Arithmetic; // block 49 | 50 | using StratWeight = arithmetic::Arithmetic; // block 51 | using MinerCount = arithmetic::Arithmetic; // block 52 | 53 | BlockTime operator% (BlockTime x, const BlockTime& y); 54 | 55 | // (money / second) * seconds = money 56 | Value operator* (ValueRate x, const BlockTime& y); 57 | 58 | // (1 / block) / (seconds / block) = (1 / second) 59 | TimeRate operator/ (const HashRate& y, BlockRate x); 60 | 61 | // (1 / block) * money = (money / block) 62 | ValueRate operator* (TimeRate x, const Value& y); 63 | 64 | // (money / second) * (seconds / block) = (money / block) 65 | BlockValue operator* (const ValueRate& y, BlockRate x); 66 | 67 | // (money / block) / (seconds / block) = (money / second) 68 | ValueRate operator/ (const BlockValue& y, BlockRate x); 69 | 70 | // blocks * (seconds / block) = seconds 71 | BlockTime operator* (const BlockCount& y, BlockRate x); 72 | 73 | double operator/ (const Value& y, StratWeight x); 74 | 75 | Value operator/ (const Value& y, MinerCount x); 76 | 77 | 78 | #else 79 | 80 | using HashRate = RateType; 81 | using TimeRate = RateType; 82 | 83 | using Value = ValueType; 84 | using ValueRate = ValueType; 85 | using BlockValue = ValueType; 86 | 87 | using BlockHeight = HeightType; 88 | using BlockTime = TimeType; 89 | using BlockRate = TimeType; 90 | using BlockCount = CountType; 91 | 92 | using StratWeight = WeightType; 93 | using MinerCount = CountType; 94 | 95 | #endif 96 | 97 | TimeType rawTime(BlockTime time); 98 | HeightType rawHeight(BlockHeight height); 99 | 100 | ValueType rawValue(Value value); 101 | ValueType rawValue(BlockValue value); 102 | ValueType rawValue(ValueRate value); 103 | 104 | CountType rawCount(MinerCount count); 105 | CountType rawCount(BlockCount count); 106 | 107 | TimeType rawBlockRate(BlockRate rate); 108 | 109 | RateType rawRate(TimeRate rate); 110 | RateType rawRate(HashRate rate); 111 | 112 | WeightType rawWeight(StratWeight weight); 113 | 114 | double valuePercentage(Value a, Value b); 115 | 116 | //#define NDEBUG 117 | 118 | #define SATOSHI_PER_BITCOIN ValueType(100000000) 119 | //#define TOTAL_BLOCK_VALUE 50 * SATOSHI_PER_BITCOIN 120 | #define UNDERCUT_VALUE Value(100000) 121 | 122 | //#define UNDERCUT_VALUE Value(.001) 123 | 124 | 125 | #define COST_PER_SEC_TO_MINE ValueRate(0)//(((A*SEC_PER_BLOCK+B)/SEC_PER_BLOCK)*(1.0/NUM_MINERS))*(1.0/2.0) 126 | //assumes block becomes profitable half way and miners have equal hash power 127 | 128 | 129 | #endif /* typeDefs_hpp */ 130 | -------------------------------------------------------------------------------- /BlockSim/utils.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // utils.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "utils.hpp" 10 | 11 | #include 12 | 13 | inline std::mt19937& getGen() { 14 | static std::random_device *rd = new std::random_device(); 15 | static std::mt19937 gen((*rd)()); 16 | return gen; 17 | } 18 | 19 | std::size_t selectRandomIndex(size_t size) { 20 | if (size == 1) { 21 | return 0; 22 | } 23 | std::uniform_int_distribution vectorDis(0, size - 1); 24 | return vectorDis(getGen()); 25 | } 26 | 27 | double selectRandomChance() { 28 | static std::uniform_real_distribution dis(0, 1); 29 | return dis(getGen()); 30 | } 31 | 32 | BlockTime selectMiningOffset(TimeRate mean) { 33 | std::geometric_distribution dis(rawRate(mean)); 34 | return BlockTime(dis(getGen())); 35 | } 36 | 37 | Value valWithNoise(Value minVal, Value maxVal) { 38 | static std::random_device *rd = new std::random_device(); 39 | static std::mt19937 gen((*rd)()); 40 | 41 | std::uniform_int_distribution dis(((rawValue(maxVal) - rawValue(minVal)) * 3) / 4 + rawValue(minVal), rawValue(maxVal)); 42 | return Value(dis(gen)); //random between 75% maxVal and minVal 43 | } 44 | -------------------------------------------------------------------------------- /BlockSim/utils.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // utils.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 5/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef utils_hpp 10 | #define utils_hpp 11 | 12 | #include "typeDefs.hpp" 13 | 14 | #include 15 | 16 | std::size_t selectRandomIndex(size_t size); 17 | double selectRandomChance(); 18 | BlockTime selectMiningOffset(TimeRate mean); 19 | 20 | Value valWithNoise(Value minVal, Value maxVal); 21 | 22 | #endif /* utils_hpp */ 23 | -------------------------------------------------------------------------------- /BlockSim/withholding_publisher.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // withholding_publisher.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "withholding_publisher.hpp" 10 | #include "block.hpp" 11 | #include "blockchain.hpp" 12 | 13 | #include 14 | #include 15 | 16 | 17 | std::vector> WithholdingPublisher::publishBlocks(const Blockchain &blockchain, const Miner &me, std::vector> &unpublishedBlocks) { 18 | std::vector> blocksToPublish; 19 | bool donePublishing = false; 20 | while (!donePublishing) { 21 | donePublishing = true; 22 | for (auto iter = begin(unpublishedBlocks); iter != end(unpublishedBlocks); iter++) { 23 | assert(iter->get() != nullptr); 24 | if (publishTest(blockchain, **iter, me)) { 25 | blocksToPublish.push_back(std::move(*iter)); 26 | unpublishedBlocks.erase(iter); 27 | donePublishing = false; 28 | break; 29 | } 30 | } 31 | } 32 | std::sort(begin(blocksToPublish), end(blocksToPublish), [](const std::unique_ptr &a, const std::unique_ptr &b) { return a->height < b->height; }); 33 | return blocksToPublish; 34 | } 35 | -------------------------------------------------------------------------------- /BlockSim/withholding_publisher.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // withholding_publisher.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/11/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef withholding_publisher_hpp 10 | #define withholding_publisher_hpp 11 | 12 | #include "publishing_strategy.hpp" 13 | 14 | class Miner; 15 | 16 | class WithholdingPublisher : public PublishingStrategy { 17 | 18 | private: 19 | std::vector> publishBlocks(const Blockchain &blockchain, const Miner &me, std::vector> &unpublishedBlocks) override; 20 | 21 | virtual bool publishTest(const Blockchain &blockchain, Block &block, const Miner &me) const = 0; 22 | 23 | bool withholdsBlocks() const override { return true; } 24 | 25 | public: 26 | WithholdingPublisher() : PublishingStrategy() {} 27 | virtual ~WithholdingPublisher() = default; 28 | }; 29 | 30 | #endif /* withholding_publisher_hpp */ 31 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Bitcoin Mining Simulator: 2 | Copyright © 2016 Harry Kalodner 3 | Licensed GPL v3 4 | 5 | CONTRIBUTORS AGREE TO FREE/OPEN SOURCE LICENSING 6 | ================================================ 7 | 8 | By contributing code or other works of authorship to this project ("Your 9 | Contributions"), you grant to Steven Englehardt a 10 | perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable 11 | license to reproduce, prepare derivative works of, publicly display, publicly 12 | perform, sublicense, and distribute Your Contributions and such derivative 13 | works under the terms of any free software or open source license or licenses, 14 | such license(s) to be selected by Steven Englehardt at its sole discretion. 15 | 16 | By contributing code or other works of authorship to this project, you 17 | represent that you have the legal right and ability to grant this license. 18 | 19 | Except for the license granted herein to Steven Englehardt and recipients of 20 | software distributed by Steven Englehardt, You reserve all right, title, and 21 | interest in and to Your Contributions. 22 | 23 | If you do not agree to these terms, please do not send patches or pull 24 | requests, or commit any material to this repository. 25 | 26 | LICENSES FOR INCORPORATED CODEBASES 27 | =================================== 28 | 29 | Incorporating code from arithmetic_type, 30 | https://github.com/gnzlbg/arithmetic_type 31 | Licensed Boost Software License Version 1.0 32 | 33 | Text of GPLv3 License: 34 | ====================== 35 | GNU GENERAL PUBLIC LICENSE 36 | Version 3, 29 June 2007 37 | 38 | Copyright (C) 2007 Free Software Foundation, Inc. 39 | Everyone is permitted to copy and distribute verbatim copies 40 | of this license document, but changing it is not allowed. 41 | 42 | Preamble 43 | 44 | The GNU General Public License is a free, copyleft license for 45 | software and other kinds of works. 46 | 47 | The licenses for most software and other practical works are designed 48 | to take away your freedom to share and change the works. By contrast, 49 | the GNU General Public License is intended to guarantee your freedom to 50 | share and change all versions of a program--to make sure it remains free 51 | software for all its users. We, the Free Software Foundation, use the 52 | GNU General Public License for most of our software; it applies also to 53 | any other work released this way by its authors. You can apply it to 54 | your programs, too. 55 | 56 | When we speak of free software, we are referring to freedom, not 57 | price. Our General Public Licenses are designed to make sure that you 58 | have the freedom to distribute copies of free software (and charge for 59 | them if you wish), that you receive source code or can get it if you 60 | want it, that you can change the software or use pieces of it in new 61 | free programs, and that you know you can do these things. 62 | 63 | To protect your rights, we need to prevent others from denying you 64 | these rights or asking you to surrender the rights. Therefore, you have 65 | certain responsibilities if you distribute copies of the software, or if 66 | you modify it: responsibilities to respect the freedom of others. 67 | 68 | For example, if you distribute copies of such a program, whether 69 | gratis or for a fee, you must pass on to the recipients the same 70 | freedoms that you received. You must make sure that they, too, receive 71 | or can get the source code. And you must show them these terms so they 72 | know their rights. 73 | 74 | Developers that use the GNU GPL protect your rights with two steps: 75 | (1) assert copyright on the software, and (2) offer you this License 76 | giving you legal permission to copy, distribute and/or modify it. 77 | 78 | For the developers' and authors' protection, the GPL clearly explains 79 | that there is no warranty for this free software. For both users' and 80 | authors' sake, the GPL requires that modified versions be marked as 81 | changed, so that their problems will not be attributed erroneously to 82 | authors of previous versions. 83 | 84 | Some devices are designed to deny users access to install or run 85 | modified versions of the software inside them, although the manufacturer 86 | can do so. This is fundamentally incompatible with the aim of 87 | protecting users' freedom to change the software. The systematic 88 | pattern of such abuse occurs in the area of products for individuals to 89 | use, which is precisely where it is most unacceptable. Therefore, we 90 | have designed this version of the GPL to prohibit the practice for those 91 | products. If such problems arise substantially in other domains, we 92 | stand ready to extend this provision to those domains in future versions 93 | of the GPL, as needed to protect the freedom of users. 94 | 95 | Finally, every program is threatened constantly by software patents. 96 | States should not allow patents to restrict development and use of 97 | software on general-purpose computers, but in those that do, we wish to 98 | avoid the special danger that patents applied to a free program could 99 | make it effectively proprietary. To prevent this, the GPL assures that 100 | patents cannot be used to render the program non-free. 101 | 102 | The precise terms and conditions for copying, distribution and 103 | modification follow. 104 | 105 | TERMS AND CONDITIONS 106 | 107 | 0. Definitions. 108 | 109 | "This License" refers to version 3 of the GNU General Public License. 110 | 111 | "Copyright" also means copyright-like laws that apply to other kinds of 112 | works, such as semiconductor masks. 113 | 114 | "The Program" refers to any copyrightable work licensed under this 115 | License. Each licensee is addressed as "you". "Licensees" and 116 | "recipients" may be individuals or organizations. 117 | 118 | To "modify" a work means to copy from or adapt all or part of the work 119 | in a fashion requiring copyright permission, other than the making of an 120 | exact copy. The resulting work is called a "modified version" of the 121 | earlier work or a work "based on" the earlier work. 122 | 123 | A "covered work" means either the unmodified Program or a work based 124 | on the Program. 125 | 126 | To "propagate" a work means to do anything with it that, without 127 | permission, would make you directly or secondarily liable for 128 | infringement under applicable copyright law, except executing it on a 129 | computer or modifying a private copy. Propagation includes copying, 130 | distribution (with or without modification), making available to the 131 | public, and in some countries other activities as well. 132 | 133 | To "convey" a work means any kind of propagation that enables other 134 | parties to make or receive copies. Mere interaction with a user through 135 | a computer network, with no transfer of a copy, is not conveying. 136 | 137 | An interactive user interface displays "Appropriate Legal Notices" 138 | to the extent that it includes a convenient and prominently visible 139 | feature that (1) displays an appropriate copyright notice, and (2) 140 | tells the user that there is no warranty for the work (except to the 141 | extent that warranties are provided), that licensees may convey the 142 | work under this License, and how to view a copy of this License. If 143 | the interface presents a list of user commands or options, such as a 144 | menu, a prominent item in the list meets this criterion. 145 | 146 | 1. Source Code. 147 | 148 | The "source code" for a work means the preferred form of the work 149 | for making modifications to it. "Object code" means any non-source 150 | form of a work. 151 | 152 | A "Standard Interface" means an interface that either is an official 153 | standard defined by a recognized standards body, or, in the case of 154 | interfaces specified for a particular programming language, one that 155 | is widely used among developers working in that language. 156 | 157 | The "System Libraries" of an executable work include anything, other 158 | than the work as a whole, that (a) is included in the normal form of 159 | packaging a Major Component, but which is not part of that Major 160 | Component, and (b) serves only to enable use of the work with that 161 | Major Component, or to implement a Standard Interface for which an 162 | implementation is available to the public in source code form. A 163 | "Major Component", in this context, means a major essential component 164 | (kernel, window system, and so on) of the specific operating system 165 | (if any) on which the executable work runs, or a compiler used to 166 | produce the work, or an object code interpreter used to run it. 167 | 168 | The "Corresponding Source" for a work in object code form means all 169 | the source code needed to generate, install, and (for an executable 170 | work) run the object code and to modify the work, including scripts to 171 | control those activities. However, it does not include the work's 172 | System Libraries, or general-purpose tools or generally available free 173 | programs which are used unmodified in performing those activities but 174 | which are not part of the work. For example, Corresponding Source 175 | includes interface definition files associated with source files for 176 | the work, and the source code for shared libraries and dynamically 177 | linked subprograms that the work is specifically designed to require, 178 | such as by intimate data communication or control flow between those 179 | subprograms and other parts of the work. 180 | 181 | The Corresponding Source need not include anything that users 182 | can regenerate automatically from other parts of the Corresponding 183 | Source. 184 | 185 | The Corresponding Source for a work in source code form is that 186 | same work. 187 | 188 | 2. Basic Permissions. 189 | 190 | All rights granted under this License are granted for the term of 191 | copyright on the Program, and are irrevocable provided the stated 192 | conditions are met. This License explicitly affirms your unlimited 193 | permission to run the unmodified Program. The output from running a 194 | covered work is covered by this License only if the output, given its 195 | content, constitutes a covered work. This License acknowledges your 196 | rights of fair use or other equivalent, as provided by copyright law. 197 | 198 | You may make, run and propagate covered works that you do not 199 | convey, without conditions so long as your license otherwise remains 200 | in force. You may convey covered works to others for the sole purpose 201 | of having them make modifications exclusively for you, or provide you 202 | with facilities for running those works, provided that you comply with 203 | the terms of this License in conveying all material for which you do 204 | not control copyright. Those thus making or running the covered works 205 | for you must do so exclusively on your behalf, under your direction 206 | and control, on terms that prohibit them from making any copies of 207 | your copyrighted material outside their relationship with you. 208 | 209 | Conveying under any other circumstances is permitted solely under 210 | the conditions stated below. Sublicensing is not allowed; section 10 211 | makes it unnecessary. 212 | 213 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 214 | 215 | No covered work shall be deemed part of an effective technological 216 | measure under any applicable law fulfilling obligations under article 217 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 218 | similar laws prohibiting or restricting circumvention of such 219 | measures. 220 | 221 | When you convey a covered work, you waive any legal power to forbid 222 | circumvention of technological measures to the extent such circumvention 223 | is effected by exercising rights under this License with respect to 224 | the covered work, and you disclaim any intention to limit operation or 225 | modification of the work as a means of enforcing, against the work's 226 | users, your or third parties' legal rights to forbid circumvention of 227 | technological measures. 228 | 229 | 4. Conveying Verbatim Copies. 230 | 231 | You may convey verbatim copies of the Program's source code as you 232 | receive it, in any medium, provided that you conspicuously and 233 | appropriately publish on each copy an appropriate copyright notice; 234 | keep intact all notices stating that this License and any 235 | non-permissive terms added in accord with section 7 apply to the code; 236 | keep intact all notices of the absence of any warranty; and give all 237 | recipients a copy of this License along with the Program. 238 | 239 | You may charge any price or no price for each copy that you convey, 240 | and you may offer support or warranty protection for a fee. 241 | 242 | 5. Conveying Modified Source Versions. 243 | 244 | You may convey a work based on the Program, or the modifications to 245 | produce it from the Program, in the form of source code under the 246 | terms of section 4, provided that you also meet all of these conditions: 247 | 248 | a) The work must carry prominent notices stating that you modified 249 | it, and giving a relevant date. 250 | 251 | b) The work must carry prominent notices stating that it is 252 | released under this License and any conditions added under section 253 | 7. This requirement modifies the requirement in section 4 to 254 | "keep intact all notices". 255 | 256 | c) You must license the entire work, as a whole, under this 257 | License to anyone who comes into possession of a copy. This 258 | License will therefore apply, along with any applicable section 7 259 | additional terms, to the whole of the work, and all its parts, 260 | regardless of how they are packaged. This License gives no 261 | permission to license the work in any other way, but it does not 262 | invalidate such permission if you have separately received it. 263 | 264 | d) If the work has interactive user interfaces, each must display 265 | Appropriate Legal Notices; however, if the Program has interactive 266 | interfaces that do not display Appropriate Legal Notices, your 267 | work need not make them do so. 268 | 269 | A compilation of a covered work with other separate and independent 270 | works, which are not by their nature extensions of the covered work, 271 | and which are not combined with it such as to form a larger program, 272 | in or on a volume of a storage or distribution medium, is called an 273 | "aggregate" if the compilation and its resulting copyright are not 274 | used to limit the access or legal rights of the compilation's users 275 | beyond what the individual works permit. Inclusion of a covered work 276 | in an aggregate does not cause this License to apply to the other 277 | parts of the aggregate. 278 | 279 | 6. Conveying Non-Source Forms. 280 | 281 | You may convey a covered work in object code form under the terms 282 | of sections 4 and 5, provided that you also convey the 283 | machine-readable Corresponding Source under the terms of this License, 284 | in one of these ways: 285 | 286 | a) Convey the object code in, or embodied in, a physical product 287 | (including a physical distribution medium), accompanied by the 288 | Corresponding Source fixed on a durable physical medium 289 | customarily used for software interchange. 290 | 291 | b) Convey the object code in, or embodied in, a physical product 292 | (including a physical distribution medium), accompanied by a 293 | written offer, valid for at least three years and valid for as 294 | long as you offer spare parts or customer support for that product 295 | model, to give anyone who possesses the object code either (1) a 296 | copy of the Corresponding Source for all the software in the 297 | product that is covered by this License, on a durable physical 298 | medium customarily used for software interchange, for a price no 299 | more than your reasonable cost of physically performing this 300 | conveying of source, or (2) access to copy the 301 | Corresponding Source from a network server at no charge. 302 | 303 | c) Convey individual copies of the object code with a copy of the 304 | written offer to provide the Corresponding Source. This 305 | alternative is allowed only occasionally and noncommercially, and 306 | only if you received the object code with such an offer, in accord 307 | with subsection 6b. 308 | 309 | d) Convey the object code by offering access from a designated 310 | place (gratis or for a charge), and offer equivalent access to the 311 | Corresponding Source in the same way through the same place at no 312 | further charge. You need not require recipients to copy the 313 | Corresponding Source along with the object code. If the place to 314 | copy the object code is a network server, the Corresponding Source 315 | may be on a different server (operated by you or a third party) 316 | that supports equivalent copying facilities, provided you maintain 317 | clear directions next to the object code saying where to find the 318 | Corresponding Source. Regardless of what server hosts the 319 | Corresponding Source, you remain obligated to ensure that it is 320 | available for as long as needed to satisfy these requirements. 321 | 322 | e) Convey the object code using peer-to-peer transmission, provided 323 | you inform other peers where the object code and Corresponding 324 | Source of the work are being offered to the general public at no 325 | charge under subsection 6d. 326 | 327 | A separable portion of the object code, whose source code is excluded 328 | from the Corresponding Source as a System Library, need not be 329 | included in conveying the object code work. 330 | 331 | A "User Product" is either (1) a "consumer product", which means any 332 | tangible personal property which is normally used for personal, family, 333 | or household purposes, or (2) anything designed or sold for incorporation 334 | into a dwelling. In determining whether a product is a consumer product, 335 | doubtful cases shall be resolved in favor of coverage. For a particular 336 | product received by a particular user, "normally used" refers to a 337 | typical or common use of that class of product, regardless of the status 338 | of the particular user or of the way in which the particular user 339 | actually uses, or expects or is expected to use, the product. A product 340 | is a consumer product regardless of whether the product has substantial 341 | commercial, industrial or non-consumer uses, unless such uses represent 342 | the only significant mode of use of the product. 343 | 344 | "Installation Information" for a User Product means any methods, 345 | procedures, authorization keys, or other information required to install 346 | and execute modified versions of a covered work in that User Product from 347 | a modified version of its Corresponding Source. The information must 348 | suffice to ensure that the continued functioning of the modified object 349 | code is in no case prevented or interfered with solely because 350 | modification has been made. 351 | 352 | If you convey an object code work under this section in, or with, or 353 | specifically for use in, a User Product, and the conveying occurs as 354 | part of a transaction in which the right of possession and use of the 355 | User Product is transferred to the recipient in perpetuity or for a 356 | fixed term (regardless of how the transaction is characterized), the 357 | Corresponding Source conveyed under this section must be accompanied 358 | by the Installation Information. But this requirement does not apply 359 | if neither you nor any third party retains the ability to install 360 | modified object code on the User Product (for example, the work has 361 | been installed in ROM). 362 | 363 | The requirement to provide Installation Information does not include a 364 | requirement to continue to provide support service, warranty, or updates 365 | for a work that has been modified or installed by the recipient, or for 366 | the User Product in which it has been modified or installed. Access to a 367 | network may be denied when the modification itself materially and 368 | adversely affects the operation of the network or violates the rules and 369 | protocols for communication across the network. 370 | 371 | Corresponding Source conveyed, and Installation Information provided, 372 | in accord with this section must be in a format that is publicly 373 | documented (and with an implementation available to the public in 374 | source code form), and must require no special password or key for 375 | unpacking, reading or copying. 376 | 377 | 7. Additional Terms. 378 | 379 | "Additional permissions" are terms that supplement the terms of this 380 | License by making exceptions from one or more of its conditions. 381 | Additional permissions that are applicable to the entire Program shall 382 | be treated as though they were included in this License, to the extent 383 | that they are valid under applicable law. If additional permissions 384 | apply only to part of the Program, that part may be used separately 385 | under those permissions, but the entire Program remains governed by 386 | this License without regard to the additional permissions. 387 | 388 | When you convey a copy of a covered work, you may at your option 389 | remove any additional permissions from that copy, or from any part of 390 | it. (Additional permissions may be written to require their own 391 | removal in certain cases when you modify the work.) You may place 392 | additional permissions on material, added by you to a covered work, 393 | for which you have or can give appropriate copyright permission. 394 | 395 | Notwithstanding any other provision of this License, for material you 396 | add to a covered work, you may (if authorized by the copyright holders of 397 | that material) supplement the terms of this License with terms: 398 | 399 | a) Disclaiming warranty or limiting liability differently from the 400 | terms of sections 15 and 16 of this License; or 401 | 402 | b) Requiring preservation of specified reasonable legal notices or 403 | author attributions in that material or in the Appropriate Legal 404 | Notices displayed by works containing it; or 405 | 406 | c) Prohibiting misrepresentation of the origin of that material, or 407 | requiring that modified versions of such material be marked in 408 | reasonable ways as different from the original version; or 409 | 410 | d) Limiting the use for publicity purposes of names of licensors or 411 | authors of the material; or 412 | 413 | e) Declining to grant rights under trademark law for use of some 414 | trade names, trademarks, or service marks; or 415 | 416 | f) Requiring indemnification of licensors and authors of that 417 | material by anyone who conveys the material (or modified versions of 418 | it) with contractual assumptions of liability to the recipient, for 419 | any liability that these contractual assumptions directly impose on 420 | those licensors and authors. 421 | 422 | All other non-permissive additional terms are considered "further 423 | restrictions" within the meaning of section 10. If the Program as you 424 | received it, or any part of it, contains a notice stating that it is 425 | governed by this License along with a term that is a further 426 | restriction, you may remove that term. If a license document contains 427 | a further restriction but permits relicensing or conveying under this 428 | License, you may add to a covered work material governed by the terms 429 | of that license document, provided that the further restriction does 430 | not survive such relicensing or conveying. 431 | 432 | If you add terms to a covered work in accord with this section, you 433 | must place, in the relevant source files, a statement of the 434 | additional terms that apply to those files, or a notice indicating 435 | where to find the applicable terms. 436 | 437 | Additional terms, permissive or non-permissive, may be stated in the 438 | form of a separately written license, or stated as exceptions; 439 | the above requirements apply either way. 440 | 441 | 8. Termination. 442 | 443 | You may not propagate or modify a covered work except as expressly 444 | provided under this License. Any attempt otherwise to propagate or 445 | modify it is void, and will automatically terminate your rights under 446 | this License (including any patent licenses granted under the third 447 | paragraph of section 11). 448 | 449 | However, if you cease all violation of this License, then your 450 | license from a particular copyright holder is reinstated (a) 451 | provisionally, unless and until the copyright holder explicitly and 452 | finally terminates your license, and (b) permanently, if the copyright 453 | holder fails to notify you of the violation by some reasonable means 454 | prior to 60 days after the cessation. 455 | 456 | Moreover, your license from a particular copyright holder is 457 | reinstated permanently if the copyright holder notifies you of the 458 | violation by some reasonable means, this is the first time you have 459 | received notice of violation of this License (for any work) from that 460 | copyright holder, and you cure the violation prior to 30 days after 461 | your receipt of the notice. 462 | 463 | Termination of your rights under this section does not terminate the 464 | licenses of parties who have received copies or rights from you under 465 | this License. If your rights have been terminated and not permanently 466 | reinstated, you do not qualify to receive new licenses for the same 467 | material under section 10. 468 | 469 | 9. Acceptance Not Required for Having Copies. 470 | 471 | You are not required to accept this License in order to receive or 472 | run a copy of the Program. Ancillary propagation of a covered work 473 | occurring solely as a consequence of using peer-to-peer transmission 474 | to receive a copy likewise does not require acceptance. However, 475 | nothing other than this License grants you permission to propagate or 476 | modify any covered work. These actions infringe copyright if you do 477 | not accept this License. Therefore, by modifying or propagating a 478 | covered work, you indicate your acceptance of this License to do so. 479 | 480 | 10. Automatic Licensing of Downstream Recipients. 481 | 482 | Each time you convey a covered work, the recipient automatically 483 | receives a license from the original licensors, to run, modify and 484 | propagate that work, subject to this License. You are not responsible 485 | for enforcing compliance by third parties with this License. 486 | 487 | An "entity transaction" is a transaction transferring control of an 488 | organization, or substantially all assets of one, or subdividing an 489 | organization, or merging organizations. If propagation of a covered 490 | work results from an entity transaction, each party to that 491 | transaction who receives a copy of the work also receives whatever 492 | licenses to the work the party's predecessor in interest had or could 493 | give under the previous paragraph, plus a right to possession of the 494 | Corresponding Source of the work from the predecessor in interest, if 495 | the predecessor has it or can get it with reasonable efforts. 496 | 497 | You may not impose any further restrictions on the exercise of the 498 | rights granted or affirmed under this License. For example, you may 499 | not impose a license fee, royalty, or other charge for exercise of 500 | rights granted under this License, and you may not initiate litigation 501 | (including a cross-claim or counterclaim in a lawsuit) alleging that 502 | any patent claim is infringed by making, using, selling, offering for 503 | sale, or importing the Program or any portion of it. 504 | 505 | 11. Patents. 506 | 507 | A "contributor" is a copyright holder who authorizes use under this 508 | License of the Program or a work on which the Program is based. The 509 | work thus licensed is called the contributor's "contributor version". 510 | 511 | A contributor's "essential patent claims" are all patent claims 512 | owned or controlled by the contributor, whether already acquired or 513 | hereafter acquired, that would be infringed by some manner, permitted 514 | by this License, of making, using, or selling its contributor version, 515 | but do not include claims that would be infringed only as a 516 | consequence of further modification of the contributor version. For 517 | purposes of this definition, "control" includes the right to grant 518 | patent sublicenses in a manner consistent with the requirements of 519 | this License. 520 | 521 | Each contributor grants you a non-exclusive, worldwide, royalty-free 522 | patent license under the contributor's essential patent claims, to 523 | make, use, sell, offer for sale, import and otherwise run, modify and 524 | propagate the contents of its contributor version. 525 | 526 | In the following three paragraphs, a "patent license" is any express 527 | agreement or commitment, however denominated, not to enforce a patent 528 | (such as an express permission to practice a patent or covenant not to 529 | sue for patent infringement). To "grant" such a patent license to a 530 | party means to make such an agreement or commitment not to enforce a 531 | patent against the party. 532 | 533 | If you convey a covered work, knowingly relying on a patent license, 534 | and the Corresponding Source of the work is not available for anyone 535 | to copy, free of charge and under the terms of this License, through a 536 | publicly available network server or other readily accessible means, 537 | then you must either (1) cause the Corresponding Source to be so 538 | available, or (2) arrange to deprive yourself of the benefit of the 539 | patent license for this particular work, or (3) arrange, in a manner 540 | consistent with the requirements of this License, to extend the patent 541 | license to downstream recipients. "Knowingly relying" means you have 542 | actual knowledge that, but for the patent license, your conveying the 543 | covered work in a country, or your recipient's use of the covered work 544 | in a country, would infringe one or more identifiable patents in that 545 | country that you have reason to believe are valid. 546 | 547 | If, pursuant to or in connection with a single transaction or 548 | arrangement, you convey, or propagate by procuring conveyance of, a 549 | covered work, and grant a patent license to some of the parties 550 | receiving the covered work authorizing them to use, propagate, modify 551 | or convey a specific copy of the covered work, then the patent license 552 | you grant is automatically extended to all recipients of the covered 553 | work and works based on it. 554 | 555 | A patent license is "discriminatory" if it does not include within 556 | the scope of its coverage, prohibits the exercise of, or is 557 | conditioned on the non-exercise of one or more of the rights that are 558 | specifically granted under this License. You may not convey a covered 559 | work if you are a party to an arrangement with a third party that is 560 | in the business of distributing software, under which you make payment 561 | to the third party based on the extent of your activity of conveying 562 | the work, and under which the third party grants, to any of the 563 | parties who would receive the covered work from you, a discriminatory 564 | patent license (a) in connection with copies of the covered work 565 | conveyed by you (or copies made from those copies), or (b) primarily 566 | for and in connection with specific products or compilations that 567 | contain the covered work, unless you entered into that arrangement, 568 | or that patent license was granted, prior to 28 March 2007. 569 | 570 | Nothing in this License shall be construed as excluding or limiting 571 | any implied license or other defenses to infringement that may 572 | otherwise be available to you under applicable patent law. 573 | 574 | 12. No Surrender of Others' Freedom. 575 | 576 | If conditions are imposed on you (whether by court order, agreement or 577 | otherwise) that contradict the conditions of this License, they do not 578 | excuse you from the conditions of this License. If you cannot convey a 579 | covered work so as to satisfy simultaneously your obligations under this 580 | License and any other pertinent obligations, then as a consequence you may 581 | not convey it at all. For example, if you agree to terms that obligate you 582 | to collect a royalty for further conveying from those to whom you convey 583 | the Program, the only way you could satisfy both those terms and this 584 | License would be to refrain entirely from conveying the Program. 585 | 586 | 13. Use with the GNU Affero General Public License. 587 | 588 | Notwithstanding any other provision of this License, you have 589 | permission to link or combine any covered work with a work licensed 590 | under version 3 of the GNU Affero General Public License into a single 591 | combined work, and to convey the resulting work. The terms of this 592 | License will continue to apply to the part which is the covered work, 593 | but the special requirements of the GNU Affero General Public License, 594 | section 13, concerning interaction through a network will apply to the 595 | combination as such. 596 | 597 | 14. Revised Versions of this License. 598 | 599 | The Free Software Foundation may publish revised and/or new versions of 600 | the GNU General Public License from time to time. Such new versions will 601 | be similar in spirit to the present version, but may differ in detail to 602 | address new problems or concerns. 603 | 604 | Each version is given a distinguishing version number. If the 605 | Program specifies that a certain numbered version of the GNU General 606 | Public License "or any later version" applies to it, you have the 607 | option of following the terms and conditions either of that numbered 608 | version or of any later version published by the Free Software 609 | Foundation. If the Program does not specify a version number of the 610 | GNU General Public License, you may choose any version ever published 611 | by the Free Software Foundation. 612 | 613 | If the Program specifies that a proxy can decide which future 614 | versions of the GNU General Public License can be used, that proxy's 615 | public statement of acceptance of a version permanently authorizes you 616 | to choose that version for the Program. 617 | 618 | Later license versions may give you additional or different 619 | permissions. However, no additional obligations are imposed on any 620 | author or copyright holder as a result of your choosing to follow a 621 | later version. 622 | 623 | 15. Disclaimer of Warranty. 624 | 625 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 626 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 627 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 628 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 629 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 630 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 631 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 632 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 633 | 634 | 16. Limitation of Liability. 635 | 636 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 637 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 638 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 639 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 640 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 641 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 642 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 643 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 644 | SUCH DAMAGES. 645 | 646 | 17. Interpretation of Sections 15 and 16. 647 | 648 | If the disclaimer of warranty and limitation of liability provided 649 | above cannot be given local legal effect according to their terms, 650 | reviewing courts shall apply local law that most closely approximates 651 | an absolute waiver of all civil liability in connection with the 652 | Program, unless a warranty or assumption of liability accompanies a 653 | copy of the Program in return for a fee. 654 | 655 | END OF TERMS AND CONDITIONS 656 | 657 | How to Apply These Terms to Your New Programs 658 | 659 | If you develop a new program, and you want it to be of the greatest 660 | possible use to the public, the best way to achieve this is to make it 661 | free software which everyone can redistribute and change under these terms. 662 | 663 | To do so, attach the following notices to the program. It is safest 664 | to attach them to the start of each source file to most effectively 665 | state the exclusion of warranty; and each file should have at least 666 | the "copyright" line and a pointer to where the full notice is found. 667 | 668 | {one line to give the program's name and a brief idea of what it does.} 669 | Copyright (C) {year} {name of author} 670 | 671 | This program is free software: you can redistribute it and/or modify 672 | it under the terms of the GNU General Public License as published by 673 | the Free Software Foundation, either version 3 of the License, or 674 | (at your option) any later version. 675 | 676 | This program is distributed in the hope that it will be useful, 677 | but WITHOUT ANY WARRANTY; without even the implied warranty of 678 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 679 | GNU General Public License for more details. 680 | 681 | You should have received a copy of the GNU General Public License 682 | along with this program. If not, see . 683 | 684 | Also add information on how to contact you by electronic and paper mail. 685 | 686 | If the program does terminal interaction, make it output a short 687 | notice like this when it starts in an interactive mode: 688 | 689 | {project} Copyright (C) {year} {fullname} 690 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 691 | This is free software, and you are welcome to redistribute it 692 | under certain conditions; type `show c' for details. 693 | 694 | The hypothetical commands `show w' and `show c' should show the appropriate 695 | parts of the General Public License. Of course, your program's commands 696 | might be different; for a GUI interface, you would use an "about box". 697 | 698 | You should also get your employer (if you work as a programmer) or school, 699 | if any, to sign a "copyright disclaimer" for the program, if necessary. 700 | For more information on this, and how to apply and follow the GNU GPL, see 701 | . 702 | 703 | The GNU General Public License does not permit incorporating your program 704 | into proprietary programs. If your program is a subroutine library, you 705 | may consider it more useful to permit linking proprietary applications with 706 | the library. If this is what you want to do, use the GNU Lesser General 707 | Public License instead of this License. But first, please read 708 | . 709 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CPP := g++ 2 | CPPFLAGS := -std=c++14 -Wall -g 3 | 4 | LIB := -L./ 5 | INC := -I./ 6 | 7 | LDLIBS := -lgsl -lcblas 8 | 9 | SRCS := $(wildcard BlockSim/*.cpp) 10 | OBJS := $(patsubst %.cpp,%.o,$(SRCS)) 11 | 12 | STRAT_SRCS := $(wildcard StratSim/*.cpp) 13 | STRAT_OBJS := $(patsubst %.cpp,%.o,$(STRAT_SRCS)) 14 | 15 | all: strat selfish 16 | 17 | strat: $(STRAT_SRCS) $(OBJS) 18 | $(CPP) $(CPPFLAGS) $(INC) $(LDLIBS) -o $@ $^ 19 | 20 | selfish: SelfishSim/main.cpp $(OBJS) 21 | $(CPP) $(CPPFLAGS) $(INC) $(LDLIBS) -o $@ $^ 22 | 23 | %.o: %.cpp 24 | $(CPP) $(CPPFLAGS) $(INC) -o $@ -c $< 25 | 26 | clean: 27 | rm -rf BlockSim/*.o *.o strat selfish 28 | 29 | .PHONY: all clean 30 | 31 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | Bitcoin Mining Simulator 2 | ======= 3 | 4 | This is a simulator intended for testing non-default bitcoin mining strategies. 5 | 6 | Installation 7 | ------------ 8 | 9 | The Bitcoin Mining Simulator has been developed and tested on Mac OS X 10.11.4. 10 | This software is currently setup to be run using Apple's Xcode IDE. 11 | 12 | The code is dependent on the GNU Scientific Library (https://www.gnu.org/software/gsl/). 13 | The xcode project file expects the headers to be located at /usr/local/include and the 14 | library files to be located at /usr/local/lib so these must be updated if your 15 | configuration differs. 16 | 17 | The code for the mining simulator is written in standard C++14. In the future we will 18 | release this code with a makefile so that it is easily compilable in a 19 | cross-platform manner. 20 | 21 | Usage 22 | ----------- 23 | 24 | main.cpp inside of the StratSim folder is the main code example 25 | for usage of this simulator. 26 | 27 | The code is generally designed around the idea of mining strategies. Each 28 | mining strategy prescribes set behaviors for a mining. We then create a set of 29 | miners with configurable hash rate, cost per hash, and network latency. These 30 | miners then compete to mine on a simulated blockchain with configurable block 31 | reward and transaction fee accumulation rate. 32 | 33 | In the future we will release more documentation and code examples for usage 34 | of this software. 35 | 36 | Output of Example Code 37 | ------------------------ 38 | StratSim produces a folder which includes a file for each miner that is competing 39 | to mine blocks. This simulation works by running a series of simulations where 40 | miners choose to use the strategy that they believe to be most effective. Each 41 | output file gives a list of the percentage of miners who used the given strategy 42 | in each round. This demonstrates the idea that miners will either all converge to 43 | an optimal strategy or oscillate between strategies when there is no equilibrium. 44 | 45 | SelfishSim evalutates the effectiveness of the selfish mining strategy. It 46 | produces a single file which contains the percentage profit earned by the 47 | selfish miner given the percentage of hash power which it controls. 48 | 49 | Disclaimer 50 | ----------- 51 | 52 | Note that the Bitcoin Mining Simulator is under active development, and should 53 | be considered experimental software. 54 | 55 | Although the Bitcoin Mining Simulator is actively used by our group for research 56 | studies, it is still possible there are unknown bugs in the simulator. We plan on 57 | writing comprehensive tests to verify the results of all included components. 58 | Prior to using the Bitcoin Mining Simulator for your own research we encourage 59 | you to write tests (and submit pull requests!) for any testing that isn't 60 | currently included in our test scripts. 61 | 62 | License 63 | ------- 64 | 65 | Bitcoin Mining Simulator is licensed under GNU GPLv3. Additional code has been included from 66 | [arithmetic_type](https://github.com/gnzlbg/arithmetic_type) which is licensed Boost Software License Version 1.0. 67 | -------------------------------------------------------------------------------- /SelfishSim/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/6/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "BlockSim/strategy.hpp" 10 | #include "BlockSim/utils.hpp" 11 | #include "BlockSim/miner.hpp" 12 | #include "BlockSim/block.hpp" 13 | #include "BlockSim/blockchain.hpp" 14 | #include "BlockSim/minerStrategies.h" 15 | #include "BlockSim/logging.h" 16 | #include "BlockSim/game.hpp" 17 | #include "BlockSim/minerGroup.hpp" 18 | #include "BlockSim/minerStrategies.h" 19 | #include "BlockSim/game_result.hpp" 20 | #include "BlockSim/miner_result.hpp" 21 | #include "BlockSim/mining_style.hpp" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | #define NOISE_IN_TRANSACTIONS false //miners don't put the max value they can into a block (simulate tx latency) 35 | 36 | #define NETWORK_DELAY BlockTime(0) //network delay in seconds for network to hear about your block 37 | #define EXPECTED_NUMBER_OF_BLOCKS BlockCount(20000) 38 | 39 | #define LAMBERT_COEFF 0.13533528323661//coeff for lambert func equil must be in [0,.2] 40 | //0.13533528323661 = 1/(e^2) 41 | 42 | #define B BlockValue(0) // Block reward 43 | //#define TOTAL_BLOCK_VALUE BlockValue(15.625) 44 | #define TOTAL_BLOCK_VALUE BlockValue(Value(25) * SATOSHI_PER_BITCOIN) 45 | 46 | #define SEC_PER_BLOCK BlockRate(600) //mean time in seconds to find a block 47 | 48 | //#define B BlockValue(3.125) // Block reward 49 | #define A (TOTAL_BLOCK_VALUE - B)/SEC_PER_BLOCK //rate transactions come in 50 | 51 | #define SELFISH_GAMMA 0.0 //fraction of network favoring your side in a dead tie 52 | //half way and miners have equal hash power 53 | 54 | int main(int, const char * []) { 55 | 56 | int numberOfGames = 25; 57 | 58 | //######################################################################################### 59 | //idea of simulation: 2 miners, only an honest, and a selfish miner. Run many games, with the 60 | //size of the two changing. Plot the expected profit vs. actual profit. (reproduce fig 2 in selfish paper) 61 | GAMEINFO("#####\nRunning Selfish Mining Simulation\n#####" << std::endl); 62 | std::ofstream plot; 63 | plot.open("selfishMiningPlot2.txt"); 64 | 65 | //start running games 66 | for (int gameNum = 1; gameNum <= numberOfGames; gameNum++) { 67 | 68 | std::vector> miners; 69 | 70 | // Scale power to reach %50 on the last game 71 | HashRate selfishPower = HashRate(.5*(1.0 / numberOfGames) * gameNum); 72 | // auto defaultStrat = createDefaultSelfishStrategy(NOISE_IN_TRANSACTIONS, SELFISH_GAMMA); 73 | // auto selfishStrat = createSelfishStrategy(NOISE_IN_TRANSACTIONS); 74 | 75 | using std::placeholders::_1; 76 | using std::placeholders::_2; 77 | 78 | std::function forkFunc(std::bind(functionForkPercentage, _1, _2, 2)); 79 | // auto selfishStrat = createCleverSelfishStrategy(false, Value(25)*SATOSHI_PER_BITCOIN); 80 | // auto defaultStrat = createPettyStrategy(NOISE_IN_TRANSACTIONS, SELFISH_GAMMA); 81 | auto defaultStrat = createDefaultSelfishStrategy(NOISE_IN_TRANSACTIONS, SELFISH_GAMMA); 82 | auto selfishStrat = createSelfishStrategy(NOISE_IN_TRANSACTIONS); 83 | MinerParameters selfishMinerParams = {0, std::to_string(0), selfishPower, NETWORK_DELAY, COST_PER_SEC_TO_MINE}; 84 | MinerParameters defaultinerParams = {1, std::to_string(1), HashRate(1.0) - selfishPower, NETWORK_DELAY, COST_PER_SEC_TO_MINE}; 85 | 86 | miners.push_back(std::make_unique(selfishMinerParams, *selfishStrat)); 87 | miners.push_back(std::make_unique(defaultinerParams, *defaultStrat)); 88 | 89 | MinerGroup minerGroup(std::move(miners)); 90 | 91 | GAMEINFO("\n\nGame#: " << gameNum << " The board is set, the pieces are in motion..." << std::endl); 92 | GAMEINFO("miner ratio:" << selfishPower << " selfish." << std::endl); 93 | 94 | BlockchainSettings blockchainSettings = {SEC_PER_BLOCK, A, B, EXPECTED_NUMBER_OF_BLOCKS}; 95 | GameSettings settings = {blockchainSettings}; 96 | 97 | 98 | auto blockchain = std::make_unique(settings.blockchainSettings); 99 | minerGroup.reset(*blockchain); 100 | minerGroup.resetOrder(); 101 | 102 | GAMEINFO("\n\nGame#: " << gameNum << " The board is set, the pieces are in motion..." << std::endl); 103 | 104 | auto result = runGame(minerGroup, *blockchain, settings); 105 | 106 | auto minerResults = result.minerResults; 107 | 108 | GAMEINFO("The game is complete. Calculate the scores:" << std::endl); 109 | 110 | GAMEINFO("Total profit:" << result.moneyInLongestChain << std::endl); 111 | 112 | assert(minerResults[0].totalProfit <= result.moneyInLongestChain); 113 | 114 | auto fractionOfProfits = valuePercentage(minerResults[0].totalProfit, result.moneyInLongestChain); 115 | GAMEINFO("Fraction earned by selfish:" << fractionOfProfits << " with " << selfishPower << " fraction of hash power" << std::endl); 116 | plot << selfishPower << " " << fractionOfProfits << std::endl; 117 | 118 | } 119 | 120 | GAMEINFO("Games over." << std::endl); 121 | } 122 | -------------------------------------------------------------------------------- /StratSim/exp3_learning_model.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // exp3_learning_model.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/24/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "exp3_learning_model.hpp" 10 | 11 | #include "learning_strategy.hpp" 12 | 13 | #include "BlockSim/utils.hpp" 14 | 15 | #include 16 | #include 17 | 18 | Exp3LearningModel::Exp3LearningModel(std::vector> &learningStrategies_, size_t minerCount_, std::string resultFolder) : LearningModel(learningStrategies_, minerCount_, resultFolder) { 19 | std::vector weights = getCurrentWeights(); 20 | minersWeights.reserve(minerCount); 21 | minersProbabilities.resize(minerCount); 22 | std::vector probabilities; 23 | for (size_t i = 0; i < minerCount_; i++) { 24 | minersWeights.push_back(weights); 25 | } 26 | } 27 | 28 | std::vector Exp3LearningModel::probabilitiesForMiner(size_t minerIndex, double phi) { 29 | 30 | std::vector probabilities; 31 | probabilities.reserve(stratCount); 32 | for (size_t strategyIndex = 0; strategyIndex < stratCount; strategyIndex++) { 33 | double probability = (1 - phi) * rawWeight(minersWeights[minerIndex][strategyIndex]) + phi / stratCount; 34 | 35 | assert(probability > 0); 36 | assert(!isnan(probability) && !isinf(probability)); 37 | assert(isfinite(probability) && isnormal(probability)); 38 | 39 | probabilities.push_back(probability); 40 | } 41 | minersProbabilities[minerIndex] = probabilities; 42 | 43 | return minersProbabilities[minerIndex]; 44 | } 45 | 46 | void Exp3LearningModel::updateWeights(std::vector profits, Value maxPossibleProfit, double phi) { 47 | 48 | for (size_t minerIndex = 0; minerIndex < minerCount; minerIndex++) { 49 | double profitRatio = valuePercentage(profits[minerIndex], maxPossibleProfit); 50 | double normalizedProfit(fmin(profitRatio, 1.0)); 51 | 52 | // Step 4 and Step 5 53 | double gHat = normalizedProfit / minersProbabilities[minerIndex][getChosenStrat(minerIndex)]; 54 | double weightAdjustment = exp((phi * gHat) / stratCount); 55 | 56 | StratWeight oldWeight = minersWeights[minerIndex][getChosenStrat(minerIndex)]; 57 | minersWeights[minerIndex][getChosenStrat(minerIndex)] *= StratWeight(weightAdjustment); 58 | StratWeight maxWeight = StratWeight(1) - oldWeight + minersWeights[minerIndex][getChosenStrat(minerIndex)]; 59 | 60 | // Normalize weights 61 | 62 | for (size_t strategyIndex = 0; strategyIndex < stratCount; strategyIndex++) { 63 | minersWeights[minerIndex][strategyIndex] /= maxWeight; 64 | } 65 | } 66 | 67 | std::vector weights; 68 | weights.resize(stratCount); 69 | 70 | for (auto &minerWeights : minersWeights) { 71 | for (size_t i = 0; i < stratCount; i++) { 72 | weights[i] += minerWeights[i]; 73 | } 74 | } 75 | 76 | for (size_t i = 0; i < stratCount; i++) { 77 | updateWeight(i, weights[i] / StratWeight(minerCount)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /StratSim/exp3_learning_model.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // exp3_learning_model.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/24/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef exp3_learning_model_hpp 10 | #define exp3_learning_model_hpp 11 | 12 | #include "learning_model.hpp" 13 | 14 | #include 15 | 16 | class Exp3LearningModel : public LearningModel { 17 | private: 18 | std::vector> minersWeights; 19 | std::vector> minersProbabilities; 20 | 21 | void updateWeights(std::vector profits, Value maxPossibleProfit, double phi) override; 22 | std::vector probabilitiesForMiner(size_t minerIndex, double phi) override; 23 | 24 | public: 25 | Exp3LearningModel(std::vector> &learningStrategies, size_t minerCount, std::string resultFolder); 26 | }; 27 | 28 | 29 | 30 | #endif /* exp3_learning_model_hpp */ 31 | -------------------------------------------------------------------------------- /StratSim/learning_model.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // learning_model.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/24/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "learning_model.hpp" 10 | 11 | #include "BlockSim/strategy.hpp" 12 | #include "BlockSim/publishing_strategy.hpp" 13 | #include "BlockSim/miner.hpp" 14 | #include "BlockSim/utils.hpp" 15 | #include "BlockSim/game_result.hpp" 16 | #include "BlockSim/miner_result.hpp" 17 | #include "BlockSim/block.hpp" 18 | 19 | #include "learning_strategy.hpp" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | LearningModel::LearningModel(std::vector> &learningStrategies_, size_t minerCount_, std::string resultFolder) : learningStrategies(std::move(learningStrategies_)), stratCount(learningStrategies.size()), minerCount(minerCount_) { 30 | 31 | assert(learningStrategies.size() > 0); 32 | 33 | char final [256]; 34 | sprintf (final, "./%s", resultFolder.c_str()); 35 | mkdir(final,0775); 36 | 37 | outputStreams.reserve(stratCount); 38 | chosenStrats.resize(minerCount); 39 | 40 | StratWeight totalWeight(0); 41 | for (auto &learningStrategy : learningStrategies) { 42 | totalWeight += learningStrategy->weight; 43 | } 44 | 45 | for (size_t strategyIndex = 0; strategyIndex < learningStrategies.size(); strategyIndex++) { 46 | std::stringstream ss; 47 | ss << resultFolder << "/index-" << strategyIndex << "-" << learningStrategies[strategyIndex]->strat->name << ".txt"; 48 | outputStreams.push_back(std::ofstream(ss.str())); 49 | learningStrategies[strategyIndex]->weight /= totalWeight; 50 | } 51 | } 52 | 53 | LearningModel::~LearningModel() = default; 54 | 55 | void LearningModel::writeWeights(unsigned int gameNum) { 56 | for (size_t strategyIndex = 0; strategyIndex < learningStrategies.size(); strategyIndex++) { 57 | outputStreams[strategyIndex] << gameNum << " " << learningStrategies[strategyIndex]->weight << std::endl; 58 | } 59 | } 60 | 61 | void LearningModel::pickNewStrategies(double phi, std::vector &miners, const Blockchain &chain) { 62 | static std::random_device *rd = new std::random_device(); 63 | static std::mt19937 gen((*rd)()); 64 | 65 | for (size_t minerIndex = 0; minerIndex < minerCount; minerIndex++) { 66 | std::vector probabilities = probabilitiesForMiner(minerIndex, phi); 67 | std::discrete_distribution dis(begin(probabilities), end(probabilities)); 68 | size_t stratIndex = dis(gen); 69 | chosenStrats[minerIndex] = stratIndex; 70 | Miner *miner = miners[minerIndex]; 71 | auto &strat = learningStrategies[stratIndex]->strat; 72 | miner->changeStrategy(*strat, chain); 73 | } 74 | } 75 | 76 | void LearningModel::updateWeights(GameResult &gameResult, Value maxPossibleProfit, double phi) { 77 | std::vector profits; 78 | profits.reserve(minerCount); 79 | 80 | for (size_t minerIndex = 0; minerIndex < minerCount; minerIndex++) { 81 | profits.push_back(gameResult.minerResults[minerIndex].totalProfit); 82 | } 83 | 84 | updateWeights(profits, maxPossibleProfit, phi); 85 | } 86 | 87 | void LearningModel::updateWeight(size_t i, StratWeight weight) { 88 | learningStrategies[i]->weight = weight; 89 | } 90 | 91 | std::vector LearningModel::getCurrentWeights() const { 92 | std::vector weights; 93 | weights.reserve(stratCount); 94 | std::transform(begin(learningStrategies), end(learningStrategies), std::back_inserter(weights), [](const auto &learningStrategy) { return learningStrategy->weight; }); 95 | return weights; 96 | } 97 | 98 | StratWeight LearningModel::getCurrentWeight(size_t i) const { 99 | return learningStrategies[i]->weight; 100 | } 101 | 102 | size_t LearningModel::getChosenStrat(size_t i) const { 103 | return chosenStrats[i]; 104 | } 105 | 106 | void LearningModel::printWeights() { 107 | for (size_t strategyIndex = 0; strategyIndex < learningStrategies.size(); strategyIndex++) { 108 | std::cout << "strategy:" << learningStrategies[strategyIndex]->strat->name; 109 | std::cout << " weight: " << learningStrategies[strategyIndex]->weight << "\n"; 110 | } 111 | } 112 | 113 | -------------------------------------------------------------------------------- /StratSim/learning_model.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // learning_model.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/24/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef learning_model_hpp 10 | #define learning_model_hpp 11 | 12 | #include "BlockSim/typeDefs.hpp" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | struct GameResult; 20 | class LearningStrategy; 21 | class Strategy; 22 | class Miner; 23 | class Blockchain; 24 | 25 | class LearningModel { 26 | private: 27 | std::vector outputStreams; 28 | std::vector> learningStrategies; 29 | std::vector chosenStrats; 30 | protected: 31 | const size_t stratCount; 32 | const size_t minerCount; 33 | 34 | void updateWeight(size_t i, StratWeight weight); 35 | 36 | std::vector getCurrentWeights() const; 37 | StratWeight getCurrentWeight(size_t i) const; 38 | size_t getChosenStrat(size_t i) const; 39 | public: 40 | 41 | LearningModel(std::vector> &learningStrategies, size_t minerCount, std::string resultFolder); 42 | virtual ~LearningModel(); 43 | 44 | virtual void updateWeights(std::vector profits, Value maxPossibleProfit, double phi) = 0; 45 | virtual std::vector probabilitiesForMiner(size_t minerIndex, double phi) = 0; 46 | 47 | void pickNewStrategies(double phi, std::vector &miners, const Blockchain &chain); 48 | void updateWeights(GameResult &gameResult, Value maxPossibleProfit, double phi); 49 | void writeWeights(unsigned int gameNum); 50 | void printWeights(); 51 | }; 52 | 53 | #endif /* learning_model_hpp */ 54 | -------------------------------------------------------------------------------- /StratSim/learning_strategy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // learning_strategy.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "learning_strategy.hpp" 10 | 11 | 12 | LearningStrategy::LearningStrategy(std::unique_ptr strat_, StratWeight weight_) : strat(std::move(strat_)), weight(weight_) {} 13 | -------------------------------------------------------------------------------- /StratSim/learning_strategy.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // learning_strategy.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/25/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef learning_strategy_hpp 10 | #define learning_strategy_hpp 11 | 12 | #include "BlockSim/strategy.hpp" 13 | #include "BlockSim/typeDefs.hpp" 14 | 15 | #include 16 | 17 | class LearningStrategy { 18 | public: 19 | std::unique_ptr strat; 20 | StratWeight weight; 21 | 22 | LearningStrategy(std::unique_ptr strat, StratWeight weight); 23 | }; 24 | 25 | 26 | #endif /* learning_strategy_hpp */ 27 | -------------------------------------------------------------------------------- /StratSim/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 6/6/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | 10 | #include "BlockSim/block.hpp" 11 | #include "BlockSim/blockchain.hpp" 12 | #include "BlockSim/minerStrategies.h" 13 | #include "BlockSim/logging.h" 14 | #include "BlockSim/game.hpp" 15 | #include "BlockSim/minerGroup.hpp" 16 | #include "BlockSim/miner_result.hpp" 17 | #include "BlockSim/game_result.hpp" 18 | #include "BlockSim/typeDefs.hpp" 19 | #include "BlockSim/miner.hpp" 20 | 21 | #include "multiplicative_weights_learning_model.hpp" 22 | #include "exp3_learning_model.hpp" 23 | #include "learning_strategy.hpp" 24 | 25 | #include 26 | #include 27 | 28 | //--more representative of smaller miners, where the chance that you mine the 29 | //next block is ~0 (not to be confused with the strategy selfish mining) 30 | 31 | #define ATOMIC false //not realistic, but do not force miners to mine on top of their own blocks 32 | #define NOISE_IN_TRANSACTIONS false //miners don't put the max value they can into a block (simulate tx latency) 33 | 34 | #define NETWORK_DELAY BlockTime(0) //network delay in seconds for network to hear about your block 35 | #define EXPECTED_NUMBER_OF_BLOCKS BlockCount(10000) 36 | 37 | #define LAMBERT_COEFF 0.13533528323661//coeff for lambert func equil must be in [0,.2] 38 | //0.13533528323661 = 1/(e^2) 39 | 40 | #define SEC_PER_BLOCK BlockRate(600) //mean time in seconds to find a block 41 | 42 | #define B BlockValue(0 * SATOSHI_PER_BITCOIN) // Block reward 43 | #define A BlockValue(50 * SATOSHI_PER_BITCOIN)/SEC_PER_BLOCK //rate transactions come in 44 | 45 | 46 | struct RunSettings { 47 | unsigned int numberOfGames; 48 | MinerCount totalMiners; 49 | MinerCount fixedDefault; 50 | GameSettings gameSettings; 51 | std::string folderPrefix; 52 | }; 53 | 54 | void runStratGame(RunSettings settings, std::vector> &learningStrategies, std::unique_ptr defaultStrategy); 55 | 56 | void runSingleStratGame(RunSettings settings); 57 | 58 | void runStratGame(RunSettings settings, std::vector> &learningStrategies, std::unique_ptr defaultStrategy) { 59 | 60 | //start running games 61 | BlockCount totalBlocksMined(0); 62 | BlockCount blocksInLongestChain(0); 63 | 64 | std::string resultFolder = ""; 65 | 66 | if (settings.folderPrefix.length() > 0) { 67 | resultFolder += settings.folderPrefix + "-"; 68 | } 69 | 70 | resultFolder += std::to_string(rawCount(settings.fixedDefault)); 71 | 72 | std::vector> miners; 73 | std::vector learningMiners; 74 | 75 | HashRate hashRate(1.0/rawCount(settings.totalMiners)); 76 | MinerCount numberRandomMiners(settings.totalMiners - settings.fixedDefault); 77 | 78 | for (MinerCount i(0); i < settings.totalMiners; i++) { 79 | auto minerName = std::to_string(rawCount(i)); 80 | MinerParameters parameters {rawCount(i), minerName, hashRate, NETWORK_DELAY, COST_PER_SEC_TO_MINE}; 81 | miners.push_back(std::make_unique(parameters, *defaultStrategy)); 82 | if (i < numberRandomMiners) { 83 | learningMiners.push_back(miners.back().get()); 84 | } 85 | } 86 | 87 | // LearningModel *learningModel = new MultiplicativeWeightsLearningModel(learningStrategies, learningMiners.size(), resultFolder); 88 | LearningModel *learningModel = new Exp3LearningModel(learningStrategies, learningMiners.size(), resultFolder); 89 | 90 | MinerGroup minerGroup(std::move(miners)); 91 | 92 | // double phi = std::sqrt(strategies.size() * std::log(strategies.size())) / std::sqrt(settings.numberOfGames); 93 | // double phi = std::sqrt(strategies.size() * std::log(strategies.size())) / std::sqrt(settings.numberOfGames / 100); 94 | 95 | double phi = .01; 96 | 97 | auto blockchain = std::make_unique(settings.gameSettings.blockchainSettings); 98 | 99 | for (unsigned int gameNum = 0; gameNum < settings.numberOfGames; gameNum++) { 100 | // double n = gameNum; 101 | // double nMax = settings.numberOfGames; 102 | // double phi = std::pow(.9, (n / nMax) * 30.0); 103 | 104 | blockchain->reset(settings.gameSettings.blockchainSettings); 105 | 106 | learningModel->writeWeights(gameNum); 107 | minerGroup.reset(*blockchain); 108 | learningModel->pickNewStrategies(phi, learningMiners, *blockchain); 109 | minerGroup.resetOrder(); 110 | 111 | GAMEINFO("\n\nGame#: " << gameNum << " The board is set, the pieces are in motion..." << std::endl); 112 | 113 | auto result = runGame(minerGroup, *blockchain, settings.gameSettings); 114 | 115 | GAMEINFO("The game is complete. Calculate the scores:" << std::endl); 116 | 117 | Value maxProfit = (A * (EXPECTED_NUMBER_OF_BLOCKS * settings.gameSettings.blockchainSettings.secondsPerBlock) - result.moneyLeftAtEnd) / Value(rawCount(settings.totalMiners) / 4); 118 | 119 | // Steps 3, 4, 5 120 | learningModel->updateWeights(result, maxProfit, phi); 121 | 122 | totalBlocksMined += result.totalBlocksMined; 123 | blocksInLongestChain += result.blocksInLongestChain; 124 | 125 | // BlockCount staleBlocks(result.totalBlocksMined - result.blocksInLongestChain); 126 | // std::cout << result.moneyInLongestChain << " in chain and " << 127 | // result.moneyLeftAtEnd << " left with " << 100 * double(rawCount(staleBlocks)) / double(rawCount(result.totalBlocksMined)) << "% orphan rate" << std::endl; 128 | 129 | // std::cout << totalBlocksMined << " total blocks mined" << std::endl; 130 | } 131 | learningModel->writeWeights(settings.numberOfGames); 132 | 133 | delete learningModel; 134 | // std::cout << 100 * double(rawCount(blocksInLongestChain)) / double(rawCount(totalBlocksMined)) << "% in final chain" << std::endl; 135 | 136 | GAMEINFOBLOCK( 137 | GAMEINFO("Games over. Final strategy weights:\n"); 138 | learningModel->printWeights(); 139 | ) 140 | } 141 | 142 | void runSingleStratGame(RunSettings settings) { 143 | using std::placeholders::_1; 144 | using std::placeholders::_2; 145 | 146 | std::vector> learningStrategies; 147 | 148 | StratWeight defaultWeight(1); 149 | 150 | std::unique_ptr defaultStrategy(createDefaultStrategy(ATOMIC, NOISE_IN_TRANSACTIONS)); 151 | 152 | learningStrategies.push_back(std::make_unique(createPettyStrategy(ATOMIC, NOISE_IN_TRANSACTIONS), defaultWeight)); 153 | for (int i = -1; i < 3; i++) { 154 | int funcCoeff = static_cast(pow(2, (i + 1))); 155 | std::function forkFunc(std::bind(functionForkPercentage, _1, _2, funcCoeff)); 156 | learningStrategies.push_back(std::make_unique(createFunctionForkStrategy(ATOMIC, forkFunc, std::to_string(funcCoeff)), defaultWeight)); 157 | } 158 | // strategies.push_back(createFunctionForkStrategy(NO_SELF_MINING, std::bind(functionForkLambert, _1, _2, LAMBERT_COEFF), "lambert")); 159 | learningStrategies.push_back(std::make_unique(createLazyForkStrategy(ATOMIC), defaultWeight)); 160 | 161 | 162 | runStratGame(settings, learningStrategies, std::move(defaultStrategy)); 163 | } 164 | 165 | int main(int, const char * []) { 166 | 167 | BlockchainSettings blockchainSettings = {SEC_PER_BLOCK, A, B, EXPECTED_NUMBER_OF_BLOCKS}; 168 | GameSettings gameSettings = {blockchainSettings}; 169 | // 170 | // for (MinerCount i(0); i < MinerCount(71); i += MinerCount(6)) { 171 | // RunSettings runSettings = {300000, MinerCount(100), i, gameSettings, "mult"}; 172 | // runSingleStratGame(runSettings); 173 | // } 174 | 175 | RunSettings runSettings = {1000, MinerCount(200), MinerCount(0), gameSettings, "test"}; 176 | runSingleStratGame(runSettings); 177 | 178 | } 179 | -------------------------------------------------------------------------------- /StratSim/multiplicative_weights_learning_model.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // multiplicative_weights_learning_model.cpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/24/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #include "multiplicative_weights_learning_model.hpp" 10 | 11 | #include "BlockSim/utils.hpp" 12 | #include "learning_strategy.hpp" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | MultiplicativeWeightsLearningModel::MultiplicativeWeightsLearningModel(std::vector> &learningStrategies, size_t minerCount_, std::string resultFolder) : LearningModel(learningStrategies, minerCount_, resultFolder) { 19 | std::vector weights = getCurrentWeights(); 20 | probabilities.reserve(stratCount); 21 | std::transform(begin(weights), end(weights), std::back_inserter(probabilities), [](const auto &weight) { return rawWeight(weight); }); 22 | } 23 | 24 | std::vector MultiplicativeWeightsLearningModel::probabilitiesForMiner(size_t, double) { 25 | return probabilities; 26 | } 27 | 28 | void MultiplicativeWeightsLearningModel::updateWeights(std::vector profits, Value, double phi) { 29 | 30 | struct StratUsage { 31 | Value profits; 32 | MinerCount minersUsing; 33 | 34 | StratUsage() : profits(0), minersUsing(0) {} 35 | 36 | void addProfit(Value profit) { 37 | profits += profit; 38 | minersUsing++; 39 | } 40 | 41 | void normalize() { 42 | if (minersUsing > MinerCount(1)) { 43 | profits /= Value(minersUsing); 44 | minersUsing = MinerCount(1); 45 | } 46 | } 47 | 48 | bool isUnused() { 49 | return minersUsing == MinerCount(0); 50 | } 51 | 52 | double profitRatio(Value maxProfits) { 53 | assert(profits <= maxProfits); 54 | return rawValue(profits/maxProfits); 55 | } 56 | }; 57 | 58 | std::vector stratUsages; 59 | stratUsages.resize(stratCount); 60 | 61 | for (size_t i = 0; i < minerCount; i++) { 62 | stratUsages[getChosenStrat(i)].addProfit(profits[i]); 63 | } 64 | 65 | Value maxProfits(0); 66 | for (auto &stratUsage : stratUsages) { 67 | stratUsage.normalize(); 68 | if (maxProfits < stratUsage.profits) { 69 | maxProfits = stratUsage.profits; 70 | } 71 | } 72 | 73 | std::vector newWeights; 74 | newWeights.reserve(stratCount); 75 | 76 | StratWeight totalWeight(0); 77 | for (size_t i = 0; i < stratUsages.size(); i++) { 78 | double c_t = 1.1 - stratUsages[i].profitRatio(maxProfits); 79 | if (stratUsages[i].isUnused()) { 80 | //means no one tried the strategy, keep weight unchanged (encourage exploration)? 81 | c_t = 0; 82 | } 83 | 84 | StratWeight newWeight = getCurrentWeight(i) * StratWeight(pow((1-phi), c_t)); 85 | updateWeight(i, newWeight); 86 | totalWeight += newWeight; 87 | newWeights.push_back(newWeight); 88 | } 89 | 90 | for (size_t i = 0; i < newWeights.size(); i++) { 91 | updateWeight(i, newWeights[i] / totalWeight); 92 | } 93 | 94 | std::vector weights = getCurrentWeights(); 95 | 96 | probabilities.clear(); 97 | probabilities.reserve(stratCount); 98 | std::transform(begin(weights), end(weights), std::back_inserter(probabilities), [](const auto &weight) { return rawWeight(weight); }); 99 | } 100 | -------------------------------------------------------------------------------- /StratSim/multiplicative_weights_learning_model.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // multiplicative_weights_learning_model.hpp 3 | // BlockSim 4 | // 5 | // Created by Harry Kalodner on 10/24/16. 6 | // Copyright © 2016 Harry Kalodner. All rights reserved. 7 | // 8 | 9 | #ifndef multiplicative_weights_learning_model_hpp 10 | #define multiplicative_weights_learning_model_hpp 11 | 12 | #include "learning_model.hpp" 13 | 14 | #include 15 | 16 | class MultiplicativeWeightsLearningModel : public LearningModel { 17 | private: 18 | std::vector probabilities; 19 | 20 | std::vector probabilitiesForMiner(size_t minerIndex, double phi) override; 21 | void updateWeights(std::vector profits, Value maxPossibleProfit, double phi) override; 22 | public: 23 | MultiplicativeWeightsLearningModel(std::vector> &learningStrategies, size_t minerCount, std::string resultFolder); 24 | 25 | }; 26 | 27 | #endif /* multiplicative_weights_learning_model_hpp */ 28 | --------------------------------------------------------------------------------