Skip to content

Commit

Permalink
Fixed a regression introduced in 4.2.1
Browse files Browse the repository at this point in the history
The issues manifests itself whenever the checkpoint block is after
the asert anchor. This caused the code in blockchain.py to have a bad time.

The asert anchor calculation code needs all headers, but if we have a
checkpoint after the anchor, all headers are not always available. The fix
is to either have checkpoints before the anchor, or to hard-code the anchor.

This is the case for all chains we support now.

We hard-coded the anchor for all chains except for scalenet, which will
reorg back to before the anchor each time so hard-coding the anchor
would break things in the future.
  • Loading branch information
cculianu committed Nov 18, 2020
1 parent a06f716 commit 3f63318
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 19 deletions.
6 changes: 6 additions & 0 deletions RELEASE-NOTES
Expand Up @@ -1060,3 +1060,9 @@ and there is no warning message.
- Added checkpoint after HF block, also added CLI arg --taxcoin for ABC's coin.
(Calin Culianu)
- Network Dialog: Added advanced request throttling params (Calin Culianu)

# RELEASE NOTES 4.2.2

- Fixed a regression introduced in 4.2.1 where the checkpoint block being after
the asert anchor caused the code in blockchain.py to have a bad time.
(Calin Culianu)
1 change: 1 addition & 0 deletions electroncash/asert_daa.py
Expand Up @@ -72,6 +72,7 @@ class ASERTDaa:

MAX_TARGET = bits_to_target(MAX_BITS)

# If left as none, blockchain.py will calculate this at runtime as we read headers.
anchor: Optional[Anchor] = None

def __init__(self, is_testnet=False):
Expand Down
17 changes: 11 additions & 6 deletions electroncash/blockchain.py
Expand Up @@ -423,19 +423,24 @@ def get_suitable_block_height(self, suitableheight, chunk=None):

return blocks1['block_height']

_cached_asert_anchor: Optional[asert_daa.Anchor] = None # cached Anchor, per-Blockchain instance
# cached Anchor, per-Blockchain instance, only used if the checkpoint for this network is *behind* the anchor block
_cached_asert_anchor: Optional[asert_daa.Anchor] = None

def get_asert_anchor(self, prevheader, mtp, chunk=None):
"""Returns the asert_anchor either from Networks.net if hardcoded or
calculated in realtime if not."""
if networks.net.asert_daa.anchor is not None:
# Checkpointed (hard-coded) value exists, just use that
return networks.net.asert_daa.anchor
# Bug note: The below does not work if we don't have all the intervening
# headers -- therefore this execution path should only be taken for networks
# where the checkpoint block is before the anchor block. This means that
# adding a checkpoint after the anchor block without setting the anchor
# block in networks.net.asert_daa.anchor will result in bugs.
if (self._cached_asert_anchor is not None
and self._cached_asert_anchor.height <= prevheader['block_height']):
return self._cached_asert_anchor
# ****
# This may be slow -- we really should be leveraging the hard-coded
# checkpointed value. TODO: add hard-coded value to networks.py after
# Nov. 15th 2020 HF to ASERT DAA
# ****

anchor = prevheader
activation_mtp = networks.net.asert_daa.MTP_ACTIVATION_TIME
while mtp >= activation_mtp:
Expand Down
39 changes: 26 additions & 13 deletions electroncash/networks.py
Expand Up @@ -22,9 +22,10 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import json, pkgutil
import json
import pkgutil

from .asert_daa import ASERTDaa
from .asert_daa import ASERTDaa, Anchor

def _read_json_dict(filename):
try:
Expand All @@ -36,7 +37,6 @@ def _read_json_dict(filename):

class AbstractNet:
TESTNET = False
asert_daa = ASERTDaa()
LEGACY_POW_TARGET_TIMESPAN = 14 * 24 * 60 * 60 # 2 weeks
LEGACY_POW_TARGET_INTERVAL = 10 * 60 # 10 minutes
LEGACY_POW_RETARGET_BLOCKS = LEGACY_POW_TARGET_TIMESPAN // LEGACY_POW_TARGET_INTERVAL # 2016 blocks
Expand Down Expand Up @@ -73,8 +73,13 @@ class MainNet(AbstractNet):
# network.synchronous_get(("blockchain.block.header", [height, height]))
#
# Consult the ElectrumX documentation for more details.
VERIFICATION_BLOCK_MERKLE_ROOT = "45fca167c5d9b7774eab414e1608cefd37737488fb1e11f10c2e42eaf1be370e"
VERIFICATION_BLOCK_HEIGHT = 661648
VERIFICATION_BLOCK_MERKLE_ROOT = "68077352cf309072547164625deb11e92bd379e759e87f3f9ac6e61d1532c536"
VERIFICATION_BLOCK_HEIGHT = 661942
asert_daa = ASERTDaa(is_testnet=False)
# Note: We *must* specify the anchor if the checkpoint is after the anchor, due to the way
# blockchain.py skips headers after the checkpoint. So all instances that have a checkpoint
# after the anchor must specify the anchor as well.
asert_daa.anchor = Anchor(height=661647, bits=402971390, prev_time=1605447844)

