Skip to content

Commit 7ef765b

Browse files
Merge pull request #413 from craigmacgregor/v452
v452 Hard Fork
2 parents a6782c3 + 2905593 commit 7ef765b

File tree

13 files changed

+602
-23
lines changed

13 files changed

+602
-23
lines changed

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
22
AC_PREREQ([2.60])
33
define(_CLIENT_VERSION_MAJOR, 4)
44
define(_CLIENT_VERSION_MINOR, 5)
5-
define(_CLIENT_VERSION_REVISION, 1)
5+
define(_CLIENT_VERSION_REVISION, 2)
66
define(_CLIENT_VERSION_BUILD, 0)
77
define(_CLIENT_VERSION_IS_RELEASE, true)
88
define(_CLIENT_BUILD_IS_TEST_RELEASE, false)

qa/pull-tester/rpc-tests.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@
150150
'cfund-donate.py',
151151
'cfund-listproposals.py',
152152
'cfund-paymentrequest-extract-funds.py',
153+
'cfund-paymentrequest-payout.py',
154+
'cfund-paymentrequest-duplicate.py',
155+
'cfund-paymentrequest-hardfork-452.py',
153156
'cfund-paymentrequest-state-accept.py',
154157
'cfund-paymentrequest-state-accept-expired-proposal.py',
155158
'cfund-paymentrequest-state-expired.py',
@@ -168,6 +171,7 @@
168171
'coldstaking_spending.py',
169172
'staticr-staking-amount.py',
170173
'hardfork-451.py',
174+
'hardfork-452.py',
171175
'staticr-tx-send.py',
172176

173177
'sendtoaddress.py',
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
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()
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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.hardfork_util import *
8+
from test_framework.cfund_util import *
9+
10+
class PaymentRequest452(NavCoinTestFramework):
11+
"""Tests whether payment requests can be double paid before and after the hardfork."""
12+
13+
def __init__(self):
14+
super().__init__()
15+
self.setup_clean_chain = True
16+
self.num_nodes = 1
17+
18+
def setup_network(self, split=False):
19+
self.nodes = self.setup_nodes()
20+
self.is_network_split = split
21+
22+
def run_test(self):
23+
activate_cfund(self.nodes[0])
24+
self.nodes[0].donatefund(100000)
25+
self.nodes[0].staking(False)
26+
27+
payoutTxID_1 = self.create_double_preq_payout()
28+
print("Second payment request payout:\n"+str(self.nodes[0].gettxout(payoutTxID_1, 1)))
29+
30+
# If the payment request is paid out again, the coinbase tx will have 2 vouts, so check txout at index 1
31+
assert(self.nodes[0].gettxout(payoutTxID_1, 1) != None)
32+
33+
34+
activateHardFork(self.nodes[0], 21, 1000)
35+
36+
37+
payoutTxID_2 = self.create_double_preq_payout()
38+
print("Second payment request payout:\n"+str(self.nodes[0].gettxout(payoutTxID_2, 1)))
39+
40+
41+
# If the payment request is paid out again, the coinbase tx will have 2 vouts, so check txout at index 1
42+
assert(self.nodes[0].gettxout(payoutTxID_2, 1) == None)
43+
44+
45+
def create_double_preq_payout(self):
46+
# Creates a proposal and payment request that is paid out twice
47+
## Returns the txid of the second payout
48+
paymentAddress = self.nodes[0].getnewaddress()
49+
proposalAmount = 10000
50+
payoutAmount = 3333
51+
52+
# Create a proposal and accept by voting
53+
54+
proposalid0 = self.nodes[0].createproposal(paymentAddress, proposalAmount, 36000, "test")["hash"]
55+
start_new_cycle(self.nodes[0])
56+
57+
self.nodes[0].proposalvote(proposalid0, "yes")
58+
59+
start_new_cycle(self.nodes[0])
60+
61+
# Proposal should be accepted
62+
assert(self.nodes[0].getproposal(proposalid0)["state"] == 1)
63+
assert(self.nodes[0].getproposal(proposalid0)["status"] == "accepted")
64+
65+
# Create 1 payment request
66+
67+
paymentReq = self.nodes[0].createpaymentrequest(proposalid0, payoutAmount, "test0")["hash"]
68+
69+
slow_gen(self.nodes[0], 1)
70+
71+
# vote yes for the payment request and generate until paid out
72+
73+
self.nodes[0].paymentrequestvote(paymentReq, "yes")
74+
75+
start_new_cycle(self.nodes[0])
76+
assert(self.nodes[0].getpaymentrequest(paymentReq)["state"] == 1)
77+
assert(self.nodes[0].getpaymentrequest(paymentReq)["paidOnBlock"] == "0000000000000000000000000000000000000000000000000000000000000000")
78+
79+
while self.nodes[0].getpaymentrequest(paymentReq)["paidOnBlock"] == "0000000000000000000000000000000000000000000000000000000000000000":
80+
blocks = slow_gen(self.nodes[0], 1)
81+
82+
slow_gen(self.nodes[0], 1)
83+
84+
85+
# try to payout accepted payment request a second time
86+
rawOutput = self.nodes[0].createrawtransaction([], {paymentAddress: payoutAmount}, "", 0)
87+
88+
self.nodes[0].coinbaseoutputs([rawOutput])
89+
self.nodes[0].setcoinbasestrdzeel('[\"'+paymentReq+'\"]')
90+
91+
payoutBlockHash = slow_gen(self.nodes[0], 1)[0]
92+
93+
payoutTxID = self.nodes[0].getblock(payoutBlockHash)["tx"][0]
94+
95+
return payoutTxID
96+
97+
98+
if __name__ == '__main__':
99+
PaymentRequest452().main()

0 commit comments

Comments
 (0)