def lwma_next_work_required(block_list): # T target_solvetime = 10 * 60 # N For T=600, 300, 150 use approximately N=60, 90, 120 average_window = 60 # Define a k that will be used to get a proper average after weighting the solvetimes. k = int(average_window * (average_window + 1) * target_solvetime // 2) height = block_list[-1]['height'] pow_limit = net['pow_limit'] # New coins should just give away first N blocks before using this algorithm. if height < average_window: return ser.compact_from_uint256(pow_limit) average_target = 0 prev_timestamp = block_list[-average_window - 1]['time'] sum_weighted_solvetimes = 0 solvetime_weight = 0 # Loop through N most recent blocks. for i in range(height + 1 - average_window, height + 1): block = block_list[i - height - 1] # Prevent solvetimes from being negative in a safe way. It must be done like this. # In particular, do not attempt anything like if(solvetime < 0) {solvetime=0;} # The +1 ensures new coins do not calculate nextTarget = 0. this_timestamp = block[ 'time'] if block['time'] > prev_timestamp else prev_timestamp + 1 # A 6*T limit will prevent large drops in difficulty from long solvetimes. solve_time = min(6 * target_solvetime, this_timestamp - prev_timestamp) # The following is part of "preventing negative solvetimes". prev_timestamp = this_timestamp # Give linearly higher weight to more recent solvetimes. solvetime_weight = solvetime_weight + 1 sum_weighted_solvetimes += solve_time * solvetime_weight target = ser.uint256_from_compact(block['nbits']) average_target += target // ( average_window * k ) # Dividing by k here prevents an overflow below. # Desired equation in next line was nextTarget = avgTarget * sumWeightSolvetimes / k # but 1/k was moved to line above to prevent overflow in new coins next_target = sum_weighted_solvetimes * average_target if next_target > pow_limit: print('exceed pow limit') next_target = pow_limit next_nbits = ser.compact_from_uint256(next_target) print('lwma nbits:', hex(next_nbits)) print('difficulty:', difficulty(next_nbits)) return next_nbits
def _check_difficulty_target(self, header): parent = b2lx(header.hashPrevBlock) target = self.get_difficulty_target(parent) if (self.get_height() + 1) % 2016 == 0: end = self.get_timestamp(parent) min, max = (302400, 4838400) for i in range(2015): parent = self._get_parent(parent) start = self.get_timestamp(parent) difference = end - start if difference < min: difference = min elif difference > max: difference = max target = compact_from_uint256(long(uint256_from_compact(target) * (float(difference) / (60 * 60 * 24 * 14)))) if self.testnet and header.nTime - self.get_timestamp(parent) >= 1200: return target if uint256_from_compact(header.nBits) > uint256_from_compact(target): raise CheckBlockHeaderError("Target difficutly is incorrect") return target
def _check_difficulty_target(self, header): parent = b2lx(header.hashPrevBlock) target = self.get_difficulty_target(parent) if (self.get_height() + 1) % 2016 == 0: end = self.get_timestamp(parent) min, max = (302400, 4838400) for i in range(2015): parent = self._get_parent(parent) start = self.get_timestamp(parent) difference = end - start if difference < min: difference = min elif difference > max: difference = max target = compact_from_uint256( long( uint256_from_compact(target) * (float(difference) / (60 * 60 * 24 * 14)))) if self.testnet and header.nTime - self.get_timestamp(parent) >= 1200: return target if uint256_from_compact(header.nBits) > uint256_from_compact(target): raise CheckBlockHeaderError("Target difficutly is incorrect") return target
def get_next_work_required(block_list): global net fork_height = net['fork_height'] adjust_interval = 72 last_height = block_list[-1]['height'] height_span = last_height + 1 - fork_height if height_span % adjust_interval != 0: print('Not time to adjust target.') return block_list[-1]['nbits'] target_time_span = 72 * 10 * 60 retarget_factor = 2 real_time_span = block_list[-1]['time'] - block_list[-adjust_interval][ 'time'] adjusted_time_span = real_time_span if adjusted_time_span < target_time_span // retarget_factor: adjusted_time_span = target_time_span // retarget_factor if adjusted_time_span > target_time_span * retarget_factor: adjusted_time_span = target_time_span * retarget_factor print('adjusted time span: %s, real time span: %s' % (adjusted_time_span, real_time_span)) pow_limit = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff last_target = ser.uint256_from_compact(block_list[-1]['nbits']) next_target = last_target * adjusted_time_span // target_time_span if next_target > pow_limit: print('exceed pow limit') next_target = pow_limit next_nbits = ser.compact_from_uint256(next_target) print('original nbits:', hex(next_nbits)) print('difficulty:', difficulty(next_nbits)) return next_nbits
def putoneblock(self, block, initsync=True): if not self.have_prevblock(block): self.orphans[block.GetHash()] = True self.orphan_deps[block.hashPrevBlock] = block self.log.warn("Orphan block %s (%d orphans)" % (b2lx(block.GetHash()), len(self.orphan_deps))) return False # if block.hashPrevBlock != self.gettophash(): # print("Cannot connect block to chain %s %s" % (b2lx(block.GetHash()), b2lx(self.gettophash()))) # return top_height = self.getheight() top_work = bytes_to_int(self.db.get(b'misc:total_work')) prevmeta = BlkMeta() if top_height >= 0: ser_prevhash = b2lx(block.hashPrevBlock) data = self.db.get(('blkmeta:'+ser_prevhash).encode()) prevmeta.deserialize(data) else: ser_prevhash = '' # build network "block" msg, as canonical disk storage form msg = msg_block() msg.block = block msg_data = msg.to_bytes() # write "block" msg to storage fpos = self.blk_write.tell() self.blk_write.write(msg_data) self.blk_write.flush() with self.db.write_batch(transaction=True) as batch: # add index entry ser_hash = b2lx(block.GetHash()) key = ('blocks:'+ser_hash).encode() value = struct.pack('i', fpos) batch.put(key, value) # store metadata related to this block blkmeta = BlkMeta() blkmeta.height = prevmeta.height + 1 blkmeta.work = (prevmeta.work + uint256_from_compact(block.nBits)) batch.put(('blkmeta:'+ser_hash).encode(), blkmeta.serialize()) # store list of blocks at this height heightidx = HeightIdx() heightstr = str(blkmeta.height) d = self.db.get(('height:'+heightstr).encode()) if d: heightidx.deserialize(d) heightidx.blocks.append(block.GetHash()) batch.put(('height:'+heightstr).encode(), heightidx.serialize()) # print('height: %s' % blkmeta.height) # print('blk: %s' % blkmeta.work) # print('top: %s' % top_work) # if chain is not best chain, proceed no further if (blkmeta.work <= top_work): self.log.info("ChainDb: height %d (weak), block %s" % (blkmeta.height, b2lx(block.GetHash()))) return True # update global chain pointers if not self.set_best_chain(ser_prevhash, ser_hash, block, blkmeta): return False return True
def hash_rate(self): bnTarget = uint256_from_compact(bytes_to_int(self.bits)) diff = int('FFFF0000000000000000000000000000000000000000000000000000', 16) / bnTarget return int(diff * (2**32 / 60))
def putoneblock(self, block): try: core.CheckBlock(block) except core.CheckBlockError: self.log.info( "Invalid block {}".format(block.GetHash().encode('hex'))) return False if not self.have_prevblock(block): self.orphans[block.GetHash()] = True self.orphan_deps[block.hashPrevBlock] = block self.log.info("Orphan block {} ({} orphans)" .format(block.GetHash().encode('hex'), len(self.orphan_deps))) return False top_height = self.getheight() top_work = long(self.db.Get(b'misc:total_work'), 16) # read metadata for previous block prevmeta = BlkMeta() if top_height >= 0: prevmeta.deserialize(self.db.Get(b'blkmeta:' + block.hashPrevBlock)) batch = leveldb.WriteBatch() # build network "block" msg, as canonical disk storage form msg = msg_block() msg.block = block f = io.BytesIO() msg.msg_ser(f) msg_data = f.getvalue() # write "block" msg to storage fpos = self.blk_write.tell() self.blk_write.write(msg_data) self.blk_write.flush() # add index entry batch.Put(b'blocks:' + block.GetHash(), str(fpos)) # store metadata related to this block blkmeta = BlkMeta() blkmeta.height = prevmeta.height + 1 blkmeta.work = (prevmeta.work + serialize.uint256_from_compact(block.nBits)) batch.Put(b'blkmeta:' + block.GetHash(), blkmeta.serialize()) # store list of blocks at this height heightidx = HeightIdx() heightstr = str(blkmeta.height) try: heightidx.deserialize(self.db.Get(b'height:' + heightstr)) except KeyError: pass heightidx.blocks.append(block.GetHash()) batch.Put(b'height:' + heightstr, heightidx.serialize()) self.db.Write(batch) # if chain is not best chain, proceed no further if blkmeta.work <= top_work: self.log.info( "height {} (weak), block {}" .format(blkmeta.height, block.GetHash().encode('hex'))) return True # update global chain pointers if not self.set_best_chain(block.hashPrevBlock, block.GetHash(), block, blkmeta): return False return True
def putoneblock(self, block): try: core.CheckBlock(block) except core.CheckBlockError: self.log.info("Invalid block {}".format( block.GetHash().encode('hex'))) return False if not self.have_prevblock(block): self.orphans[block.GetHash()] = True self.orphan_deps[block.hashPrevBlock] = block self.log.info("Orphan block {} ({} orphans)".format( block.GetHash().encode('hex'), len(self.orphan_deps))) return False top_height = self.getheight() top_work = long(self.db.Get(b'misc:total_work'), 16) # read metadata for previous block prevmeta = BlkMeta() if top_height >= 0: prevmeta.deserialize(self.db.Get(b'blkmeta:' + block.hashPrevBlock)) batch = leveldb.WriteBatch() # build network "block" msg, as canonical disk storage form msg = msg_block() msg.block = block f = io.BytesIO() msg.msg_ser(f) msg_data = f.getvalue() # write "block" msg to storage fpos = self.blk_write.tell() self.blk_write.write(msg_data) self.blk_write.flush() # add index entry batch.Put(b'blocks:' + block.GetHash(), str(fpos)) # store metadata related to this block blkmeta = BlkMeta() blkmeta.height = prevmeta.height + 1 blkmeta.work = (prevmeta.work + serialize.uint256_from_compact(block.nBits)) batch.Put(b'blkmeta:' + block.GetHash(), blkmeta.serialize()) # store list of blocks at this height heightidx = HeightIdx() heightstr = str(blkmeta.height) try: heightidx.deserialize(self.db.Get(b'height:' + heightstr)) except KeyError: pass heightidx.blocks.append(block.GetHash()) batch.Put(b'height:' + heightstr, heightidx.serialize()) self.db.Write(batch) # if chain is not best chain, proceed no further if blkmeta.work <= top_work: self.log.info("height {} (weak), block {}".format( blkmeta.height, block.GetHash().encode('hex'))) return True # update global chain pointers if not self.set_best_chain(block.hashPrevBlock, block.GetHash(), block, blkmeta): return False return True