github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/blockchain/hardfork_core.go (about) 1 // Copyright 2017-2018 DERO Project. All rights reserved. 2 // Use of this source code in any form is governed by RESEARCH license. 3 // license can be found in the LICENSE file. 4 // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 5 // 6 // 7 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 10 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 11 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 12 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 13 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 14 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 15 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 17 package blockchain 18 19 import "github.com/deroproject/derosuite/block" 20 import "github.com/deroproject/derosuite/config" 21 import "github.com/deroproject/derosuite/storage" 22 import "github.com/deroproject/derosuite/globals" 23 24 // the voting for hard fork works as follows 25 // block major version remains contant, while block minor version contains the next hard fork number, 26 // at trigger height, the last window_size blocks are counted as folllows 27 // if Major_Version == minor version, it is a negative vote 28 // if minor_version > major_version, it is positive vote 29 // if threshold votes are positive, the next hard fork triggers 30 31 // this is work in progress 32 // hard forking is integrated deep within the the blockchain as almost anything can be replaced in DERO without disruption 33 const default_voting_window_size = 6000 // this many votes will counted 34 const default_vote_percent = 62 // 62 percent votes means the hard fork is locked in 35 36 type Hard_fork struct { 37 Version int64 // which version will trigger 38 Height int64 // at what height hard fork will come into effect, trigger block 39 Window_size int64 // how many votes to count (x number of votes) 40 Threshold int64 // between 0 and 99 // percent number of votes required to lock in hardfork, 0 = mandatory 41 Votes int64 // number of votes in favor 42 Voted bool // whether voting resulted in hardfork 43 } 44 45 // current mainnet_hard_forks 46 var mainnet_hard_forks = []Hard_fork{ 47 // {0, 0,0,0,0,true}, // dummy entry so as we can directly use the fork index into this entry 48 {1, 0, 0, 0, 0, true}, // version 1 hard fork where genesis block landed and chain migration occurs 49 // version 1 has difficulty hardcoded to 1 50 {2, 95551, 0, 0, 0, true}, // version 2 hard fork where Atlantis bootstraps , it's mandatory 51 {3, 721000, 0, 0, 0, true}, // version 3 hard fork emission fix, it's mandatory 52 {4, 4550555, 0, 0, 0, true}, // version 4 hard fork AstroBWT CPU Mining enabled. It's mandatory 53 } 54 55 // current testnet_hard_forks 56 var testnet_hard_forks = []Hard_fork{ 57 //{1, 0, 0, 0, 0, true}, // version 1 hard fork where genesis block landed 58 {3, 0, 0, 0, 0, true}, // version 3 hard fork where we started , it's mandatory 59 {4, 3, 0, 0, 0, true}, // version 4 hard fork where we change mining algorithm it's mandatory 60 } 61 62 // current simulation_hard_forks 63 // these can be tampered with for testing and other purposes 64 // this variable is exported so as simulation can play/test hard fork code 65 var Simulation_hard_forks = []Hard_fork{ 66 {1, 0, 0, 0, 0, true}, // version 1 hard fork where genesis block landed 67 {2, 1, 0, 0, 0, true}, // version 2 hard fork where we started , it's mandatory 68 } 69 70 // at init time, suitable versions are selected 71 var current_hard_forks []Hard_fork 72 73 // init suitable structure based on mainnet/testnet selection at runtime 74 func init_hard_forks(params map[string]interface{}) { 75 76 // if simulation , load simulation features 77 if params["--simulator"] == true { 78 current_hard_forks = Simulation_hard_forks // enable simulator mode hard forks 79 logger.Debugf("simulator hardforks are online") 80 } else { 81 if globals.IsMainnet() { 82 current_hard_forks = mainnet_hard_forks 83 logger.Debugf("mainnet hardforks are online") 84 } else { 85 current_hard_forks = testnet_hard_forks 86 logger.Debugf("testnet hardforks are online") 87 } 88 89 } 90 91 // if voting in progress, load all votes from db, since we do not store votes in disk, 92 // we will load all necessary blocks, counting votes 93 } 94 95 // check block version validity at specific height according to current network 96 func (chain *Blockchain) Check_Block_Version(dbtx storage.DBTX, bl *block.Block) (result bool) { 97 98 height := chain.Calculate_Height_At_Tips(dbtx, bl.Tips) 99 100 if height == 0 && bl.Major_Version == 1 { // handle genesis block as exception 101 return true 102 } 103 // all blocks except genesis block land here 104 if bl.Major_Version == uint64(chain.Get_Current_Version_at_Height(height)) { 105 return true 106 } 107 108 return 109 } 110 111 // this func will recount votes, set whether the version is voted in 112 // only the main chain blocks are counted in 113 // this func must be called with chain in lock state 114 /* 115 func (chain *Blockchain) Recount_Votes() { 116 height := chain.Load_Height_for_BL_ID(chain.Get_Top_ID()) 117 118 for i := len(current_hard_forks) - 1; i > 0; i-- { 119 // count votes only if voting is in progress 120 if 0 != current_hard_forks[i].Window_size && // if window_size > 0 121 height <= current_hard_forks[i].Height && 122 height >= (current_hard_forks[i].Height-current_hard_forks[i].Window_size) { // start voting when required 123 124 hard_fork_locked := false 125 current_hard_forks[i].Votes = 0 // make votes zero, before counting 126 for j := height; j >= (current_hard_forks[i].Height - current_hard_forks[i].Window_size); j-- { 127 // load each block, and count the votes 128 129 hash, err := chain.Load_BL_ID_at_Height(j) 130 if err == nil { 131 bl, err := chain.Load_BL_FROM_ID(hash) 132 if err == nil { 133 if bl.Minor_Version == uint64(current_hard_forks[i].Version) { 134 current_hard_forks[i].Votes++ 135 } 136 } else { 137 logger.Warnf("err loading block (%s) at height %d, chain height %d err %s", hash, j, height, err) 138 } 139 140 } else { 141 logger.Warnf("err loading block at height %d, chain height %d err %s", j, height, err) 142 } 143 144 } 145 146 // if necessary votes have been accumulated , lock in the hard fork 147 if ((current_hard_forks[i].Votes * 100) / current_hard_forks[i].Window_size) >= current_hard_forks[i].Threshold { 148 hard_fork_locked = true 149 } 150 current_hard_forks[i].Voted = hard_fork_locked // keep it as per status 151 } 152 153 } 154 155 } 156 */ 157 // this function returns number of information whether hf is going on scheduled, everything is okay etc 158 func (chain *Blockchain) Get_HF_info() (state int, enabled bool, earliest_height, threshold, version, votes, window int64) { 159 160 state = 2 // default is everything is okay 161 enabled = true 162 163 topoheight := chain.Load_TOPO_HEIGHT(nil) 164 block_id, err := chain.Load_Block_Topological_order_at_index(nil, topoheight) 165 if err != nil { 166 return 167 } 168 169 bl, err := chain.Load_BL_FROM_ID(nil, block_id) 170 if err != nil { 171 logger.Warnf("err loading block (%s) at topo height %d err %s", block_id, topoheight, err) 172 } 173 174 height := chain.Load_Height_for_BL_ID(nil, block_id) 175 176 version = chain.Get_Current_Version_at_Height(height) 177 178 // check top block to see if the network is going through a hard fork 179 if bl.Major_Version != bl.Minor_Version { // network is going through voting 180 state = 0 181 enabled = false 182 } 183 184 if bl.Minor_Version != uint64(chain.Get_Ideal_Version_at_Height(height)) { 185 // we are NOT voting for the hard fork ( or we are already broken), issue warning to user, that we need an upgrade NOW 186 state = 1 187 enabled = false 188 version = int64(bl.Minor_Version) 189 } 190 if state == 0 { // we know our state is good, report back, good info 191 for i := range current_hard_forks { 192 if version == current_hard_forks[i].Version { 193 earliest_height = current_hard_forks[i].Height 194 threshold = current_hard_forks[i].Threshold 195 version = current_hard_forks[i].Version 196 votes = current_hard_forks[i].Votes 197 window = current_hard_forks[i].Window_size 198 } 199 } 200 } 201 202 return 203 } 204 205 // current hard fork version , block major version 206 // we may be at genesis block height 207 func (chain *Blockchain) Get_Current_Version() int64 { // it is last version voted or mandatory update 208 return chain.Get_Current_Version_at_Height(chain.Get_Height()) 209 } 210 211 func (chain *Blockchain) Get_Current_BlockTime() uint64 { // it is last version voted or mandatory update 212 block_time:= config.BLOCK_TIME 213 if chain.Get_Current_Version() >= 4 { 214 block_time= config.BLOCK_TIME_hf4 215 } 216 return block_time 217 } 218 219 220 func (chain *Blockchain) Get_Current_Version_at_Height(height int64) int64 { 221 for i := len(current_hard_forks) - 1; i >= 0; i-- { 222 //logger.Infof("i %d height %d hf height %d",i, height,current_hard_forks[i].Height ) 223 if height >= current_hard_forks[i].Height { 224 225 // if it was a mandatory fork handle it directly 226 if current_hard_forks[i].Threshold == 0 { 227 return current_hard_forks[i].Version 228 } 229 230 if current_hard_forks[i].Voted { // if the version was voted in, select it, other wise try lower 231 return current_hard_forks[i].Version 232 } 233 } 234 } 235 return 0 236 } 237 238 // if we are voting, return the next expected version 239 func (chain *Blockchain) Get_Ideal_Version() int64 { 240 return chain.Get_Ideal_Version_at_Height(chain.Get_Height()) 241 } 242 243 // used to cast vote 244 func (chain *Blockchain) Get_Ideal_Version_at_Height(height int64) int64 { 245 for i := len(current_hard_forks) - 1; i > 0; i-- { 246 // only voted during the period required 247 if height <= current_hard_forks[i].Height && 248 height >= (current_hard_forks[i].Height-current_hard_forks[i].Window_size) { // start voting when required 249 return current_hard_forks[i].Version 250 } 251 } 252 253 // if we are not voting, return current version 254 return chain.Get_Current_Version_at_Height(height) 255 } 256 257 /* 258 259 // if the block major version is more than what we have in our index, display warning to user 260 func (chain *Blockchain) Display_Warning_If_Blocks_are_New(bl *block.Block) { 261 // check the biggest fork 262 if current_hard_forks[len(current_hard_forks )-1].version < bl.Major_Version { 263 logger.Warnf("We have seen new blocks floating with version number bigger than ours, please update the software") 264 } 265 return 266 } 267 */