|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# Copyright (c) 2018 The Navcoin Core developers |
| 3 | +# Distributed under the MIT software license, see the accompanying |
| 4 | +# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
| 5 | + |
| 6 | +from test_framework.test_framework import NavCoinTestFramework |
| 7 | +from test_framework.cfund_util import * |
| 8 | + |
| 9 | +import time |
| 10 | +import http.client |
| 11 | +import urllib.parse |
| 12 | + |
| 13 | +class CommunityFundPaymentRequestDuplicate(NavCoinTestFramework): |
| 14 | + """Tests the payment request procedures of the Community fund.""" |
| 15 | + |
| 16 | + def __init__(self): |
| 17 | + super().__init__() |
| 18 | + self.setup_clean_chain = True |
| 19 | + self.num_nodes = 2 |
| 20 | + |
| 21 | + def setup_network(self, split=False): |
| 22 | + self.nodes = [] |
| 23 | + |
| 24 | + self.nodes.append(start_node(0, self.options.tmpdir, [])) |
| 25 | + self.nodes.append(start_node(1, self.options.tmpdir, [])) |
| 26 | + |
| 27 | + connect_nodes(self.nodes[0], 1) |
| 28 | + |
| 29 | + self.is_network_split = split |
| 30 | + |
| 31 | + def run_test(self): |
| 32 | + |
| 33 | + activate_cfund(self.nodes[0]) |
| 34 | + self.nodes[0].donatefund(100000) |
| 35 | + |
| 36 | + sync_blocks(self.nodes) |
| 37 | + |
| 38 | + balance = self.nodes[0].getbalance() |
| 39 | + |
| 40 | + balanceSplit = float(balance / self.num_nodes) |
| 41 | + |
| 42 | + addresses = [] |
| 43 | + |
| 44 | + for x in range(self.num_nodes): |
| 45 | + addresses.append(self.nodes[x].getnewaddress()) |
| 46 | + self.nodes[0].sendtoaddress(addresses[x], balanceSplit) |
| 47 | + |
| 48 | + slow_gen(self.nodes[0], 1) |
| 49 | + |
| 50 | + sync_blocks(self.nodes) |
| 51 | + |
| 52 | + for x in range(self.num_nodes): |
| 53 | + assert(self.nodes[x].getbalance() >= balanceSplit) |
| 54 | + |
| 55 | + SATOSHI = 100000000 |
| 56 | + |
| 57 | + proposals = [{},{},{},{},{}] |
| 58 | + |
| 59 | + # internships |
| 60 | + proposals[0]["address"] = self.nodes[0].getnewaddress() |
| 61 | + proposals[0]["amount"] = 10000 |
| 62 | + proposals[0]["preqs"] = [{"amount": 3333}] |
| 63 | + |
| 64 | + # beekart posters |
| 65 | + proposals[1]["address"] = self.nodes[0].getnewaddress() |
| 66 | + proposals[1]["amount"] = 5000 |
| 67 | + proposals[1]["preqs"] = [{"amount": 5000}] |
| 68 | + |
| 69 | + # vinyl stickers |
| 70 | + proposals[2]["address"] = self.nodes[0].getnewaddress() |
| 71 | + proposals[2]["amount"] = 2000 |
| 72 | + proposals[2]["preqs"] = [{"amount": 2000}] |
| 73 | + |
| 74 | + # nio italia |
| 75 | + proposals[3]["address"] = self.nodes[0].getnewaddress() |
| 76 | + proposals[3]["amount"] = 1000 |
| 77 | + proposals[3]["preqs"] = [{"amount": 1000}] |
| 78 | + |
| 79 | + # cryptocandor video |
| 80 | + proposals[4]["address"] = self.nodes[0].getnewaddress() |
| 81 | + proposals[4]["amount"] = 5500 |
| 82 | + proposals[4]["preqs"] = [{"amount": 2500}, {"amount": 2000}] |
| 83 | + |
| 84 | + # Create proposals |
| 85 | + for proposal in proposals: |
| 86 | + proposal["proposalHash"] = self.nodes[0].createproposal(proposal["address"], proposal["amount"], 36000, "proposal description")["hash"] |
| 87 | + |
| 88 | + end_cycle(self.nodes[0]) |
| 89 | + sync_blocks(self.nodes) |
| 90 | + |
| 91 | + # Accept the proposals |
| 92 | + for proposal in proposals: |
| 93 | + self.nodes[0].proposalvote(proposal["proposalHash"], "yes") |
| 94 | + |
| 95 | + slow_gen(self.nodes[0], 1) |
| 96 | + end_cycle(self.nodes[0]) |
| 97 | + |
| 98 | + locked_accepted = self.nodes[0].cfundstats()["funds"]["locked"] |
| 99 | + |
| 100 | + sync_blocks(self.nodes) |
| 101 | + |
| 102 | + # Check proposals are accepted on all nodes |
| 103 | + for x in range(self.num_nodes): |
| 104 | + locked_tallied = 0 |
| 105 | + for proposal in proposals: |
| 106 | + assert(self.nodes[x].getproposal(proposal["proposalHash"])["state"] == 1) |
| 107 | + assert(self.nodes[x].getproposal(proposal["proposalHash"])["status"] == "accepted") |
| 108 | + locked_tallied += float(self.nodes[x].getproposal(proposal["proposalHash"])["requestedAmount"]) |
| 109 | + assert(locked_accepted == locked_tallied) |
| 110 | + |
| 111 | + # Create payment requests for all the proposals |
| 112 | + |
| 113 | + for proposal in proposals: |
| 114 | + for preq in proposal["preqs"]: |
| 115 | + preq["hash"] = self.nodes[0].createpaymentrequest(proposal["proposalHash"], preq["amount"], "payment request description")["hash"] |
| 116 | + |
| 117 | + slow_gen(self.nodes[0], 1) |
| 118 | + sync_blocks(self.nodes) |
| 119 | + |
| 120 | + # Check payment requests are present on all nodes |
| 121 | + |
| 122 | + for x in range(self.num_nodes): |
| 123 | + for proposal in proposals: |
| 124 | + for preq in proposal["preqs"]: |
| 125 | + assert(self.nodes[x].getpaymentrequest(preq["hash"])["state"] == 0) |
| 126 | + assert(self.nodes[x].getpaymentrequest(preq["hash"])["status"] == "pending") |
| 127 | + assert(self.nodes[x].cfundstats()["funds"]["locked"] == locked_accepted) |
| 128 | + |
| 129 | + end_cycle(self.nodes[0]) |
| 130 | + |
| 131 | + # vote yes for the payment requests |
| 132 | + |
| 133 | + for proposal in proposals: |
| 134 | + for preq in proposal["preqs"]: |
| 135 | + self.nodes[0].paymentrequestvote(preq["hash"], "yes") |
| 136 | + |
| 137 | + slow_gen(self.nodes[0], 1) |
| 138 | + end_cycle(self.nodes[0]) |
| 139 | + sync_blocks(self.nodes) |
| 140 | + |
| 141 | + for x in range(self.num_nodes): |
| 142 | + for proposal in proposals: |
| 143 | + for preq in proposal["preqs"]: |
| 144 | + assert(self.nodes[x].getpaymentrequest(preq["hash"])["state"] == 1) |
| 145 | + assert(self.nodes[x].getpaymentrequest(preq["hash"])["paidOnBlock"] == "0000000000000000000000000000000000000000000000000000000000000000") |
| 146 | + |
| 147 | + |
| 148 | + |
| 149 | + wallet_info1 = self.nodes[0].getwalletinfo() |
| 150 | + |
| 151 | + while self.nodes[0].getpaymentrequest(proposals[0]["preqs"][0]["hash"])["paidOnBlock"] == "0000000000000000000000000000000000000000000000000000000000000000": |
| 152 | + blocks = slow_gen(self.nodes[0], 1) |
| 153 | + |
| 154 | + sync_blocks(self.nodes) |
| 155 | + |
| 156 | + wallet_info2 = self.nodes[0].getwalletinfo() |
| 157 | + |
| 158 | + # check all wallets see the payout |
| 159 | + |
| 160 | + |
| 161 | + for x in range(self.num_nodes): |
| 162 | + paymentsFound = 0 |
| 163 | + preqsFound = 0 |
| 164 | + for proposal in proposals: |
| 165 | + for preq in proposal["preqs"]: |
| 166 | + preqsFound += 1 |
| 167 | + payoutBlockHash = self.nodes[x].getpaymentrequest(preq["hash"])["paidOnBlock"] |
| 168 | + payoutBlock = self.nodes[x].getblock(payoutBlockHash) |
| 169 | + payoutHex = self.nodes[x].getrawtransaction(payoutBlock["tx"][0]) |
| 170 | + payoutTx = self.nodes[x].decoderawtransaction(payoutHex) |
| 171 | + |
| 172 | + for vout in payoutTx["vout"]: |
| 173 | + if vout["scriptPubKey"]["addresses"][0] == proposal["address"] and vout["valueSat"] == preq["amount"] * SATOSHI: |
| 174 | + paymentsFound += 1 |
| 175 | + |
| 176 | + assert(paymentsFound == 6) |
| 177 | + assert(preqsFound == 6) |
| 178 | + |
| 179 | + # check node zero received the payout |
| 180 | + |
| 181 | + lastTransactions = self.nodes[0].listtransactions("", 7) |
| 182 | + |
| 183 | + # print(lastTransactions) |
| 184 | + txFound = 0 |
| 185 | + preqsFound = 0 |
| 186 | + |
| 187 | + for tx in lastTransactions: |
| 188 | + for proposal in proposals: |
| 189 | + for preq in proposal["preqs"]: |
| 190 | + preqsFound += 1 |
| 191 | + if tx["address"] == proposal["address"] and int(tx["amount"] * SATOSHI) == int(preq["amount"] * SATOSHI): |
| 192 | + assert(tx["category"] == "immature") |
| 193 | + assert(tx["confirmations"] == 1) |
| 194 | + txFound += 1 |
| 195 | + |
| 196 | + assert(txFound == 6) |
| 197 | + |
| 198 | + # disconnect the nodes mine blocks on each |
| 199 | + url = urllib.parse.urlparse(self.nodes[1].url) |
| 200 | + self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1))) |
| 201 | + |
| 202 | + blocks0 = self.nodes[0].getblockchaininfo()["blocks"] |
| 203 | + blocks1 = self.nodes[1].getblockchaininfo()["blocks"] |
| 204 | + |
| 205 | + slow_gen(self.nodes[0], 2) |
| 206 | + slow_gen(self.nodes[1], 1) |
| 207 | + |
| 208 | + assert(self.nodes[0].getblockchaininfo()["blocks"] == blocks0 + 2) |
| 209 | + assert(self.nodes[1].getblockchaininfo()["blocks"] == blocks1 + 1) |
| 210 | + assert(self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash()) |
| 211 | + |
| 212 | + # reconnect the node making node 1 reorg |
| 213 | + connect_nodes_bi(self.nodes,0,1) |
| 214 | + sync_blocks(self.nodes) |
| 215 | + |
| 216 | + assert(self.nodes[0].getblockchaininfo()["blocks"] == blocks0 + 2) |
| 217 | + assert(self.nodes[1].getblockchaininfo()["blocks"] == blocks1 + 2) |
| 218 | + assert(self.nodes[0].getbestblockhash() == self.nodes[1].getbestblockhash()) |
| 219 | + |
| 220 | + slow_gen(self.nodes[1], 1) |
| 221 | + |
| 222 | + bestblockHash = self.nodes[1].getbestblockhash() |
| 223 | + bestBlock = self.nodes[1].getblock(bestblockHash) |
| 224 | + |
| 225 | + # Check that the only tx in the block is the block reward |
| 226 | + |
| 227 | + assert(len(bestBlock["tx"]) == 1) |
| 228 | + |
| 229 | +if __name__ == '__main__': |
| 230 | + CommunityFundPaymentRequestDuplicate().main() |
0 commit comments