# Version numbers for BIP32 extended keys
# standard: xprv, xpub
Expand All @@ -89,7 +94,6 @@ class MainNet(AbstractNet):

class TestNet(AbstractNet):
TESTNET = True
asert_daa = ASERTDaa(is_testnet=True)
WIF_PREFIX = 0xef
ADDRTYPE_P2PKH = 111
ADDRTYPE_P2PKH_BITPAY = 111 # Unsure
Expand All @@ -113,6 +117,8 @@ class TestNet(AbstractNet):

VERIFICATION_BLOCK_MERKLE_ROOT = "d97d670815829fddcf728fa2d29665de53e83609fd471b0716a49cde383fb888"
VERIFICATION_BLOCK_HEIGHT = 1421482
asert_daa = ASERTDaa(is_testnet=True)
asert_daa.anchor = Anchor(height=1421481, bits=486604799, prev_time=1605445400)

# Version numbers for BIP32 extended keys
# standard: tprv, tpub
Expand All @@ -134,38 +140,43 @@ class TestNet4(TestNet):
DEFAULT_SERVERS = _read_json_dict('servers_testnet4.json') # DO NOT MODIFY IN CLIENT CODE
DEFAULT_PORTS = {'t': '62001', 's': '62002'}

VERIFICATION_BLOCK_MERKLE_ROOT = "9ca8933d4aa7b85093e3ec317e40bdfeda3e2b793fcd7907b38580fa193d9c77"
VERIFICATION_BLOCK_HEIGHT = 16845

BITCOIN_CASH_FORK_BLOCK_HEIGHT = 6
BITCOIN_CASH_FORK_BLOCK_HASH = "00000000d71b9b1f7e13b0c9b218a12df6526c1bcd1b667764b8693ae9a413cb"

# Nov 13. 2017 HF to CW144 DAA height (height of last block mined on old DAA)
CW144_HEIGHT = 3000

VERIFICATION_BLOCK_MERKLE_ROOT = "9ca8933d4aa7b85093e3ec317e40bdfeda3e2b793fcd7907b38580fa193d9c77"
VERIFICATION_BLOCK_HEIGHT = 16845
asert_daa = ASERTDaa(is_testnet=True) # Redeclare to get instance for this subclass
asert_daa.anchor = Anchor(height=16844, bits=486604799, prev_time=1605451779)



class ScaleNet(TestNet):
GENESIS = "00000000e6453dc2dfe1ffa19023f86002eb11dbb8e87d0291a4599f0430be52"
TITLE = 'Electron Cash Scalenet'
BASE_UNITS = {'sBCH': 8, 'msBCH': 5, 'sbits': 2}
DEFAULT_UNIT = "tBCH"

asert_daa = ASERTDaa(is_testnet=False) # Despite being a "testnet", ScaleNet uses 2d half-life

HEADERS_URL = "http://bitcoincash.com/files/scalenet_headers" # Unused

DEFAULT_SERVERS = _read_json_dict('servers_scalenet.json') # DO NOT MODIFY IN CLIENT CODE
DEFAULT_PORTS = {'t': '63001', 's': '63002'}

VERIFICATION_BLOCK_MERKLE_ROOT = "41eb32849a353fcb408c8b25e84578c714dbdc5ee774d0fbe25e85755250df6a"
VERIFICATION_BLOCK_HEIGHT = 2016

BITCOIN_CASH_FORK_BLOCK_HEIGHT = 6
BITCOIN_CASH_FORK_BLOCK_HASH = "000000000e16730d293050fc5fe5b0978b858f5d9d91192a5ca2793902493597"

# Nov 13. 2017 HF to CW144 DAA height (height of last block mined on old DAA)
CW144_HEIGHT = 3000

VERIFICATION_BLOCK_MERKLE_ROOT = "41eb32849a353fcb408c8b25e84578c714dbdc5ee774d0fbe25e85755250df6a"
VERIFICATION_BLOCK_HEIGHT = 2016
asert_daa = ASERTDaa(is_testnet=False) # Despite being a "testnet", ScaleNet uses 2d half-life
asert_daa.anchor = None # Intentionally not specified because it's after checkpoint; blockchain.py will calculate



class TaxCoinNet(AbstractNet):
""" This is for supporting ABC tax coin. Use CLI arg --taxcoin to see this network.
Expand Down Expand Up @@ -204,6 +215,8 @@ class TaxCoinNet(AbstractNet):
# Consult the ElectrumX documentation for more details.
VERIFICATION_BLOCK_MERKLE_ROOT = "d0d925862df595918416020caf5467b7ae67ae8f807daf60626c36755b62f9a2"
VERIFICATION_BLOCK_HEIGHT = 661648 # ABC fork block
asert_daa = ASERTDaa(is_testnet=False)
asert_daa.anchor = Anchor(height=661647, bits=402971390, prev_time=1605447844)

# Version numbers for BIP32 extended keys
# standard: xprv, xpub
Expand Down

0 comments on commit 3f63318

Please sign in to comment.