diff --git a/src/esperanza/walletextension.cpp b/src/esperanza/walletextension.cpp index f6aa099122..bb0ea4b255 100644 --- a/src/esperanza/walletextension.cpp +++ b/src/esperanza/walletextension.cpp @@ -128,8 +128,8 @@ CAmount WalletExtension::GetRemoteStakingBalance() const { for (size_t i = 0; i < tx->tx->vout.size(); ++i) { const CTxOut &txout = tx->tx->vout[i]; - if (m_enclosing_wallet.IsSpent(hashTx, i)) { - continue; + if (m_enclosing_wallet.IsSpent(hashTx, i)) { + continue; } if (::IsStakedRemotely(m_enclosing_wallet, txout.scriptPubKey)) { balance += txout.nValue; diff --git a/test/functional/feature_remote_staking.py b/test/functional/feature_remote_staking.py index 24bb4a2c95..1eef3b52da 100755 --- a/test/functional/feature_remote_staking.py +++ b/test/functional/feature_remote_staking.py @@ -2,11 +2,38 @@ # Copyright (c) 2019 The Unit-e Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from test_framework.mininode import sha256 -from test_framework.regtest_mnemonics import regtest_mnemonics -from test_framework.script import CScript, OP_2, hash160 -from test_framework.test_framework import UnitETestFramework, STAKE_SPLIT_THRESHOLD -from test_framework.util import assert_equal, assert_greater_than, bytes_to_hex_str, hex_str_to_bytes, wait_until +from test_framework.blocktools import ( + create_block, + create_coinbase, + get_tip_snapshot_meta, + sign_coinbase, +) +from test_framework.mininode import ( + msg_witness_block, + network_thread_start, + P2PInterface, + sha256, +) +from test_framework.regtest_mnemonics import ( + regtest_mnemonics, +) +from test_framework.script import ( + CScript, + OP_2, + hash160, +) +from test_framework.test_framework import ( + UnitETestFramework, + PROPOSER_REWARD, + STAKE_SPLIT_THRESHOLD, +) +from test_framework.util import ( + assert_equal, + assert_greater_than, + bytes_to_hex_str, + hex_str_to_bytes, + wait_until, +) def stake_p2wsh(node, staking_node, amount): @@ -18,33 +45,68 @@ def stake_p2wsh(node, staking_node, amount): staking_node: the node which will be able to stake nodes amount: the amount to send """ - multisig = node.addmultisigaddress(2, [node.getnewaddress(), node.getnewaddress()]) + multisig = node.addmultisigaddress( + 2, [node.getnewaddress(), node.getnewaddress()]) bare = CScript(hex_str_to_bytes(multisig['redeemScript'])) spending_script_hash = sha256(bare) - addr_info = staking_node.validateaddress(staking_node.getnewaddress('', 'legacy')) + addr_info = staking_node.validateaddress( + staking_node.getnewaddress('', 'legacy')) staking_key_hash = hash160(hex_str_to_bytes(addr_info['pubkey'])) rs_p2wsh = CScript([OP_2, staking_key_hash, spending_script_hash]) - outputs = [{'address': 'script', 'amount': amount, 'script': bytes_to_hex_str(rs_p2wsh)}] + outputs = [{'address': 'script', 'amount': amount, + 'script': bytes_to_hex_str(rs_p2wsh)}] node.sendtypeto('unite', 'unite', outputs) +def build_block_with_remote_stake(node): + height = node.getblockcount() + snapshot_meta = get_tip_snapshot_meta(node) + stakes = node.liststakeablecoins() + + coin = stakes['stakeable_coins'][0]['coin'] + pubkey = hex_str_to_bytes(coin['script_pub_key']['hex']) + stake = { + 'txid': coin['out_point']['txid'], + 'vout': coin['out_point']['n'], + 'amount': coin['amount'], + } + + tip = int(node.getbestblockhash(), 16) + block_time = node.getblock( + node.getbestblockhash())['time'] + 1 + coinbase = sign_coinbase( + node, create_coinbase( + height, stake, snapshot_meta.hash, raw_pubkey=pubkey)) + + return create_block(tip, coinbase, block_time) + + class RemoteStakingTest(UnitETestFramework): def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True - self.extra_args=[ + self.extra_args = [ [], ['-minimumchainwork=0', '-maxtipage=1000000000'] ] + self.customchainparams = [ + {"stake_maturity": 1, "stake_maturity_activation_height": 2}] * 2 def run_test(self): alice, bob = self.nodes alice.importmasterkey(regtest_mnemonics[0]['mnemonics']) + bob.add_p2p_connection(P2PInterface()) + network_thread_start() + + self.log.info("Waiting untill the P2P connection is fully up...") + bob.p2p.wait_for_verack() + alice.generate(1) - assert_equal(len(alice.listunspent()), regtest_mnemonics[0]['balance'] / STAKE_SPLIT_THRESHOLD) + assert_equal(len(alice.listunspent()), + regtest_mnemonics[0]['balance'] / STAKE_SPLIT_THRESHOLD) alices_addr = alice.getnewaddress() @@ -73,8 +135,18 @@ def bob_is_staking_the_new_coin(): return ps['wallets'][0]['stakeable_balance'] == 2 wait_until(bob_is_staking_the_new_coin, timeout=10) + # Generate block with remote stake + block = build_block_with_remote_stake(bob) + bob.p2p.send_and_ping(msg_witness_block(block)) + self.sync_all() + + # Stake vout must be ignored in 'remote_staking_balance' + wi = alice.getwalletinfo() + assert_equal(wi['remote_staking_balance'], 2 + PROPOSER_REWARD) + # Change outputs for both staked coins, and the balance staked remotely - assert_equal(len(alice.listunspent()), 2 + (regtest_mnemonics[0]['balance'] // STAKE_SPLIT_THRESHOLD)) + assert_equal(len(alice.listunspent()), 2 + + (regtest_mnemonics[0]['balance'] // STAKE_SPLIT_THRESHOLD)) if __name__ == '__main__': diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index edddb50471..7eff418130 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -69,7 +69,7 @@ def serialize_script_num(value): # If pubkey is passed in, the coinbase outputs will be P2PK outputs; # otherwise anyone-can-spend outputs. The first output is the reward, # which is not spendable for COINBASE_MATURITY blocks. -def create_coinbase(height, stake, snapshot_hash, pubkey = None, n_pieces = 1): +def create_coinbase(height, stake, snapshot_hash, pubkey = None, raw_pubkey = None, n_pieces = 1): assert n_pieces > 0 stake_in = COutPoint(int(stake['txid'], 16), stake['vout']) coinbase = CTransaction() @@ -81,6 +81,8 @@ def create_coinbase(height, stake, snapshot_hash, pubkey = None, n_pieces = 1): output_script = None if (pubkey != None): output_script = CScript([pubkey, OP_CHECKSIG]) + elif (raw_pubkey != None): + output_script = CScript(raw_pubkey) else: output_script = CScript([OP_TRUE])