Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_p2p_avalanche_transaction_voting.py
Show All 22 Lines | |||||
from test_framework.wallet import MiniWallet | from test_framework.wallet import MiniWallet | ||||
QUORUM_NODE_COUNT = 16 | QUORUM_NODE_COUNT = 16 | ||||
class AvalancheTransactionVotingTest(BitcoinTestFramework): | class AvalancheTransactionVotingTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.extra_args = [[ | self.extra_args = [ | ||||
'-avalanchepreconsensus=1', | [ | ||||
'-avacooldown=0', | "-avalanchepreconsensus=1", | ||||
'-avaproofstakeutxoconfirmations=1', | "-avacooldown=0", | ||||
"-avaproofstakeutxoconfirmations=1", | |||||
# Low enough for coinbase transactions to be staked in valid proofs | # Low enough for coinbase transactions to be staked in valid proofs | ||||
'-avaproofstakeutxodustthreshold=1000000', | "-avaproofstakeutxodustthreshold=1000000", | ||||
'-avaminquorumstake=0', | "-avaminquorumstake=0", | ||||
'-avaminavaproofsnodecount=0', | "-avaminavaproofsnodecount=0", | ||||
'-whitelist=noban@127.0.0.1', | "-whitelist=noban@127.0.0.1", | ||||
]] | ] | ||||
] | |||||
def run_test(self): | def run_test(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
poll_node = get_ava_p2p_interface(self, node) | poll_node = get_ava_p2p_interface(self, node) | ||||
# Create helper to check expected poll responses | # Create helper to check expected poll responses | ||||
avakey = ECPubKey() | avakey = ECPubKey() | ||||
avakey.set(bytes.fromhex(node.getavalanchekey())) | avakey.set(bytes.fromhex(node.getavalanchekey())) | ||||
Show All 14 Lines | def run_test(self): | ||||
# Make some valid txs | # Make some valid txs | ||||
num_txs = 5 | num_txs = 5 | ||||
wallet = MiniWallet(node) | wallet = MiniWallet(node) | ||||
self.generate(wallet, num_txs, sync_fun=self.no_op) | self.generate(wallet, num_txs, sync_fun=self.no_op) | ||||
# Mature the coinbases | # Mature the coinbases | ||||
self.generate(node, 100, sync_fun=self.no_op) | self.generate(node, 100, sync_fun=self.no_op) | ||||
assert_equal(node.getmempoolinfo()['size'], 0) | assert_equal(node.getmempoolinfo()["size"], 0) | ||||
tx_ids = [int(wallet.send_self_transfer(from_node=node) | tx_ids = [ | ||||
['txid'], 16) for _ in range(num_txs)] | int(wallet.send_self_transfer(from_node=node)["txid"], 16) | ||||
assert_equal(node.getmempoolinfo()['size'], num_txs) | for _ in range(num_txs) | ||||
] | |||||
assert_equal(node.getmempoolinfo()["size"], num_txs) | |||||
self.log.info( | self.log.info("Check the votes are unknown while the quorum is not established") | ||||
"Check the votes are unknown while the quorum is not established") | |||||
poll_node.send_poll(tx_ids, MSG_TX) | poll_node.send_poll(tx_ids, MSG_TX) | ||||
assert_response( | assert_response( | ||||
[AvalancheVote(AvalancheTxVoteError.UNKNOWN, txid) for txid in tx_ids]) | [AvalancheVote(AvalancheTxVoteError.UNKNOWN, txid) for txid in tx_ids] | ||||
) | |||||
self.log.info("Check the votes on valid mempool transactions") | self.log.info("Check the votes on valid mempool transactions") | ||||
def get_quorum(): | def get_quorum(): | ||||
return [get_ava_p2p_interface(self, node) | return [ | ||||
for _ in range(0, QUORUM_NODE_COUNT)] | get_ava_p2p_interface(self, node) for _ in range(0, QUORUM_NODE_COUNT) | ||||
] | |||||
_ = get_quorum() | _ = get_quorum() | ||||
poll_node.send_poll(tx_ids, MSG_TX) | poll_node.send_poll(tx_ids, MSG_TX) | ||||
assert_response( | assert_response( | ||||
[AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids]) | [AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids] | ||||
) | |||||
self.log.info("Check the votes on recently mined transactions") | self.log.info("Check the votes on recently mined transactions") | ||||
self.generate(node, 1, sync_fun=self.no_op) | self.generate(node, 1, sync_fun=self.no_op) | ||||
assert_equal(node.getmempoolinfo()['size'], 0) | assert_equal(node.getmempoolinfo()["size"], 0) | ||||
poll_node.send_poll(tx_ids, MSG_TX) | poll_node.send_poll(tx_ids, MSG_TX) | ||||
assert_response( | assert_response( | ||||
[AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids]) | [AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids] | ||||
) | |||||
for _ in range(10): | for _ in range(10): | ||||
self.generate(node, 1, sync_fun=self.no_op) | self.generate(node, 1, sync_fun=self.no_op) | ||||
poll_node.send_poll(tx_ids, MSG_TX) | poll_node.send_poll(tx_ids, MSG_TX) | ||||
assert_response( | assert_response( | ||||
[AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids]) | [AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids] | ||||
) | |||||
self.log.info("Check the votes on unknown transactions") | self.log.info("Check the votes on unknown transactions") | ||||
tx_ids = [random.randint(0, 2**256) for _ in range(10)] | tx_ids = [random.randint(0, 2**256) for _ in range(10)] | ||||
poll_node.send_poll(tx_ids, MSG_TX) | poll_node.send_poll(tx_ids, MSG_TX) | ||||
assert_response( | assert_response( | ||||
[AvalancheVote(AvalancheTxVoteError.UNKNOWN, txid) for txid in tx_ids]) | [AvalancheVote(AvalancheTxVoteError.UNKNOWN, txid) for txid in tx_ids] | ||||
) | |||||
self.log.info("Check the votes on invalid transactions") | self.log.info("Check the votes on invalid transactions") | ||||
invalid_tx = CTransaction() | invalid_tx = CTransaction() | ||||
invalid_txid = int(invalid_tx.get_id(), 16) | invalid_txid = int(invalid_tx.get_id(), 16) | ||||
with node.assert_debug_log(["bad-txns-vin-empty", "Misbehaving"], []): | with node.assert_debug_log(["bad-txns-vin-empty", "Misbehaving"], []): | ||||
# The node has the NOBAN whitelist flag, so it remains connected | # The node has the NOBAN whitelist flag, so it remains connected | ||||
poll_node.send_message(msg_tx(invalid_tx)) | poll_node.send_message(msg_tx(invalid_tx)) | ||||
poll_node.send_poll([invalid_txid], MSG_TX) | poll_node.send_poll([invalid_txid], MSG_TX) | ||||
assert_response( | assert_response([AvalancheVote(AvalancheTxVoteError.INVALID, invalid_txid)]) | ||||
[AvalancheVote(AvalancheTxVoteError.INVALID, invalid_txid)]) | |||||
self.log.info("Check the votes on orphan transactions") | self.log.info("Check the votes on orphan transactions") | ||||
orphan_tx = CTransaction() | orphan_tx = CTransaction() | ||||
orphan_tx.vin.append( | orphan_tx.vin.append(CTxIn(outpoint=COutPoint(random.randint(0, 2**256), 0))) | ||||
CTxIn(outpoint=COutPoint(random.randint(0, 2**256), 0))) | |||||
orphan_tx.vout = [ | orphan_tx.vout = [ | ||||
CTxOut( | CTxOut(nValue=1_000_000, scriptPubKey=wallet.get_scriptPubKey()) | ||||
nValue=1_000_000, | ] | ||||
scriptPubKey=wallet.get_scriptPubKey())] | |||||
pad_tx(orphan_tx) | pad_tx(orphan_tx) | ||||
orphan_txid = int(orphan_tx.get_id(), 16) | orphan_txid = int(orphan_tx.get_id(), 16) | ||||
with node.assert_debug_log(["bad-txns-inputs-missingorspent"], []): | with node.assert_debug_log(["bad-txns-inputs-missingorspent"], []): | ||||
poll_node.send_message(msg_tx(orphan_tx)) | poll_node.send_message(msg_tx(orphan_tx)) | ||||
poll_node.send_poll([orphan_txid], MSG_TX) | poll_node.send_poll([orphan_txid], MSG_TX) | ||||
assert_response( | assert_response([AvalancheVote(AvalancheTxVoteError.ORPHAN, orphan_txid)]) | ||||
[AvalancheVote(AvalancheTxVoteError.ORPHAN, orphan_txid)]) | |||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
AvalancheTransactionVotingTest().main() | AvalancheTransactionVotingTest().main() |