Changes for target calculation
All the changes required for target calculation, verification and saving parts of chunks for FLO @akhil2015 Co-authored-by: Akhil Bharti <akhil2015@users.noreply.github.com>
This commit is contained in:
parent
ca30705c69
commit
85bae50e62
@ -28,7 +28,14 @@ from .bitcoin import Hash, hash_encode, int_to_hex, rev_hex
|
||||
from . import constants
|
||||
from .util import bfh, bh2u
|
||||
|
||||
MAX_TARGET = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
|
||||
try:
|
||||
import scrypt
|
||||
getPoWHash = lambda x: scrypt.hash(x, x, N=1024, r=1, p=1, buflen=32)
|
||||
except ImportError:
|
||||
util.print_msg("Warning: package scrypt not available; synchronization could be very slow")
|
||||
from .scrypt import scrypt_1024_1_1_80 as getPoWHash
|
||||
|
||||
MAX_TARGET = 0x00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
|
||||
|
||||
class MissingHeader(Exception):
|
||||
@ -69,6 +76,8 @@ def hash_header(header):
|
||||
header['prev_block_hash'] = '00'*32
|
||||
return hash_encode(Hash(bfh(serialize_header(header))))
|
||||
|
||||
def pow_hash_header(header):
|
||||
return hash_encode(getPoWHash(bfh(serialize_header(header))))
|
||||
|
||||
blockchains = {}
|
||||
|
||||
@ -168,25 +177,36 @@ class Blockchain(util.PrintError):
|
||||
|
||||
def verify_header(self, header, prev_hash, target):
|
||||
_hash = hash_header(header)
|
||||
#if prev_hash != header.get('prev_block_hash'):
|
||||
# raise Exception("prev hash mismatch: %s vs %s" % (prev_hash, header.get('prev_block_hash')))
|
||||
#if constants.net.TESTNET:
|
||||
# return
|
||||
bits = self.target_to_bits(target)
|
||||
#if bits != header.get('bits'):
|
||||
# raise Exception("bits mismatch: %s vs %s" % (bits, header.get('bits')))
|
||||
#if int('0x' + _hash, 16) > target:
|
||||
# raise Exception("insufficient proof of work: %s vs target %s" % (int('0x' + _hash, 16), target))
|
||||
_powhash = pow_hash_header(header)
|
||||
if prev_hash != header.get('prev_block_hash'):
|
||||
raise Exception("prev hash mismatch: %s vs %s" % (prev_hash, header.get('prev_block_hash')))
|
||||
if constants.net.TESTNET:
|
||||
return
|
||||
print("I'm inside verify_header")
|
||||
#bits = self.target_to_bits(target)
|
||||
bits = target
|
||||
if bits != header.get('bits'):
|
||||
raise Exception("bits mismatch: %s vs %s" % (bits, header.get('bits')))
|
||||
block_hash = int('0x' + _hash, 16)
|
||||
target_val = self.bits_to_target(bits)
|
||||
if int('0x' + _powhash, 16) > target_val:
|
||||
raise Exception("insufficient proof of work: %s vs target %s" % (int('0x' + _hash, 16), target_val))
|
||||
print("I passed verify_header(). Calc target values have been matched")
|
||||
|
||||
def verify_chunk(self, index, data):
|
||||
num = len(data) // 80
|
||||
prev_hash = self.get_hash(index * 2016 - 1)
|
||||
target = self.get_target(index-1)
|
||||
current_header = (index * 2016)
|
||||
# last = (index * 2016 + 2015)
|
||||
prev_hash = self.get_hash(current_header - 1)
|
||||
for i in range(num):
|
||||
target = self.get_target(current_header - 1)
|
||||
raw_header = data[i*80:(i+1) * 80]
|
||||
header = deserialize_header(raw_header, index*2016 + i)
|
||||
header = deserialize_header(raw_header, current_header)
|
||||
print(i)
|
||||
self.verify_header(header, prev_hash, target)
|
||||
self.save_chunk_part(header)
|
||||
prev_hash = hash_header(header)
|
||||
current_header = current_header + 1
|
||||
|
||||
def path(self):
|
||||
d = util.get_headers_dir(self.config)
|
||||
@ -202,15 +222,15 @@ class Blockchain(util.PrintError):
|
||||
main_chain.save_chunk(index, chunk)
|
||||
return
|
||||
|
||||
delta_height = (index * 2016 - self.forkpoint)
|
||||
#delta_height = (index * 2016 - self.forkpoint)
|
||||
delta_bytes = delta_height * 80
|
||||
# if this chunk contains our forkpoint, only save the part after forkpoint
|
||||
# (the part before is the responsibility of the parent)
|
||||
if delta_bytes < 0:
|
||||
chunk = chunk[-delta_bytes:]
|
||||
delta_bytes = 0
|
||||
truncate = not chunk_within_checkpoint_region
|
||||
self.write(chunk, delta_bytes, truncate)
|
||||
#if delta_bytes < 0:
|
||||
# chunk = chunk[-delta_bytes:]
|
||||
# delta_bytes = 0
|
||||
#truncate = not chunk_within_checkpoint_region
|
||||
#self.write(chunk, delta_bytes, truncate)
|
||||
self.swap_with_parent()
|
||||
|
||||
@with_lock
|
||||
@ -319,29 +339,58 @@ class Blockchain(util.PrintError):
|
||||
# compute target from chunk x, used in chunk x+1
|
||||
if constants.net.TESTNET:
|
||||
return 0
|
||||
if index == -1:
|
||||
return MAX_TARGET
|
||||
# The range is first 90 blocks because FLO's block time was 90 blocks when it started
|
||||
if -1 <= index <= 88:
|
||||
return 0x1e0ffff0
|
||||
if index < len(self.checkpoints):
|
||||
h, t = self.checkpoints[index]
|
||||
return t
|
||||
# new target
|
||||
first = self.read_header(index * 2016)
|
||||
last = self.read_header(index * 2016 + 2015)
|
||||
if not first or not last:
|
||||
raise MissingHeader()
|
||||
bits = last.get('bits')
|
||||
target = self.bits_to_target(bits)
|
||||
nActualTimespan = last.get('timestamp') - first.get('timestamp')
|
||||
nTargetTimespan = 14 * 24 * 60 * 60
|
||||
nActualTimespan = max(nActualTimespan, nTargetTimespan // 4)
|
||||
nActualTimespan = min(nActualTimespan, nTargetTimespan * 4)
|
||||
new_target = min(MAX_TARGET, (target * nActualTimespan) // nTargetTimespan)
|
||||
return new_target
|
||||
headerLast = self.read_header(index)
|
||||
height = headerLast["block_height"]
|
||||
# check if the height passes is in range for retargeting
|
||||
if (height + 1) % self.DifficultyAdjustmentInterval(height + 1) != 0:
|
||||
return int(headerLast["bits"])
|
||||
averagingInterval = self.AveragingInterval(height + 1)
|
||||
blockstogoback = averagingInterval - 1
|
||||
# print("Blocks to go back = " + str(blockstogoback))
|
||||
if (height + 1) != averagingInterval:
|
||||
blockstogoback = averagingInterval
|
||||
firstHeight = height - blockstogoback
|
||||
headerFirst = self.read_header(int(firstHeight))
|
||||
firstBlockTime = headerFirst["timestamp"]
|
||||
nMinActualTimespan = int(self.MinActualTimespan(int(headerLast["block_height"]) + 1))
|
||||
|
||||
nMaxActualTimespan = int(self.MaxActualTimespan(int(headerLast["block_height"]) + 1))
|
||||
# Limit adjustment step
|
||||
nActualTimespan = headerLast["timestamp"] - firstBlockTime
|
||||
if nActualTimespan < nMinActualTimespan:
|
||||
nActualTimespan = nMinActualTimespan
|
||||
if nActualTimespan > nMaxActualTimespan:
|
||||
nActualTimespan = nMaxActualTimespan
|
||||
# Retarget
|
||||
bnNewBits = int(headerLast["bits"])
|
||||
bnNew = self.bits_to_target(bnNewBits)
|
||||
bnOld = bnNew
|
||||
# FLO: intermediate uint256 can overflow by 1 bit
|
||||
# const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
|
||||
fShift = bnNew > MAX_TARGET - 1
|
||||
|
||||
if (fShift):
|
||||
bnNew = bnNew >> 1
|
||||
bnNew = bnNew * nActualTimespan
|
||||
bnNew = bnNew / self.TargetTimespan(headerLast["block_height"] + 1)
|
||||
if fShift:
|
||||
bnNew = bnNew << 1
|
||||
if bnNew > MAX_TARGET:
|
||||
bnNew = MAX_TARGET
|
||||
bnNew = self.target_to_bits(int(bnNew))
|
||||
return bnNew
|
||||
|
||||
def bits_to_target(self, bits):
|
||||
bitsN = (bits >> 24) & 0xff
|
||||
if not (bitsN >= 0x03 and bitsN <= 0x1d):
|
||||
raise Exception("First part of bits should be in [0x03, 0x1d]")
|
||||
if not (bitsN >= 0x03 and bitsN <= 0x1e):
|
||||
raise BaseException("First part of bits should be in [0x03, 0x1e]")
|
||||
bitsBase = bits & 0xffffff
|
||||
if not (bitsBase >= 0x8000 and bitsBase <= 0x7fffff):
|
||||
raise Exception("Second part of bits should be in [0x8000, 0x7fffff]")
|
||||
@ -373,7 +422,7 @@ class Blockchain(util.PrintError):
|
||||
if prev_hash != header.get('prev_block_hash'):
|
||||
return False
|
||||
try:
|
||||
target = self.get_target(height // 2016 - 1)
|
||||
target = self.get_target(height - 1)
|
||||
except MissingHeader:
|
||||
return False
|
||||
try:
|
||||
@ -402,3 +451,67 @@ class Blockchain(util.PrintError):
|
||||
target = self.get_target(index)
|
||||
cp.append((h, target))
|
||||
return cp
|
||||
|
||||
def AveragingInterval(self, height):
|
||||
# V1
|
||||
if height < constants.net.nHeight_Difficulty_Version2:
|
||||
return constants.net.nAveragingInterval_Version1
|
||||
# V2
|
||||
elif height < constants.net.nHeight_Difficulty_Version3:
|
||||
return constants.net.nAveragingInterval_Version2
|
||||
# V3
|
||||
else:
|
||||
return constants.net.nAveragingInterval_Version3
|
||||
|
||||
def MinActualTimespan(self, height):
|
||||
averagingTargetTimespan = self.AveragingInterval(height) * constants.net.nPowTargetSpacing
|
||||
# V1
|
||||
if height < constants.net.nHeight_Difficulty_Version2:
|
||||
return int(averagingTargetTimespan * (100 - constants.net.nMaxAdjustUp_Version1) / 100)
|
||||
# V2
|
||||
elif height < constants.net.nHeight_Difficulty_Version3:
|
||||
return int(averagingTargetTimespan * (100 - constants.net.nMaxAdjustUp_Version2) / 100)
|
||||
# V3
|
||||
else:
|
||||
return int(averagingTargetTimespan * (100 - constants.net.nMaxAdjustUp_Version3) / 100)
|
||||
|
||||
def MaxActualTimespan(self, height):
|
||||
averagingTargetTimespan = self.AveragingInterval(height) * constants.net.nPowTargetSpacing
|
||||
# V1
|
||||
if height < constants.net.nHeight_Difficulty_Version2:
|
||||
return int(averagingTargetTimespan * (100 + constants.net.nMaxAdjustDown_Version1) / 100)
|
||||
# V2
|
||||
elif height < constants.net.nHeight_Difficulty_Version3:
|
||||
return int(averagingTargetTimespan * (100 + constants.net.nMaxAdjustDown_Version2) / 100)
|
||||
# V3
|
||||
else:
|
||||
return int(averagingTargetTimespan * (100 + constants.net.nMaxAdjustDown_Version3) / 100)
|
||||
|
||||
def TargetTimespan(self, height):
|
||||
# V1
|
||||
if height < constants.net.nHeight_Difficulty_Version2:
|
||||
return constants.net.nTargetTimespan_Version1
|
||||
# V2
|
||||
if height < constants.net.nHeight_Difficulty_Version3:
|
||||
return constants.net.nAveragingInterval_Version2 * constants.net.nPowTargetSpacing
|
||||
# V3
|
||||
return constants.net.nAveragingInterval_Version3 * constants.net.nPowTargetSpacing
|
||||
|
||||
def DifficultyAdjustmentInterval(self, height):
|
||||
# V1
|
||||
if height < constants.net.nHeight_Difficulty_Version2:
|
||||
return constants.net.nInterval_Version1
|
||||
# V2
|
||||
if height < constants.net.nHeight_Difficulty_Version3:
|
||||
return constants.net.nInterval_Version2
|
||||
# V3
|
||||
return constants.net.nInterval_Version3
|
||||
|
||||
def save_chunk_part(self, header):
|
||||
filename = self.path()
|
||||
delta = header.get('block_height') - self.checkpoint
|
||||
data = bfh(serialize_header(header))
|
||||
# assert delta == self.size()
|
||||
assert len(data) == 80
|
||||
self.write(data, delta * 80)
|
||||
# self.swap_with_parent()
|
||||
|
||||
@ -64,6 +64,31 @@ class BitcoinMainnet:
|
||||
'p2wsh': 0x02aa7ed3, # Zpub
|
||||
}
|
||||
BIP44_COIN_TYPE = 2
|
||||
# FLO Network constants
|
||||
fPowAllowMinDifficultyBlocks = False
|
||||
fPowNoRetargeting = False
|
||||
nRuleChangeActivationThreshold = 6048 # 75% of 8064
|
||||
nMinerConfirmationWindow = 8064
|
||||
# Difficulty adjustments
|
||||
nPowTargetSpacing = 40 # 40s block time
|
||||
# V1
|
||||
nTargetTimespan_Version1 = 60 * 60
|
||||
nInterval_Version1 = nTargetTimespan_Version1 / nPowTargetSpacing
|
||||
nMaxAdjustUp_Version1 = 75
|
||||
nMaxAdjustDown_Version1 = 300
|
||||
nAveragingInterval_Version1 = nInterval_Version1
|
||||
# V2
|
||||
nHeight_Difficulty_Version2 = 208440
|
||||
nInterval_Version2 = 15
|
||||
nMaxAdjustDown_Version2 = 300
|
||||
nMaxAdjustUp_Version2 = 75
|
||||
nAveragingInterval_Version2 = nInterval_Version2
|
||||
# V3
|
||||
nHeight_Difficulty_Version3 = 426000
|
||||
nInterval_Version3 = 1
|
||||
nMaxAdjustDown_Version3 = 3
|
||||
nMaxAdjustUp_Version3 = 2
|
||||
nAveragingInterval_Version3 = 6
|
||||
|
||||
|
||||
class BitcoinTestnet:
|
||||
@ -93,6 +118,26 @@ class BitcoinTestnet:
|
||||
'p2wsh': 0x02575483, # Vpub
|
||||
}
|
||||
BIP44_COIN_TYPE = 1
|
||||
#Difficulty adjustments
|
||||
nPowTargetSpacing = 40 # 40 block time
|
||||
# V1
|
||||
nTargetTimespan_Version1 = 60 * 60
|
||||
nInterval_Version1 = nTargetTimespan_Version1 / nPowTargetSpacing;
|
||||
nMaxAdjustUp_Version1 = 75
|
||||
nMaxAdjustDown_Version1 = 300
|
||||
nAveragingInterval_Version1 = nInterval_Version1
|
||||
# V2
|
||||
nHeight_Difficulty_Version2 = 50000
|
||||
nInterval_Version2 = 15
|
||||
nMaxAdjustDown_Version2 = 300
|
||||
nMaxAdjustUp_Version2 = 75
|
||||
nAveragingInterval_Version2 = nInterval_Version2
|
||||
# V3
|
||||
nHeight_Difficulty_Version3 = 60000
|
||||
nInterval_Version3 = 1
|
||||
nMaxAdjustDown_Version3 = 3
|
||||
nMaxAdjustUp_Version3 = 2
|
||||
nAveragingInterval_Version3 = 6
|
||||
|
||||
|
||||
class BitcoinRegtest(BitcoinTestnet):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user