2019-04-04 08:18:04 +02:00
|
|
|
#!/usr/bin/env python3
|
2023-12-31 01:00:00 +01:00
|
|
|
# Copyright (c) 2015-2024 The Dash Core developers
|
2019-04-04 08:18:04 +02:00
|
|
|
# Distributed under the MIT software license, see the accompanying
|
|
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
'''
|
2020-07-17 01:44:20 +02:00
|
|
|
feature_dip4_coinbasemerkleroots.py
|
2019-04-04 08:18:04 +02:00
|
|
|
|
|
|
|
Checks DIP4 merkle roots in coinbases
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
Merge #13054: tests: Enable automatic detection of undefined names in Python tests scripts. Remove wildcard imports.
68400d8b96 tests: Use explicit imports (practicalswift)
Pull request description:
Enable automatic detection of undefined names in Python tests scripts. Remove wildcard imports.
Wildcard imports make it unclear which names are present in the namespace, confusing both readers and many automated tools.
An additional benefit of not using wildcard imports in tests scripts is that readers of a test script then can infer the rough testing scope just by looking at the imports.
Before this commit:
```
$ contrib/devtools/lint-python.sh | head -10
./test/functional/feature_rbf.py:8:1: F403 'from test_framework.util import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:9:1: F403 'from test_framework.script import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:10:1: F403 'from test_framework.mininode import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:15:12: F405 bytes_to_hex_str may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:17:58: F405 CScript may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:25:13: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:26:31: F405 satoshi_round may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:26:60: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:30:41: F405 satoshi_round may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:30:68: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
$
```
After this commit:
```
$ contrib/devtools/lint-python.sh | head -10
$
```
Tree-SHA512: 3f826d39cffb6438388e5efcb20a9622ff8238247e882d68f7b38609877421b2a8e10e9229575f8eb6a8fa42dec4256986692e92922c86171f750a0e887438d9
2018-08-13 14:24:43 +02:00
|
|
|
from io import BytesIO
|
|
|
|
|
2021-06-24 12:47:04 +02:00
|
|
|
from test_framework.messages import CBlock, CBlockHeader, CCbTx, CMerkleBlock, from_hex, hash256, msg_getmnlistd, QuorumId, ser_uint256
|
2024-01-15 20:35:29 +01:00
|
|
|
from test_framework.p2p import P2PInterface
|
Merge #13054: tests: Enable automatic detection of undefined names in Python tests scripts. Remove wildcard imports.
68400d8b96 tests: Use explicit imports (practicalswift)
Pull request description:
Enable automatic detection of undefined names in Python tests scripts. Remove wildcard imports.
Wildcard imports make it unclear which names are present in the namespace, confusing both readers and many automated tools.
An additional benefit of not using wildcard imports in tests scripts is that readers of a test script then can infer the rough testing scope just by looking at the imports.
Before this commit:
```
$ contrib/devtools/lint-python.sh | head -10
./test/functional/feature_rbf.py:8:1: F403 'from test_framework.util import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:9:1: F403 'from test_framework.script import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:10:1: F403 'from test_framework.mininode import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:15:12: F405 bytes_to_hex_str may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:17:58: F405 CScript may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:25:13: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:26:31: F405 satoshi_round may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:26:60: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:30:41: F405 satoshi_round may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:30:68: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
$
```
After this commit:
```
$ contrib/devtools/lint-python.sh | head -10
$
```
Tree-SHA512: 3f826d39cffb6438388e5efcb20a9622ff8238247e882d68f7b38609877421b2a8e10e9229575f8eb6a8fa42dec4256986692e92922c86171f750a0e887438d9
2018-08-13 14:24:43 +02:00
|
|
|
from test_framework.test_framework import DashTestFramework
|
2020-08-27 08:21:53 +02:00
|
|
|
from test_framework.util import assert_equal
|
Merge #13054: tests: Enable automatic detection of undefined names in Python tests scripts. Remove wildcard imports.
68400d8b96 tests: Use explicit imports (practicalswift)
Pull request description:
Enable automatic detection of undefined names in Python tests scripts. Remove wildcard imports.
Wildcard imports make it unclear which names are present in the namespace, confusing both readers and many automated tools.
An additional benefit of not using wildcard imports in tests scripts is that readers of a test script then can infer the rough testing scope just by looking at the imports.
Before this commit:
```
$ contrib/devtools/lint-python.sh | head -10
./test/functional/feature_rbf.py:8:1: F403 'from test_framework.util import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:9:1: F403 'from test_framework.script import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:10:1: F403 'from test_framework.mininode import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:15:12: F405 bytes_to_hex_str may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:17:58: F405 CScript may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:25:13: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:26:31: F405 satoshi_round may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:26:60: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:30:41: F405 satoshi_round may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:30:68: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
$
```
After this commit:
```
$ contrib/devtools/lint-python.sh | head -10
$
```
Tree-SHA512: 3f826d39cffb6438388e5efcb20a9622ff8238247e882d68f7b38609877421b2a8e10e9229575f8eb6a8fa42dec4256986692e92922c86171f750a0e887438d9
2018-08-13 14:24:43 +02:00
|
|
|
|
2024-08-08 13:26:14 +02:00
|
|
|
DIP0008_HEIGHT = 432
|
2024-10-09 09:42:14 +02:00
|
|
|
DIP0024_HEIGHT = 900
|
Merge #13054: tests: Enable automatic detection of undefined names in Python tests scripts. Remove wildcard imports.
68400d8b96 tests: Use explicit imports (practicalswift)
Pull request description:
Enable automatic detection of undefined names in Python tests scripts. Remove wildcard imports.
Wildcard imports make it unclear which names are present in the namespace, confusing both readers and many automated tools.
An additional benefit of not using wildcard imports in tests scripts is that readers of a test script then can infer the rough testing scope just by looking at the imports.
Before this commit:
```
$ contrib/devtools/lint-python.sh | head -10
./test/functional/feature_rbf.py:8:1: F403 'from test_framework.util import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:9:1: F403 'from test_framework.script import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:10:1: F403 'from test_framework.mininode import *' used; unable to detect undefined names
./test/functional/feature_rbf.py:15:12: F405 bytes_to_hex_str may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:17:58: F405 CScript may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:25:13: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:26:31: F405 satoshi_round may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:26:60: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:30:41: F405 satoshi_round may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
./test/functional/feature_rbf.py:30:68: F405 COIN may be undefined, or defined from star imports: test_framework.mininode, test_framework.script, test_framework.util
$
```
After this commit:
```
$ contrib/devtools/lint-python.sh | head -10
$
```
Tree-SHA512: 3f826d39cffb6438388e5efcb20a9622ff8238247e882d68f7b38609877421b2a8e10e9229575f8eb6a8fa42dec4256986692e92922c86171f750a0e887438d9
2018-08-13 14:24:43 +02:00
|
|
|
|
2020-08-27 08:21:53 +02:00
|
|
|
# TODO: this helper used in many tests, find a new home for it
|
2020-07-09 11:31:01 +02:00
|
|
|
class TestP2PConn(P2PInterface):
|
2019-04-04 08:18:04 +02:00
|
|
|
def __init__(self):
|
2019-05-20 19:01:39 +02:00
|
|
|
super().__init__()
|
2019-04-04 08:18:04 +02:00
|
|
|
self.last_mnlistdiff = None
|
|
|
|
|
2020-04-05 13:12:45 +02:00
|
|
|
def on_mnlistdiff(self, message):
|
2019-04-04 08:18:04 +02:00
|
|
|
self.last_mnlistdiff = message
|
|
|
|
|
|
|
|
def wait_for_mnlistdiff(self, timeout=30):
|
|
|
|
def received_mnlistdiff():
|
|
|
|
return self.last_mnlistdiff is not None
|
2020-08-27 08:21:53 +02:00
|
|
|
self.wait_until(received_mnlistdiff, timeout=timeout)
|
2019-04-04 08:18:04 +02:00
|
|
|
|
|
|
|
def getmnlistdiff(self, baseBlockHash, blockHash):
|
|
|
|
msg = msg_getmnlistd(baseBlockHash, blockHash)
|
2020-01-22 11:35:47 +01:00
|
|
|
self.last_mnlistdiff = None
|
2019-04-04 08:18:04 +02:00
|
|
|
self.send_message(msg)
|
|
|
|
self.wait_for_mnlistdiff()
|
|
|
|
return self.last_mnlistdiff
|
|
|
|
|
|
|
|
|
|
|
|
class LLMQCoinbaseCommitmentsTest(DashTestFramework):
|
2019-09-24 00:57:30 +02:00
|
|
|
def set_test_params(self):
|
2024-10-09 09:42:14 +02:00
|
|
|
self.extra_args = [[ f'-testactivationheight=dip0008@{DIP0008_HEIGHT}', f'-testactivationheight=dip0024@{DIP0024_HEIGHT}', "-vbparams=testdummy:999999999999:999999999999" ]] * 4
|
2024-08-27 12:30:39 +02:00
|
|
|
self.set_dash_test_params(4, 3, extra_args = self.extra_args)
|
2024-11-21 10:57:44 +01:00
|
|
|
|
|
|
|
def remove_masternode(self, idx):
|
|
|
|
mn = self.mninfo[idx]
|
|
|
|
rawtx = self.nodes[0].createrawtransaction([{"txid": mn.collateral_txid, "vout": mn.collateral_vout}], {self.nodes[0].getnewaddress(): 999.9999})
|
|
|
|
rawtx = self.nodes[0].signrawtransactionwithwallet(rawtx)
|
|
|
|
self.nodes[0].sendrawtransaction(rawtx["hex"])
|
|
|
|
self.generate(self.nodes[0], 1)
|
|
|
|
self.mninfo.remove(mn)
|
|
|
|
|
|
|
|
self.log.info("Removed masternode %d", idx)
|
|
|
|
|
2019-04-04 08:18:04 +02:00
|
|
|
def run_test(self):
|
2023-06-21 05:49:41 +02:00
|
|
|
# No IS or Chainlocks in this test
|
|
|
|
self.bump_mocktime(1)
|
|
|
|
self.nodes[0].sporkupdate("SPORK_2_INSTANTSEND_ENABLED", 4070908800)
|
|
|
|
self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", 4070908800)
|
|
|
|
self.wait_for_sporks_same()
|
|
|
|
|
2020-07-09 11:31:01 +02:00
|
|
|
self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn())
|
2019-04-04 08:18:04 +02:00
|
|
|
|
|
|
|
self.confirm_mns()
|
|
|
|
|
|
|
|
null_hash = format(0, "064x")
|
|
|
|
|
|
|
|
# Check if a diff with the genesis block as base returns all MNs
|
|
|
|
expectedUpdated = [mn.proTxHash for mn in self.mninfo]
|
|
|
|
mnList = self.test_getmnlistdiff(null_hash, self.nodes[0].getbestblockhash(), {}, [], expectedUpdated)
|
|
|
|
expectedUpdated2 = expectedUpdated + []
|
|
|
|
|
|
|
|
# Register one more MN, but don't start it (that would fail as DashTestFramework doesn't support this atm)
|
|
|
|
baseBlockHash = self.nodes[0].getbestblockhash()
|
|
|
|
self.prepare_masternode(self.mn_count)
|
|
|
|
new_mn = self.mninfo[self.mn_count]
|
|
|
|
|
|
|
|
# Now test if that MN appears in a diff when the base block is the one just before MN registration
|
|
|
|
expectedDeleted = []
|
|
|
|
expectedUpdated = [new_mn.proTxHash]
|
|
|
|
mnList = self.test_getmnlistdiff(baseBlockHash, self.nodes[0].getbestblockhash(), mnList, expectedDeleted, expectedUpdated)
|
2021-08-27 21:03:02 +02:00
|
|
|
assert mnList[new_mn.proTxHash].confirmedHash == 0
|
2019-04-04 08:18:04 +02:00
|
|
|
# Now let the MN get enough confirmations and verify that the MNLISTDIFF now has confirmedHash != 0
|
|
|
|
self.confirm_mns()
|
|
|
|
mnList = self.test_getmnlistdiff(baseBlockHash, self.nodes[0].getbestblockhash(), mnList, expectedDeleted, expectedUpdated)
|
2021-08-27 21:03:02 +02:00
|
|
|
assert mnList[new_mn.proTxHash].confirmedHash != 0
|
2019-04-04 08:18:04 +02:00
|
|
|
|
2019-04-04 11:46:52 +02:00
|
|
|
# Spend the collateral of the previously added MN and test if it appears in "deletedMNs"
|
2019-04-04 08:18:04 +02:00
|
|
|
expectedDeleted = [new_mn.proTxHash]
|
|
|
|
expectedUpdated = []
|
|
|
|
baseBlockHash2 = self.nodes[0].getbestblockhash()
|
2021-01-14 21:00:57 +01:00
|
|
|
self.remove_masternode(self.mn_count)
|
2019-04-04 08:18:04 +02:00
|
|
|
mnList = self.test_getmnlistdiff(baseBlockHash2, self.nodes[0].getbestblockhash(), mnList, expectedDeleted, expectedUpdated)
|
|
|
|
|
|
|
|
# When comparing genesis and best block, we shouldn't see the previously added and then deleted MN
|
|
|
|
mnList = self.test_getmnlistdiff(null_hash, self.nodes[0].getbestblockhash(), {}, [], expectedUpdated2)
|
|
|
|
|
2019-04-04 08:18:24 +02:00
|
|
|
#############################
|
|
|
|
# Now start testing quorum commitment merkle roots
|
|
|
|
|
2024-10-01 21:22:56 +02:00
|
|
|
self.generate(self.nodes[0], 1, sync_fun=self.no_op)
|
2019-04-04 17:38:23 +02:00
|
|
|
oldhash = self.nodes[0].getbestblockhash()
|
2023-06-21 05:49:41 +02:00
|
|
|
|
2019-04-04 08:18:24 +02:00
|
|
|
# Test DIP8 activation once with a pre-existing quorum and once without (we don't know in which order it will activate on mainnet)
|
|
|
|
self.test_dip8_quorum_merkle_root_activation(True)
|
|
|
|
for n in self.nodes:
|
2019-04-04 17:38:23 +02:00
|
|
|
n.invalidateblock(oldhash)
|
|
|
|
self.sync_all()
|
2021-01-08 20:56:32 +01:00
|
|
|
first_quorum = self.test_dip8_quorum_merkle_root_activation(False, True)
|
2019-04-04 08:18:24 +02:00
|
|
|
|
|
|
|
# Verify that the first quorum appears in MNLISTDIFF
|
|
|
|
expectedDeleted = []
|
2023-02-20 00:05:54 +01:00
|
|
|
expectedNew = [QuorumId(100, int(first_quorum, 16)), QuorumId(104, int(first_quorum, 16)), QuorumId(106, int(first_quorum, 16))]
|
2019-04-04 08:18:24 +02:00
|
|
|
quorumList = self.test_getmnlistdiff_quorums(null_hash, self.nodes[0].getbestblockhash(), {}, expectedDeleted, expectedNew)
|
|
|
|
baseBlockHash = self.nodes[0].getbestblockhash()
|
|
|
|
|
|
|
|
second_quorum = self.mine_quorum()
|
|
|
|
|
|
|
|
# Verify that the second quorum appears in MNLISTDIFF
|
|
|
|
expectedDeleted = []
|
2023-02-20 00:05:54 +01:00
|
|
|
expectedNew = [QuorumId(100, int(second_quorum, 16)), QuorumId(104, int(second_quorum, 16)), QuorumId(106, int(second_quorum, 16))]
|
2019-04-04 08:18:24 +02:00
|
|
|
quorums_before_third = self.test_getmnlistdiff_quorums(baseBlockHash, self.nodes[0].getbestblockhash(), quorumList, expectedDeleted, expectedNew)
|
|
|
|
block_before_third = self.nodes[0].getbestblockhash()
|
|
|
|
|
|
|
|
third_quorum = self.mine_quorum()
|
|
|
|
|
|
|
|
# Verify that the first quorum is deleted and the third quorum is added in MNLISTDIFF (the first got inactive)
|
2023-02-20 00:05:54 +01:00
|
|
|
expectedDeleted = [QuorumId(100, int(first_quorum, 16)), QuorumId(104, int(first_quorum, 16)), QuorumId(106, int(first_quorum, 16))]
|
|
|
|
expectedNew = [QuorumId(100, int(third_quorum, 16)), QuorumId(104, int(third_quorum, 16)), QuorumId(106, int(third_quorum, 16))]
|
2019-04-04 08:18:24 +02:00
|
|
|
self.test_getmnlistdiff_quorums(block_before_third, self.nodes[0].getbestblockhash(), quorums_before_third, expectedDeleted, expectedNew)
|
|
|
|
|
|
|
|
# Verify that the diff between genesis and best block is the current active set (second and third quorum)
|
|
|
|
expectedDeleted = []
|
2023-02-20 00:05:54 +01:00
|
|
|
expectedNew = [QuorumId(100, int(second_quorum, 16)), QuorumId(104, int(second_quorum, 16)), QuorumId(106, int(second_quorum, 16)), QuorumId(100, int(third_quorum, 16)), QuorumId(104, int(third_quorum, 16)), QuorumId(106, int(third_quorum, 16))]
|
2019-04-04 08:18:24 +02:00
|
|
|
self.test_getmnlistdiff_quorums(null_hash, self.nodes[0].getbestblockhash(), {}, expectedDeleted, expectedNew)
|
|
|
|
|
|
|
|
# Now verify that diffs are correct around the block that mined the third quorum.
|
|
|
|
# This tests the logic in CalcCbTxMerkleRootQuorums, which has to manually add the commitment from the current
|
|
|
|
# block
|
|
|
|
mined_in_block = self.nodes[0].quorum("info", 100, third_quorum)["minedBlock"]
|
|
|
|
prev_block = self.nodes[0].getblock(mined_in_block)["previousblockhash"]
|
|
|
|
prev_block2 = self.nodes[0].getblock(prev_block)["previousblockhash"]
|
|
|
|
next_block = self.nodes[0].getblock(mined_in_block)["nextblockhash"]
|
|
|
|
next_block2 = self.nodes[0].getblock(mined_in_block)["nextblockhash"]
|
|
|
|
# The 2 block before the quorum was mined should both give an empty diff
|
|
|
|
expectedDeleted = []
|
|
|
|
expectedNew = []
|
|
|
|
self.test_getmnlistdiff_quorums(block_before_third, prev_block2, quorums_before_third, expectedDeleted, expectedNew)
|
|
|
|
self.test_getmnlistdiff_quorums(block_before_third, prev_block, quorums_before_third, expectedDeleted, expectedNew)
|
|
|
|
# The block in which the quorum was mined and the 2 after that should all give the same diff
|
2023-02-20 00:05:54 +01:00
|
|
|
expectedDeleted = [QuorumId(100, int(first_quorum, 16)), QuorumId(104, int(first_quorum, 16)), QuorumId(106, int(first_quorum, 16))]
|
|
|
|
expectedNew = [QuorumId(100, int(third_quorum, 16)), QuorumId(104, int(third_quorum, 16)), QuorumId(106, int(third_quorum, 16))]
|
2019-04-04 08:18:24 +02:00
|
|
|
quorums_with_third = self.test_getmnlistdiff_quorums(block_before_third, mined_in_block, quorums_before_third, expectedDeleted, expectedNew)
|
|
|
|
self.test_getmnlistdiff_quorums(block_before_third, next_block, quorums_before_third, expectedDeleted, expectedNew)
|
|
|
|
self.test_getmnlistdiff_quorums(block_before_third, next_block2, quorums_before_third, expectedDeleted, expectedNew)
|
|
|
|
# A diff between the two block that happened after the quorum was mined should give an empty diff
|
|
|
|
expectedDeleted = []
|
|
|
|
expectedNew = []
|
|
|
|
self.test_getmnlistdiff_quorums(mined_in_block, next_block, quorums_with_third, expectedDeleted, expectedNew)
|
|
|
|
self.test_getmnlistdiff_quorums(mined_in_block, next_block2, quorums_with_third, expectedDeleted, expectedNew)
|
|
|
|
self.test_getmnlistdiff_quorums(next_block, next_block2, quorums_with_third, expectedDeleted, expectedNew)
|
|
|
|
|
|
|
|
# Using the same block for baseBlockHash and blockHash should give empty diffs
|
|
|
|
self.test_getmnlistdiff_quorums(prev_block, prev_block, quorums_before_third, expectedDeleted, expectedNew)
|
|
|
|
self.test_getmnlistdiff_quorums(prev_block2, prev_block2, quorums_before_third, expectedDeleted, expectedNew)
|
|
|
|
self.test_getmnlistdiff_quorums(mined_in_block, mined_in_block, quorums_with_third, expectedDeleted, expectedNew)
|
|
|
|
self.test_getmnlistdiff_quorums(next_block, next_block, quorums_with_third, expectedDeleted, expectedNew)
|
|
|
|
self.test_getmnlistdiff_quorums(next_block2, next_block2, quorums_with_third, expectedDeleted, expectedNew)
|
|
|
|
|
|
|
|
|
2019-04-04 08:18:04 +02:00
|
|
|
def test_getmnlistdiff(self, baseBlockHash, blockHash, baseMNList, expectedDeleted, expectedUpdated):
|
|
|
|
d = self.test_getmnlistdiff_base(baseBlockHash, blockHash)
|
|
|
|
|
|
|
|
# Assert that the deletedMNs and mnList fields are what we expected
|
|
|
|
assert_equal(set(d.deletedMNs), set([int(e, 16) for e in expectedDeleted]))
|
|
|
|
assert_equal(set([e.proRegTxHash for e in d.mnList]), set(int(e, 16) for e in expectedUpdated))
|
|
|
|
|
|
|
|
# Build a new list based on the old list and the info from the diff
|
|
|
|
newMNList = baseMNList.copy()
|
|
|
|
for e in d.deletedMNs:
|
|
|
|
newMNList.pop(format(e, '064x'))
|
|
|
|
for e in d.mnList:
|
|
|
|
newMNList[format(e.proRegTxHash, '064x')] = e
|
|
|
|
|
|
|
|
cbtx = CCbTx()
|
|
|
|
cbtx.deserialize(BytesIO(d.cbTx.vExtraPayload))
|
|
|
|
|
|
|
|
# Verify that the merkle root matches what we locally calculate
|
|
|
|
hashes = []
|
|
|
|
for mn in sorted(newMNList.values(), key=lambda mn: ser_uint256(mn.proRegTxHash)):
|
2023-06-11 19:29:00 +02:00
|
|
|
hashes.append(hash256(mn.serialize(with_version = False)))
|
2019-04-04 08:18:04 +02:00
|
|
|
merkleRoot = CBlock.get_merkle_root(hashes)
|
|
|
|
assert_equal(merkleRoot, cbtx.merkleRootMNList)
|
|
|
|
|
|
|
|
return newMNList
|
|
|
|
|
2019-04-04 08:18:24 +02:00
|
|
|
def test_getmnlistdiff_quorums(self, baseBlockHash, blockHash, baseQuorumList, expectedDeleted, expectedNew):
|
|
|
|
d = self.test_getmnlistdiff_base(baseBlockHash, blockHash)
|
|
|
|
|
|
|
|
assert_equal(set(d.deletedQuorums), set(expectedDeleted))
|
|
|
|
assert_equal(set([QuorumId(e.llmqType, e.quorumHash) for e in d.newQuorums]), set(expectedNew))
|
|
|
|
|
|
|
|
newQuorumList = baseQuorumList.copy()
|
|
|
|
|
|
|
|
for e in d.deletedQuorums:
|
|
|
|
newQuorumList.pop(e)
|
|
|
|
|
|
|
|
for e in d.newQuorums:
|
|
|
|
newQuorumList[QuorumId(e.llmqType, e.quorumHash)] = e
|
|
|
|
|
|
|
|
cbtx = CCbTx()
|
|
|
|
cbtx.deserialize(BytesIO(d.cbTx.vExtraPayload))
|
|
|
|
|
2024-11-01 13:16:42 +01:00
|
|
|
if cbtx.nVersion >= 2:
|
2019-04-04 08:18:24 +02:00
|
|
|
hashes = []
|
|
|
|
for qc in newQuorumList.values():
|
|
|
|
hashes.append(hash256(qc.serialize()))
|
|
|
|
hashes.sort()
|
|
|
|
merkleRoot = CBlock.get_merkle_root(hashes)
|
|
|
|
assert_equal(merkleRoot, cbtx.merkleRootQuorums)
|
|
|
|
|
|
|
|
return newQuorumList
|
|
|
|
|
|
|
|
|
2019-04-04 08:18:04 +02:00
|
|
|
def test_getmnlistdiff_base(self, baseBlockHash, blockHash):
|
|
|
|
hexstr = self.nodes[0].getblockheader(blockHash, False)
|
2021-06-24 12:47:04 +02:00
|
|
|
header = from_hex(CBlockHeader(), hexstr)
|
2019-04-04 08:18:04 +02:00
|
|
|
|
|
|
|
d = self.test_node.getmnlistdiff(int(baseBlockHash, 16), int(blockHash, 16))
|
|
|
|
assert_equal(d.baseBlockHash, int(baseBlockHash, 16))
|
|
|
|
assert_equal(d.blockHash, int(blockHash, 16))
|
|
|
|
|
|
|
|
# Check that the merkle proof is valid
|
|
|
|
proof = CMerkleBlock(header, d.merkleProof)
|
|
|
|
proof = proof.serialize().hex()
|
|
|
|
assert_equal(self.nodes[0].verifytxoutproof(proof), [d.cbTx.hash])
|
|
|
|
|
|
|
|
# Check if P2P messages match with RPCs
|
|
|
|
d2 = self.nodes[0].protx("diff", baseBlockHash, blockHash)
|
|
|
|
assert_equal(d2["baseBlockHash"], baseBlockHash)
|
|
|
|
assert_equal(d2["blockHash"], blockHash)
|
|
|
|
assert_equal(d2["cbTxMerkleTree"], d.merkleProof.serialize().hex())
|
|
|
|
assert_equal(d2["cbTx"], d.cbTx.serialize().hex())
|
|
|
|
assert_equal(set([int(e, 16) for e in d2["deletedMNs"]]), set(d.deletedMNs))
|
|
|
|
assert_equal(set([int(e["proRegTxHash"], 16) for e in d2["mnList"]]), set([e.proRegTxHash for e in d.mnList]))
|
2019-04-04 08:18:24 +02:00
|
|
|
assert_equal(set([QuorumId(e["llmqType"], int(e["quorumHash"], 16)) for e in d2["deletedQuorums"]]), set(d.deletedQuorums))
|
|
|
|
assert_equal(set([QuorumId(e["llmqType"], int(e["quorumHash"], 16)) for e in d2["newQuorums"]]), set([QuorumId(e.llmqType, e.quorumHash) for e in d.newQuorums]))
|
2019-04-04 08:18:04 +02:00
|
|
|
|
|
|
|
return d
|
|
|
|
|
2024-08-08 13:26:14 +02:00
|
|
|
def activate_dip8(self, slow_mode=False):
|
|
|
|
# NOTE: set slow_mode=True if you are activating dip8 after a huge reorg
|
|
|
|
# or nodes might fail to catch up otherwise due to a large
|
|
|
|
# (MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16 blocks) reorg error.
|
|
|
|
self.log.info("Wait for dip0008 activation")
|
|
|
|
while self.nodes[0].getblockcount() < DIP0008_HEIGHT:
|
|
|
|
self.bump_mocktime(10)
|
2024-10-01 21:22:56 +02:00
|
|
|
self.generate(self.nodes[0], 10, sync_fun=self.no_op)
|
2024-08-08 13:26:14 +02:00
|
|
|
if slow_mode:
|
|
|
|
self.sync_blocks()
|
|
|
|
self.sync_blocks()
|
|
|
|
|
2021-01-08 20:56:32 +01:00
|
|
|
def test_dip8_quorum_merkle_root_activation(self, with_initial_quorum, slow_mode=False):
|
2019-04-04 08:18:24 +02:00
|
|
|
if with_initial_quorum:
|
2022-06-18 18:52:45 +02:00
|
|
|
self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 0)
|
2019-04-04 08:18:24 +02:00
|
|
|
self.wait_for_sporks_same()
|
|
|
|
|
|
|
|
# Mine one quorum before dip8 is activated
|
|
|
|
self.mine_quorum()
|
|
|
|
|
2022-06-18 18:52:45 +02:00
|
|
|
self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 4070908800)
|
2019-04-04 08:18:24 +02:00
|
|
|
self.wait_for_sporks_same()
|
|
|
|
|
|
|
|
cbtx = self.nodes[0].getblock(self.nodes[0].getbestblockhash(), 2)["tx"][0]
|
2021-08-27 21:03:02 +02:00
|
|
|
assert cbtx["cbTx"]["version"] == 1
|
2019-04-04 08:18:24 +02:00
|
|
|
|
2021-01-08 20:56:32 +01:00
|
|
|
self.activate_dip8(slow_mode)
|
2019-04-04 08:18:24 +02:00
|
|
|
|
|
|
|
# Assert that merkleRootQuorums is present and 0 (we have no quorums yet)
|
|
|
|
cbtx = self.nodes[0].getblock(self.nodes[0].getbestblockhash(), 2)["tx"][0]
|
|
|
|
assert_equal(cbtx["cbTx"]["version"], 2)
|
2021-08-27 21:03:02 +02:00
|
|
|
assert "merkleRootQuorums" in cbtx["cbTx"]
|
2019-04-04 08:18:24 +02:00
|
|
|
merkleRootQuorums = int(cbtx["cbTx"]["merkleRootQuorums"], 16)
|
|
|
|
|
|
|
|
if with_initial_quorum:
|
2021-08-27 21:03:02 +02:00
|
|
|
assert merkleRootQuorums != 0
|
2019-04-04 08:18:24 +02:00
|
|
|
else:
|
|
|
|
assert_equal(merkleRootQuorums, 0)
|
|
|
|
|
2019-08-09 01:14:11 +02:00
|
|
|
self.bump_mocktime(1)
|
2022-06-18 18:52:45 +02:00
|
|
|
self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 0)
|
2019-04-04 08:18:24 +02:00
|
|
|
self.wait_for_sporks_same()
|
|
|
|
|
|
|
|
# Mine quorum and verify that merkleRootQuorums has changed
|
|
|
|
quorum = self.mine_quorum()
|
|
|
|
cbtx = self.nodes[0].getblock(self.nodes[0].getbestblockhash(), 2)["tx"][0]
|
2021-08-27 21:03:02 +02:00
|
|
|
assert int(cbtx["cbTx"]["merkleRootQuorums"], 16) != merkleRootQuorums
|
2019-04-04 08:18:24 +02:00
|
|
|
|
|
|
|
return quorum
|
|
|
|
|
2019-04-04 08:18:04 +02:00
|
|
|
def confirm_mns(self):
|
|
|
|
while True:
|
|
|
|
diff = self.nodes[0].protx("diff", 1, self.nodes[0].getblockcount())
|
|
|
|
found_unconfirmed = False
|
|
|
|
for mn in diff["mnList"]:
|
|
|
|
if int(mn["confirmedHash"], 16) == 0:
|
|
|
|
found_unconfirmed = True
|
|
|
|
break
|
|
|
|
if not found_unconfirmed:
|
|
|
|
break
|
2024-10-01 21:22:56 +02:00
|
|
|
self.generate(self.nodes[0], 1, sync_fun=self.no_op)
|
2020-04-14 12:00:16 +02:00
|
|
|
self.sync_blocks()
|
2019-04-04 08:18:04 +02:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
LLMQCoinbaseCommitmentsTest().main()
|