2018-11-20 18:57:16 +01:00
|
|
|
import shutil
|
|
|
|
|
import tempfile
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
from electrum import constants, blockchain
|
|
|
|
|
from electrum.simple_config import SimpleConfig
|
2023-04-23 02:00:50 +00:00
|
|
|
from electrum.blockchain import Blockchain, deserialize_header, hash_header, InvalidHeader
|
2023-02-17 11:35:03 +00:00
|
|
|
from electrum.util import bfh, make_dir
|
2018-11-20 18:57:16 +01:00
|
|
|
|
2019-09-22 20:46:01 +02:00
|
|
|
from . import ElectrumTestCase
|
2018-11-20 18:57:16 +01:00
|
|
|
|
|
|
|
|
|
2019-09-22 20:46:01 +02:00
|
|
|
class TestBlockchain(ElectrumTestCase):
|
2018-11-20 18:57:16 +01:00
|
|
|
|
|
|
|
|
HEADERS = {
|
|
|
|
|
'A': deserialize_header(bfh("0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f2002000000"), 0),
|
|
|
|
|
'B': deserialize_header(bfh("0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f186c8dfd970a4545f79916bc1d75c9d00432f57c89209bf3bb115b7612848f509c25f45bffff7f2000000000"), 1),
|
|
|
|
|
'C': deserialize_header(bfh("00000020686bdfc6a3db73d5d93e8c9663a720a26ecb1ef20eb05af11b36cdbc57c19f7ebf2cbf153013a1c54abaf70e95198fcef2f3059cc6b4d0f7e876808e7d24d11cc825f45bffff7f2000000000"), 2),
|
|
|
|
|
'D': deserialize_header(bfh("00000020122baa14f3ef54985ae546d1611559e3f487bd2a0f46e8dbb52fbacc9e237972e71019d7feecd9b8596eca9a67032c5f4641b23b5d731dc393e37de7f9c2f299e725f45bffff7f2000000000"), 3),
|
|
|
|
|
'E': deserialize_header(bfh("00000020f8016f7ef3a17d557afe05d4ea7ab6bde1b2247b7643896c1b63d43a1598b747a3586da94c71753f27c075f57f44faf913c31177a0957bbda42e7699e3a2141aed25f45bffff7f2001000000"), 4),
|
|
|
|
|
'F': deserialize_header(bfh("000000201d589c6643c1d121d73b0573e5ee58ab575b8fdf16d507e7e915c5fbfbbfd05e7aee1d692d1615c3bdf52c291032144ce9e3b258a473c17c745047f3431ff8e2ee25f45bffff7f2000000000"), 5),
|
|
|
|
|
'O': deserialize_header(bfh("00000020b833ed46eea01d4c980f59feee44a66aa1162748b6801029565d1466790c405c3a141ce635cbb1cd2b3a4fcdd0a3380517845ba41736c82a79cab535d31128066526f45bffff7f2001000000"), 6),
|
|
|
|
|
'P': deserialize_header(bfh("00000020abe8e119d1877c9dc0dc502d1a253fb9a67967c57732d2f71ee0280e8381ff0a9690c2fe7c1a4450c74dc908fe94dd96c3b0637d51475e9e06a78e944a0c7fe28126f45bffff7f2000000000"), 7),
|
|
|
|
|
'Q': deserialize_header(bfh("000000202ce41d94eb70e1518bc1f72523f84a903f9705d967481e324876e1f8cf4d3452148be228a4c3f2061bafe7efdfc4a8d5a94759464b9b5c619994d45dfcaf49e1a126f45bffff7f2000000000"), 8),
|
|
|
|
|
'R': deserialize_header(bfh("00000020552755b6c59f3d51e361d16281842a4e166007799665b5daed86a063dd89857415681cb2d00ff889193f6a68a93f5096aeb2d84ca0af6185a462555822552221a626f45bffff7f2000000000"), 9),
|
|
|
|
|
'S': deserialize_header(bfh("00000020a13a491cbefc93cd1bb1938f19957e22a134faf14c7dee951c45533e2c750f239dc087fc977b06c24a69c682d1afd1020e6dc1f087571ccec66310a786e1548fab26f45bffff7f2000000000"), 10),
|
|
|
|
|
'T': deserialize_header(bfh("00000020dbf3a9b55dfefbaf8b6e43a89cf833fa2e208bbc0c1c5d76c0d71b9e4a65337803b243756c25053253aeda309604363460a3911015929e68705bd89dff6fe064b026f45bffff7f2002000000"), 11),
|
|
|
|
|
'U': deserialize_header(bfh("000000203d0932b3b0c78eccb39a595a28ae4a7c966388648d7783fd1305ec8d40d4fe5fd67cb902a7d807cee7676cb543feec3e053aa824d5dfb528d5b94f9760313d9db726f45bffff7f2001000000"), 12),
|
|
|
|
|
'G': deserialize_header(bfh("00000020b833ed46eea01d4c980f59feee44a66aa1162748b6801029565d1466790c405c3a141ce635cbb1cd2b3a4fcdd0a3380517845ba41736c82a79cab535d31128066928f45bffff7f2001000000"), 6),
|
|
|
|
|
'H': deserialize_header(bfh("00000020e19e687f6e7f83ca394c114144dbbbc4f3f9c9450f66331a125413702a2e1a719690c2fe7c1a4450c74dc908fe94dd96c3b0637d51475e9e06a78e944a0c7fe26a28f45bffff7f2002000000"), 7),
|
|
|
|
|
'I': deserialize_header(bfh("0000002009dcb3b158293c89d7cf7ceeb513add122ebc3880a850f47afbb2747f5e48c54148be228a4c3f2061bafe7efdfc4a8d5a94759464b9b5c619994d45dfcaf49e16a28f45bffff7f2000000000"), 8),
|
|
|
|
|
'J': deserialize_header(bfh("000000206a65f3bdd3374a5a6c4538008ba0b0a560b8566291f9ef4280ab877627a1742815681cb2d00ff889193f6a68a93f5096aeb2d84ca0af6185a462555822552221c928f45bffff7f2000000000"), 9),
|
|
|
|
|
'K': deserialize_header(bfh("00000020bb3b421653548991998f96f8ba486b652fdb07ca16e9cee30ece033547cd1a6e9dc087fc977b06c24a69c682d1afd1020e6dc1f087571ccec66310a786e1548fca28f45bffff7f2000000000"), 10),
|
|
|
|
|
'L': deserialize_header(bfh("00000020c391d74d37c24a130f4bf4737932bdf9e206dd4fad22860ec5408978eb55d46303b243756c25053253aeda309604363460a3911015929e68705bd89dff6fe064ca28f45bffff7f2000000000"), 11),
|
|
|
|
|
'M': deserialize_header(bfh("000000206a65f3bdd3374a5a6c4538008ba0b0a560b8566291f9ef4280ab877627a1742815681cb2d00ff889193f6a68a93f5096aeb2d84ca0af6185a4625558225522214229f45bffff7f2000000000"), 9),
|
|
|
|
|
'N': deserialize_header(bfh("00000020383dab38b57f98aa9b4f0d5ff868bc674b4828d76766bf048296f4c45fff680a9dc087fc977b06c24a69c682d1afd1020e6dc1f087571ccec66310a786e1548f4329f45bffff7f2003000000"), 10),
|
|
|
|
|
'X': deserialize_header(bfh("0000002067f1857f54b7fef732cb4940f7d1b339472b3514660711a820330fd09d8fba6b03b243756c25053253aeda309604363460a3911015929e68705bd89dff6fe0649b29f45bffff7f2002000000"), 11),
|
|
|
|
|
'Y': deserialize_header(bfh("00000020db33c9768a9e5f7c37d0f09aad88d48165946c87d08f7d63793f07b5c08c527fd67cb902a7d807cee7676cb543feec3e053aa824d5dfb528d5b94f9760313d9d9b29f45bffff7f2000000000"), 12),
|
|
|
|
|
'Z': deserialize_header(bfh("0000002047822b67940e337fda38be6f13390b3596e4dea2549250256879722073824e7f0f2596c29203f8a0f71ae94193092dc8f113be3dbee4579f1e649fa3d6dcc38c622ef45bffff7f2003000000"), 13),
|
|
|
|
|
}
|
|
|
|
|
# tree of headers:
|
|
|
|
|
# - M <- N <- X <- Y <- Z
|
|
|
|
|
# /
|
|
|
|
|
# - G <- H <- I <- J <- K <- L
|
|
|
|
|
# /
|
|
|
|
|
# A <- B <- C <- D <- E <- F <- O <- P <- Q <- R <- S <- T <- U
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def setUpClass(cls):
|
|
|
|
|
super().setUpClass()
|
2024-09-16 15:27:45 +00:00
|
|
|
constants.BitcoinRegtest.set_as_network()
|
2018-11-20 18:57:16 +01:00
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def tearDownClass(cls):
|
|
|
|
|
super().tearDownClass()
|
2025-11-27 18:38:36 +01:00
|
|
|
constants.Palladium.set_as_network()
|
2018-11-20 18:57:16 +01:00
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
super().setUp()
|
2019-09-22 20:46:01 +02:00
|
|
|
self.data_dir = self.electrum_path
|
2018-11-20 18:57:16 +01:00
|
|
|
make_dir(os.path.join(self.data_dir, 'forks'))
|
|
|
|
|
self.config = SimpleConfig({'electrum_path': self.data_dir})
|
|
|
|
|
blockchain.blockchains = {}
|
|
|
|
|
|
|
|
|
|
def _append_header(self, chain: Blockchain, header: dict):
|
|
|
|
|
self.assertTrue(chain.can_connect(header))
|
|
|
|
|
chain.save_header(header)
|
|
|
|
|
|
2019-03-26 21:01:43 +01:00
|
|
|
def test_get_height_of_last_common_block_with_chain(self):
|
|
|
|
|
blockchain.blockchains[constants.net.GENESIS] = chain_u = Blockchain(
|
|
|
|
|
config=self.config, forkpoint=0, parent=None,
|
|
|
|
|
forkpoint_hash=constants.net.GENESIS, prev_hash=None)
|
|
|
|
|
open(chain_u.path(), 'w+').close()
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['A'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['B'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['C'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['D'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['E'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['F'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['O'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['P'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['Q'])
|
|
|
|
|
|
|
|
|
|
chain_l = chain_u.fork(self.HEADERS['G'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['H'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['I'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['J'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['K'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['L'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual({chain_u: 8, chain_l: 5}, chain_u.get_parent_heights())
|
|
|
|
|
self.assertEqual({chain_l: 11}, chain_l.get_parent_heights())
|
|
|
|
|
|
|
|
|
|
chain_z = chain_l.fork(self.HEADERS['M'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['N'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['X'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['Y'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['Z'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual({chain_u: 8, chain_z: 5}, chain_u.get_parent_heights())
|
|
|
|
|
self.assertEqual({chain_l: 11, chain_z: 8}, chain_l.get_parent_heights())
|
|
|
|
|
self.assertEqual({chain_z: 13}, chain_z.get_parent_heights())
|
|
|
|
|
self.assertEqual(5, chain_u.get_height_of_last_common_block_with_chain(chain_l))
|
|
|
|
|
self.assertEqual(5, chain_l.get_height_of_last_common_block_with_chain(chain_u))
|
|
|
|
|
self.assertEqual(5, chain_u.get_height_of_last_common_block_with_chain(chain_z))
|
|
|
|
|
self.assertEqual(5, chain_z.get_height_of_last_common_block_with_chain(chain_u))
|
|
|
|
|
self.assertEqual(8, chain_l.get_height_of_last_common_block_with_chain(chain_z))
|
|
|
|
|
self.assertEqual(8, chain_z.get_height_of_last_common_block_with_chain(chain_l))
|
|
|
|
|
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['R'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['S'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['T'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['U'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual({chain_u: 12, chain_z: 5}, chain_u.get_parent_heights())
|
|
|
|
|
self.assertEqual({chain_l: 11, chain_z: 8}, chain_l.get_parent_heights())
|
|
|
|
|
self.assertEqual({chain_z: 13}, chain_z.get_parent_heights())
|
|
|
|
|
self.assertEqual(5, chain_u.get_height_of_last_common_block_with_chain(chain_l))
|
|
|
|
|
self.assertEqual(5, chain_l.get_height_of_last_common_block_with_chain(chain_u))
|
|
|
|
|
self.assertEqual(5, chain_u.get_height_of_last_common_block_with_chain(chain_z))
|
|
|
|
|
self.assertEqual(5, chain_z.get_height_of_last_common_block_with_chain(chain_u))
|
|
|
|
|
self.assertEqual(8, chain_l.get_height_of_last_common_block_with_chain(chain_z))
|
|
|
|
|
self.assertEqual(8, chain_z.get_height_of_last_common_block_with_chain(chain_l))
|
|
|
|
|
|
2019-03-26 19:43:02 +01:00
|
|
|
def test_parents_after_forking(self):
|
|
|
|
|
blockchain.blockchains[constants.net.GENESIS] = chain_u = Blockchain(
|
|
|
|
|
config=self.config, forkpoint=0, parent=None,
|
|
|
|
|
forkpoint_hash=constants.net.GENESIS, prev_hash=None)
|
|
|
|
|
open(chain_u.path(), 'w+').close()
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['A'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['B'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['C'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['D'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['E'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['F'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['O'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['P'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['Q'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual(None, chain_u.parent)
|
|
|
|
|
|
|
|
|
|
chain_l = chain_u.fork(self.HEADERS['G'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['H'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['I'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['J'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['K'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['L'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual(None, chain_l.parent)
|
|
|
|
|
self.assertEqual(chain_l, chain_u.parent)
|
|
|
|
|
|
|
|
|
|
chain_z = chain_l.fork(self.HEADERS['M'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['N'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['X'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['Y'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['Z'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual(chain_z, chain_u.parent)
|
|
|
|
|
self.assertEqual(chain_z, chain_l.parent)
|
|
|
|
|
self.assertEqual(None, chain_z.parent)
|
|
|
|
|
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['R'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['S'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['T'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['U'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual(chain_z, chain_u.parent)
|
|
|
|
|
self.assertEqual(chain_z, chain_l.parent)
|
|
|
|
|
self.assertEqual(None, chain_z.parent)
|
|
|
|
|
|
2018-11-20 18:57:16 +01:00
|
|
|
def test_forking_and_swapping(self):
|
|
|
|
|
blockchain.blockchains[constants.net.GENESIS] = chain_u = Blockchain(
|
|
|
|
|
config=self.config, forkpoint=0, parent=None,
|
|
|
|
|
forkpoint_hash=constants.net.GENESIS, prev_hash=None)
|
|
|
|
|
open(chain_u.path(), 'w+').close()
|
|
|
|
|
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['A'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['B'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['C'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['D'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['E'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['F'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['O'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['P'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['Q'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['R'])
|
|
|
|
|
|
|
|
|
|
chain_l = chain_u.fork(self.HEADERS['G'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['H'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['I'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['J'])
|
|
|
|
|
|
|
|
|
|
# do checks
|
|
|
|
|
self.assertEqual(2, len(blockchain.blockchains))
|
|
|
|
|
self.assertEqual(1, len(os.listdir(os.path.join(self.data_dir, "forks"))))
|
|
|
|
|
self.assertEqual(0, chain_u.forkpoint)
|
|
|
|
|
self.assertEqual(None, chain_u.parent)
|
|
|
|
|
self.assertEqual(constants.net.GENESIS, chain_u._forkpoint_hash)
|
|
|
|
|
self.assertEqual(None, chain_u._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "blockchain_headers"), chain_u.path())
|
|
|
|
|
self.assertEqual(10 * 80, os.stat(chain_u.path()).st_size)
|
|
|
|
|
self.assertEqual(6, chain_l.forkpoint)
|
|
|
|
|
self.assertEqual(chain_u, chain_l.parent)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['G']), chain_l._forkpoint_hash)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['F']), chain_l._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "forks", "fork2_6_5c400c7966145d56291080b6482716a16aa644eefe590f984c1da0ee46ed33b8_711a2e2a701354121a33660f45c9f9f3c4bbdb4441114c39ca837f6e7f689ee1"), chain_l.path())
|
|
|
|
|
self.assertEqual(4 * 80, os.stat(chain_l.path()).st_size)
|
|
|
|
|
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['K'])
|
|
|
|
|
|
|
|
|
|
# chains were swapped, do checks
|
|
|
|
|
self.assertEqual(2, len(blockchain.blockchains))
|
|
|
|
|
self.assertEqual(1, len(os.listdir(os.path.join(self.data_dir, "forks"))))
|
|
|
|
|
self.assertEqual(6, chain_u.forkpoint)
|
|
|
|
|
self.assertEqual(chain_l, chain_u.parent)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['O']), chain_u._forkpoint_hash)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['F']), chain_u._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "forks", "fork2_6_5c400c7966145d56291080b6482716a16aa644eefe590f984c1da0ee46ed33b8_aff81830e28e01ef7d23277c56779a6b93f251a2d50dcc09d7c87d119e1e8ab"), chain_u.path())
|
|
|
|
|
self.assertEqual(4 * 80, os.stat(chain_u.path()).st_size)
|
|
|
|
|
self.assertEqual(0, chain_l.forkpoint)
|
|
|
|
|
self.assertEqual(None, chain_l.parent)
|
|
|
|
|
self.assertEqual(constants.net.GENESIS, chain_l._forkpoint_hash)
|
|
|
|
|
self.assertEqual(None, chain_l._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "blockchain_headers"), chain_l.path())
|
|
|
|
|
self.assertEqual(11 * 80, os.stat(chain_l.path()).st_size)
|
|
|
|
|
for b in (chain_u, chain_l):
|
2025-06-09 18:59:31 +00:00
|
|
|
self.assertTrue(all([b.can_connect(b.read_header(i), check_height=False) for i in range(b.height())]))
|
2018-11-20 18:57:16 +01:00
|
|
|
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['S'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['T'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['U'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['L'])
|
|
|
|
|
|
|
|
|
|
chain_z = chain_l.fork(self.HEADERS['M'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['N'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['X'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['Y'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['Z'])
|
|
|
|
|
|
|
|
|
|
# chain_z became best chain, do checks
|
|
|
|
|
self.assertEqual(3, len(blockchain.blockchains))
|
|
|
|
|
self.assertEqual(2, len(os.listdir(os.path.join(self.data_dir, "forks"))))
|
|
|
|
|
self.assertEqual(0, chain_z.forkpoint)
|
|
|
|
|
self.assertEqual(None, chain_z.parent)
|
|
|
|
|
self.assertEqual(constants.net.GENESIS, chain_z._forkpoint_hash)
|
|
|
|
|
self.assertEqual(None, chain_z._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "blockchain_headers"), chain_z.path())
|
|
|
|
|
self.assertEqual(14 * 80, os.stat(chain_z.path()).st_size)
|
|
|
|
|
self.assertEqual(9, chain_l.forkpoint)
|
|
|
|
|
self.assertEqual(chain_z, chain_l.parent)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['J']), chain_l._forkpoint_hash)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['I']), chain_l._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "forks", "fork2_9_2874a1277687ab8042eff9916256b860a5b0a08b0038456c5a4a37d3bdf3656a_6e1acd473503ce0ee3cee916ca07db2f656b48baf8968f999189545316423bbb"), chain_l.path())
|
|
|
|
|
self.assertEqual(3 * 80, os.stat(chain_l.path()).st_size)
|
|
|
|
|
self.assertEqual(6, chain_u.forkpoint)
|
|
|
|
|
self.assertEqual(chain_z, chain_u.parent)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['O']), chain_u._forkpoint_hash)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['F']), chain_u._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "forks", "fork2_6_5c400c7966145d56291080b6482716a16aa644eefe590f984c1da0ee46ed33b8_aff81830e28e01ef7d23277c56779a6b93f251a2d50dcc09d7c87d119e1e8ab"), chain_u.path())
|
|
|
|
|
self.assertEqual(7 * 80, os.stat(chain_u.path()).st_size)
|
|
|
|
|
for b in (chain_u, chain_l, chain_z):
|
2025-06-09 18:59:31 +00:00
|
|
|
self.assertTrue(all([b.can_connect(b.read_header(i), check_height=False) for i in range(b.height())]))
|
2018-11-20 18:57:16 +01:00
|
|
|
|
|
|
|
|
self.assertEqual(constants.net.GENESIS, chain_z.get_hash(0))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['F']), chain_z.get_hash(5))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['G']), chain_z.get_hash(6))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['I']), chain_z.get_hash(8))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['M']), chain_z.get_hash(9))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['Z']), chain_z.get_hash(13))
|
|
|
|
|
|
|
|
|
|
def test_doing_multiple_swaps_after_single_new_header(self):
|
|
|
|
|
blockchain.blockchains[constants.net.GENESIS] = chain_u = Blockchain(
|
|
|
|
|
config=self.config, forkpoint=0, parent=None,
|
|
|
|
|
forkpoint_hash=constants.net.GENESIS, prev_hash=None)
|
|
|
|
|
open(chain_u.path(), 'w+').close()
|
|
|
|
|
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['A'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['B'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['C'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['D'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['E'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['F'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['O'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['P'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['Q'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['R'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['S'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual(1, len(blockchain.blockchains))
|
|
|
|
|
self.assertEqual(0, len(os.listdir(os.path.join(self.data_dir, "forks"))))
|
|
|
|
|
|
|
|
|
|
chain_l = chain_u.fork(self.HEADERS['G'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['H'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['I'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['J'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['K'])
|
|
|
|
|
# now chain_u is best chain, but it's tied with chain_l
|
|
|
|
|
|
|
|
|
|
self.assertEqual(2, len(blockchain.blockchains))
|
|
|
|
|
self.assertEqual(1, len(os.listdir(os.path.join(self.data_dir, "forks"))))
|
|
|
|
|
|
|
|
|
|
chain_z = chain_l.fork(self.HEADERS['M'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['N'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['X'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual(3, len(blockchain.blockchains))
|
|
|
|
|
self.assertEqual(2, len(os.listdir(os.path.join(self.data_dir, "forks"))))
|
|
|
|
|
|
|
|
|
|
# chain_z became best chain, do checks
|
|
|
|
|
self.assertEqual(0, chain_z.forkpoint)
|
|
|
|
|
self.assertEqual(None, chain_z.parent)
|
|
|
|
|
self.assertEqual(constants.net.GENESIS, chain_z._forkpoint_hash)
|
|
|
|
|
self.assertEqual(None, chain_z._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "blockchain_headers"), chain_z.path())
|
|
|
|
|
self.assertEqual(12 * 80, os.stat(chain_z.path()).st_size)
|
|
|
|
|
self.assertEqual(9, chain_l.forkpoint)
|
|
|
|
|
self.assertEqual(chain_z, chain_l.parent)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['J']), chain_l._forkpoint_hash)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['I']), chain_l._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "forks", "fork2_9_2874a1277687ab8042eff9916256b860a5b0a08b0038456c5a4a37d3bdf3656a_6e1acd473503ce0ee3cee916ca07db2f656b48baf8968f999189545316423bbb"), chain_l.path())
|
|
|
|
|
self.assertEqual(2 * 80, os.stat(chain_l.path()).st_size)
|
|
|
|
|
self.assertEqual(6, chain_u.forkpoint)
|
|
|
|
|
self.assertEqual(chain_z, chain_u.parent)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['O']), chain_u._forkpoint_hash)
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['F']), chain_u._prev_hash)
|
|
|
|
|
self.assertEqual(os.path.join(self.data_dir, "forks", "fork2_6_5c400c7966145d56291080b6482716a16aa644eefe590f984c1da0ee46ed33b8_aff81830e28e01ef7d23277c56779a6b93f251a2d50dcc09d7c87d119e1e8ab"), chain_u.path())
|
|
|
|
|
self.assertEqual(5 * 80, os.stat(chain_u.path()).st_size)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(constants.net.GENESIS, chain_z.get_hash(0))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['F']), chain_z.get_hash(5))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['G']), chain_z.get_hash(6))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['I']), chain_z.get_hash(8))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['M']), chain_z.get_hash(9))
|
|
|
|
|
self.assertEqual(hash_header(self.HEADERS['X']), chain_z.get_hash(11))
|
|
|
|
|
|
|
|
|
|
for b in (chain_u, chain_l, chain_z):
|
2025-06-09 18:59:31 +00:00
|
|
|
self.assertTrue(all([b.can_connect(b.read_header(i), check_height=False) for i in range(b.height())]))
|
2019-07-28 13:20:42 +02:00
|
|
|
|
2020-06-21 11:31:54 +02:00
|
|
|
def get_chains_that_contain_header_helper(self, header: dict):
|
|
|
|
|
height = header['block_height']
|
|
|
|
|
header_hash = hash_header(header)
|
|
|
|
|
return blockchain.get_chains_that_contain_header(height, header_hash)
|
|
|
|
|
|
|
|
|
|
def test_get_chains_that_contain_header(self):
|
|
|
|
|
blockchain.blockchains[constants.net.GENESIS] = chain_u = Blockchain(
|
|
|
|
|
config=self.config, forkpoint=0, parent=None,
|
|
|
|
|
forkpoint_hash=constants.net.GENESIS, prev_hash=None)
|
|
|
|
|
open(chain_u.path(), 'w+').close()
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['A'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['B'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['C'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['D'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['E'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['F'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['O'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['P'])
|
|
|
|
|
self._append_header(chain_u, self.HEADERS['Q'])
|
|
|
|
|
|
|
|
|
|
chain_l = chain_u.fork(self.HEADERS['G'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['H'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['I'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['J'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['K'])
|
|
|
|
|
self._append_header(chain_l, self.HEADERS['L'])
|
|
|
|
|
|
|
|
|
|
chain_z = chain_l.fork(self.HEADERS['M'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual([chain_l, chain_z, chain_u], self.get_chains_that_contain_header_helper(self.HEADERS['A']))
|
|
|
|
|
self.assertEqual([chain_l, chain_z, chain_u], self.get_chains_that_contain_header_helper(self.HEADERS['C']))
|
|
|
|
|
self.assertEqual([chain_l, chain_z, chain_u], self.get_chains_that_contain_header_helper(self.HEADERS['F']))
|
|
|
|
|
self.assertEqual([chain_l, chain_z], self.get_chains_that_contain_header_helper(self.HEADERS['G']))
|
|
|
|
|
self.assertEqual([chain_l, chain_z], self.get_chains_that_contain_header_helper(self.HEADERS['I']))
|
|
|
|
|
self.assertEqual([chain_z], self.get_chains_that_contain_header_helper(self.HEADERS['M']))
|
|
|
|
|
self.assertEqual([chain_l], self.get_chains_that_contain_header_helper(self.HEADERS['K']))
|
|
|
|
|
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['N'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['X'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['Y'])
|
|
|
|
|
self._append_header(chain_z, self.HEADERS['Z'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual([chain_z, chain_l, chain_u], self.get_chains_that_contain_header_helper(self.HEADERS['A']))
|
|
|
|
|
self.assertEqual([chain_z, chain_l, chain_u], self.get_chains_that_contain_header_helper(self.HEADERS['C']))
|
|
|
|
|
self.assertEqual([chain_z, chain_l, chain_u], self.get_chains_that_contain_header_helper(self.HEADERS['F']))
|
|
|
|
|
self.assertEqual([chain_u], self.get_chains_that_contain_header_helper(self.HEADERS['O']))
|
|
|
|
|
self.assertEqual([chain_z, chain_l], self.get_chains_that_contain_header_helper(self.HEADERS['I']))
|
|
|
|
|
|
blockchain: fix bugs in bits_to_target and target_to_bits
This fixes three bugs:
- too large targets: the fixme in target_to_bits, which meant that we could
not handle targets where the first bit was non-zero. This however cannot
happen due to these being over MAX_TARGET. (difficulty 1)
- too small targets: in bits_to_target, very small targets were not handled well:
```
>>> Blockchain.bits_to_target(0x03008000)
32768
```
We could not process headers with targets smaller than the above value.
(note that these small targets would only occur at astronomically high mining difficulty)
- non-canonically encoded targets:
we would not accept headers that had targets encoded in compact form (nBits) in a non-canonical way.
I think this bug could actually be triggered by mining such a header.
E.g. consider the target "1167130406913723784571467005534932607254396928"
```
Blockchain.target_to_bits(1167130406913723784571467005534932607254396928).to_bytes(4, "big").hex()
'13345600'
```
Bitcoin Core when used to e.g. mine a block would encode this target as 0x13345600 in compact form.
However, AFAICT, when validating Bitcoin Core would equally accept 0x14003456 which decodes to the
same target. We were however rejecting such non-canonical compact nBits.
```
>>> from electrum.blockchain import Blockchain
>>> Blockchain.bits_to_target(0x14003456)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/wspace/electrum/electrum/blockchain.py", line 548, in bits_to_target
raise Exception("Second part of bits should be in [0x8000, 0x7fffff]")
Exception: Second part of bits should be in [0x8000, 0x7fffff]
>>> Blockchain.bits_to_target(0x13345600)
1167130406913723784571467005534932607254396928
```
2021-11-13 04:31:08 +01:00
|
|
|
def test_target_to_bits(self):
|
|
|
|
|
# https://github.com/bitcoin/bitcoin/blob/7fcf53f7b4524572d1d0c9a5fdc388e87eb02416/src/arith_uint256.h#L269
|
|
|
|
|
self.assertEqual(0x05123456, Blockchain.target_to_bits(0x1234560000))
|
|
|
|
|
self.assertEqual(0x0600c0de, Blockchain.target_to_bits(0xc0de000000))
|
|
|
|
|
|
|
|
|
|
# tests from https://github.com/bitcoin/bitcoin/blob/a7d17daa5cd8bf6398d5f8d7e77290009407d6ea/src/test/arith_uint256_tests.cpp#L411
|
|
|
|
|
tuples = (
|
|
|
|
|
(0, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x00123456, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x01003456, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x02000056, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x03000000, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x04000000, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x00923456, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x01803456, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x02800056, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x03800000, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x04800000, 0x0000000000000000000000000000000000000000000000000000000000000000, 0),
|
|
|
|
|
(0x01123456, 0x0000000000000000000000000000000000000000000000000000000000000012, 0x01120000),
|
|
|
|
|
(0x02123456, 0x0000000000000000000000000000000000000000000000000000000000001234, 0x02123400),
|
|
|
|
|
(0x03123456, 0x0000000000000000000000000000000000000000000000000000000000123456, 0x03123456),
|
|
|
|
|
(0x04123456, 0x0000000000000000000000000000000000000000000000000000000012345600, 0x04123456),
|
|
|
|
|
(0x05009234, 0x0000000000000000000000000000000000000000000000000000000092340000, 0x05009234),
|
|
|
|
|
(0x20123456, 0x1234560000000000000000000000000000000000000000000000000000000000, 0x20123456),
|
|
|
|
|
)
|
|
|
|
|
for nbits1, target, nbits2 in tuples:
|
|
|
|
|
with self.subTest(original_compact_nbits=nbits1.to_bytes(length=4, byteorder="big").hex()):
|
|
|
|
|
num = Blockchain.bits_to_target(nbits1)
|
|
|
|
|
self.assertEqual(target, num)
|
|
|
|
|
self.assertEqual(nbits2, Blockchain.target_to_bits(num))
|
|
|
|
|
|
|
|
|
|
# Make sure that we don't generate compacts with the 0x00800000 bit set
|
|
|
|
|
self.assertEqual(0x02008000, Blockchain.target_to_bits(0x80))
|
|
|
|
|
|
2023-04-23 02:00:50 +00:00
|
|
|
with self.assertRaises(InvalidHeader): # target cannot be negative
|
blockchain: fix bugs in bits_to_target and target_to_bits
This fixes three bugs:
- too large targets: the fixme in target_to_bits, which meant that we could
not handle targets where the first bit was non-zero. This however cannot
happen due to these being over MAX_TARGET. (difficulty 1)
- too small targets: in bits_to_target, very small targets were not handled well:
```
>>> Blockchain.bits_to_target(0x03008000)
32768
```
We could not process headers with targets smaller than the above value.
(note that these small targets would only occur at astronomically high mining difficulty)
- non-canonically encoded targets:
we would not accept headers that had targets encoded in compact form (nBits) in a non-canonical way.
I think this bug could actually be triggered by mining such a header.
E.g. consider the target "1167130406913723784571467005534932607254396928"
```
Blockchain.target_to_bits(1167130406913723784571467005534932607254396928).to_bytes(4, "big").hex()
'13345600'
```
Bitcoin Core when used to e.g. mine a block would encode this target as 0x13345600 in compact form.
However, AFAICT, when validating Bitcoin Core would equally accept 0x14003456 which decodes to the
same target. We were however rejecting such non-canonical compact nBits.
```
>>> from electrum.blockchain import Blockchain
>>> Blockchain.bits_to_target(0x14003456)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/wspace/electrum/electrum/blockchain.py", line 548, in bits_to_target
raise Exception("Second part of bits should be in [0x8000, 0x7fffff]")
Exception: Second part of bits should be in [0x8000, 0x7fffff]
>>> Blockchain.bits_to_target(0x13345600)
1167130406913723784571467005534932607254396928
```
2021-11-13 04:31:08 +01:00
|
|
|
Blockchain.bits_to_target(0x01fedcba)
|
2023-04-23 02:00:50 +00:00
|
|
|
with self.assertRaises(InvalidHeader): # target cannot be negative
|
blockchain: fix bugs in bits_to_target and target_to_bits
This fixes three bugs:
- too large targets: the fixme in target_to_bits, which meant that we could
not handle targets where the first bit was non-zero. This however cannot
happen due to these being over MAX_TARGET. (difficulty 1)
- too small targets: in bits_to_target, very small targets were not handled well:
```
>>> Blockchain.bits_to_target(0x03008000)
32768
```
We could not process headers with targets smaller than the above value.
(note that these small targets would only occur at astronomically high mining difficulty)
- non-canonically encoded targets:
we would not accept headers that had targets encoded in compact form (nBits) in a non-canonical way.
I think this bug could actually be triggered by mining such a header.
E.g. consider the target "1167130406913723784571467005534932607254396928"
```
Blockchain.target_to_bits(1167130406913723784571467005534932607254396928).to_bytes(4, "big").hex()
'13345600'
```
Bitcoin Core when used to e.g. mine a block would encode this target as 0x13345600 in compact form.
However, AFAICT, when validating Bitcoin Core would equally accept 0x14003456 which decodes to the
same target. We were however rejecting such non-canonical compact nBits.
```
>>> from electrum.blockchain import Blockchain
>>> Blockchain.bits_to_target(0x14003456)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/wspace/electrum/electrum/blockchain.py", line 548, in bits_to_target
raise Exception("Second part of bits should be in [0x8000, 0x7fffff]")
Exception: Second part of bits should be in [0x8000, 0x7fffff]
>>> Blockchain.bits_to_target(0x13345600)
1167130406913723784571467005534932607254396928
```
2021-11-13 04:31:08 +01:00
|
|
|
Blockchain.bits_to_target(0x04923456)
|
2023-04-23 02:00:50 +00:00
|
|
|
with self.assertRaises(InvalidHeader): # overflow
|
blockchain: fix bugs in bits_to_target and target_to_bits
This fixes three bugs:
- too large targets: the fixme in target_to_bits, which meant that we could
not handle targets where the first bit was non-zero. This however cannot
happen due to these being over MAX_TARGET. (difficulty 1)
- too small targets: in bits_to_target, very small targets were not handled well:
```
>>> Blockchain.bits_to_target(0x03008000)
32768
```
We could not process headers with targets smaller than the above value.
(note that these small targets would only occur at astronomically high mining difficulty)
- non-canonically encoded targets:
we would not accept headers that had targets encoded in compact form (nBits) in a non-canonical way.
I think this bug could actually be triggered by mining such a header.
E.g. consider the target "1167130406913723784571467005534932607254396928"
```
Blockchain.target_to_bits(1167130406913723784571467005534932607254396928).to_bytes(4, "big").hex()
'13345600'
```
Bitcoin Core when used to e.g. mine a block would encode this target as 0x13345600 in compact form.
However, AFAICT, when validating Bitcoin Core would equally accept 0x14003456 which decodes to the
same target. We were however rejecting such non-canonical compact nBits.
```
>>> from electrum.blockchain import Blockchain
>>> Blockchain.bits_to_target(0x14003456)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/wspace/electrum/electrum/blockchain.py", line 548, in bits_to_target
raise Exception("Second part of bits should be in [0x8000, 0x7fffff]")
Exception: Second part of bits should be in [0x8000, 0x7fffff]
>>> Blockchain.bits_to_target(0x13345600)
1167130406913723784571467005534932607254396928
```
2021-11-13 04:31:08 +01:00
|
|
|
Blockchain.bits_to_target(0xff123456)
|
|
|
|
|
|
2019-07-28 13:20:42 +02:00
|
|
|
|
2019-09-22 20:46:01 +02:00
|
|
|
class TestVerifyHeader(ElectrumTestCase):
|
2019-07-28 13:20:42 +02:00
|
|
|
|
|
|
|
|
# Data for Bitcoin block header #100.
|
|
|
|
|
valid_header = "0100000095194b8567fe2e8bbda931afd01a7acd399b9325cb54683e64129bcd00000000660802c98f18fd34fd16d61c63cf447568370124ac5f3be626c2e1c3c9f0052d19a76949ffff001d33f3c25d"
|
|
|
|
|
target = Blockchain.bits_to_target(0x1d00ffff)
|
|
|
|
|
prev_hash = "00000000cd9b12643e6854cb25939b39cd7a1ad0af31a9bd8b2efe67854b1995"
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
super().setUp()
|
|
|
|
|
self.header = deserialize_header(bfh(self.valid_header), 100)
|
|
|
|
|
|
|
|
|
|
def test_valid_header(self):
|
|
|
|
|
Blockchain.verify_header(self.header, self.prev_hash, self.target)
|
|
|
|
|
|
|
|
|
|
def test_expected_hash_mismatch(self):
|
2023-04-23 02:00:50 +00:00
|
|
|
with self.assertRaises(InvalidHeader):
|
2019-07-28 13:20:42 +02:00
|
|
|
Blockchain.verify_header(self.header, self.prev_hash, self.target,
|
|
|
|
|
expected_header_hash="foo")
|
|
|
|
|
|
|
|
|
|
def test_prev_hash_mismatch(self):
|
2023-04-23 02:00:50 +00:00
|
|
|
with self.assertRaises(InvalidHeader):
|
2019-07-28 13:20:42 +02:00
|
|
|
Blockchain.verify_header(self.header, "foo", self.target)
|
|
|
|
|
|
|
|
|
|
def test_target_mismatch(self):
|
2023-04-23 02:00:50 +00:00
|
|
|
with self.assertRaises(InvalidHeader):
|
2019-07-28 13:20:42 +02:00
|
|
|
other_target = Blockchain.bits_to_target(0x1d00eeee)
|
|
|
|
|
Blockchain.verify_header(self.header, self.prev_hash, other_target)
|
|
|
|
|
|
|
|
|
|
def test_insufficient_pow(self):
|
2023-04-23 02:00:50 +00:00
|
|
|
with self.assertRaises(InvalidHeader):
|
2019-07-28 13:20:42 +02:00
|
|
|
self.header["nonce"] = 42
|
|
|
|
|
Blockchain.verify_header(self.header, self.prev_hash, self.target)
|