Skip to content

Commit b1c776c

Browse files
author
alex v
authored
Cold staking (#249)
* stake weight counts cold staking balance * show colstaking output values in gui * overview layout * overview layout move to staking section * receive layout * fix top menu layout * unused var * set coinstake version before signing * resign coinstake tx * error takes string as arg * error must return false * inherit return value * extract pub key from input scripsig when cold staking * gui cold staking wizard * fix layout * fix layout * restrict getcoldstakingaddress only after actv * use chainactive instead of pindexbestheader * add logging * correctly extract pubkey from coldstaking script * new regtest genesis block * IsPayToPublicKey() * addressindex and unspentindex track p2pk (staking) outputs * use address type 1 for p2pk * use extract destination for address/unspent indexes * track cold staking addresses in index * GetStakingKeyID / GetSpendingKeyID Add new class methods to obtain the staking and spending key ids from a cold staking address * ui checks if spends coldstaking out when sending a transaction, the ui will check whether any of the outputs is a cold staking script. in that case, it will warn the user about the coins going to a normal change address if he didnt specify a cold staking address as custom change destination * fix * update strings * add IsColdStake() to CScript * parse OP_COINSTAKE opcode * Solver() extracts addresses from cold staking tx * read key from coldstaking script when verifying block signature * sign coldstaking input * remove cnavcoinaddress * add key_io * revert * fix extractdestinations * required signatures * show cold staking balance * get available stakable credit * get available stakable credit * count cold staking balance when creating coinstake * show canspend / canstake in listtransactions * fix total stakable amount * list transactions canspend/stake * fix order of the public keys on raw decoded address * cold staking balance in ui * show colstaking output values in gui * overview layout * overview layout move to staking section * fix top menu layout * extract pub key from input scripsig when cold staking * gui cold staking wizard * add logging * remove duplicate case * Remove duplicated case * Remove wrong duplicated check * do not enforce random string for preq v2 * adjust overview layout * fix condition order * extend log * move proposal/preq check to contextualcheckblock * revert * rebase cold staking branch * testnet coldstaking versionbit * fix version bit * check versionbit testnet * sync branch * restart testnet / increase pow last block * add log * cfund change logic for accepting props/preq * add consensus info to cfundstats * do not count rejected preqs when creating a new one * added cold staking to regtest (#31) * combined cfund test helper functions: activate_cfund, start_new_cycle, end_cycle, slow_gen * simplified setup-network using existing code * removed duplicate code from rawtx tests and minor linting fixes * adds cold staking to regtest * added cold staking to regtest * new testnet genesis * a coldstakingaddress can be constructued only from two normal addresses * bug fix for getcoldstakingaddress (#32) * forces user to use different staking and spending addresses for getcoldstakingaddress * updated the cold-staking wizard so you cannot enter the same address as both args * add coldstaking to regtest * admit holding two priv keys of a cstaking script * Merge from Cfund cold staking (#33) * do not enforce random string for preq v2 * adjust overview layout * fix condition order * extend log * move proposal/preq check to contextualcheckblock * revert * restart testnet / increase pow last block * add log * cfund change logic for accepting props/preq * add consensus info to cfundstats * do not count rejected preqs when creating a new one * new testnet genesis * a coldstakingaddress can be constructued only from two normal addresses * bug fix for getcoldstakingaddress (#32) * forces user to use different staking and spending addresses for getcoldstakingaddress * updated the cold-staking wizard so you cannot enter the same address as both args * add coldstaking to regtest * admit holding two priv keys of a cstaking script * FIxed wizard text (#35) * fix overview page * fix coldstaking wizard * show both staking and spending pubkeys * fix cold staking wizard * combine signatures cold staking * Moved over RPC tests from other branch * Updated gitignore * ported fix for zlib compile on mac from bitcoin bitcoin/bitcoin#9973 * tided tests up slightly * First spending test * Largely completed tests for coldstaking where we hold the spending address * started work on coldstaing tests where we hold the staking address * fixed accidental var reasignment in test * Added a staking test * added some debugging to test * added missing brackets to function call * added a loop that waits until we stake * fixed syntax error * fixed some more syntax errors * replaced missing bracket * Updated test so we use getblockheight instead of getblockchaininfo and only set up 1 node instaed of 2 * we now mine blocks so our coins mature for stkaing * now we check if the cold staking utxo is used for staking * adding in block generation so we confirm our tx to the cold stkaing address * ading more logs for debugging * more debugging * syncing blocks between nodes * Rejigged node setup, hopefully gets syncing working * get the utxo a different way * fixed syntax error * New method to get utxo * fixes some syntax errors * fixes other syntax errors * We check if the uxto is spent via staking * bump version 4.5.0 * added some more staing address tests * added ore logging * updated arg name in send raw tx function, os it's more verbose * Updated function so we throw a custom exception we can explicitely catch * fixed exception throwing * fixed syntax err * fixing more syntax errors * playing around with exception catching * fixed typo * Removed some logging, unused variables and commented out some printing as part of test clean up * added syncing to test * more test fixes * removed syncing * removed syncing * wrapped operation in rbackets * parse numbers asfloats * removed back slahses * fixed syntax error * we generate our blocks on node 0 now and just remove the block rewards value from our balance calculatins * added getcoldstaking error message * updated rpc test for new help text * adds modified coldstaking client testing doc * format fixes * format fixes * Moved over RPC tests from other branch * Updated gitignore * ported fix for zlib compile on mac from bitcoin bitcoin/bitcoin#9973 * tided tests up slightly * First spending test * Largely completed tests for coldstaking where we hold the spending address * started work on coldstaing tests where we hold the staking address * fixed accidental var reasignment in test * Added a staking test * added some debugging to test * added missing brackets to function call * added a loop that waits until we stake * fixed syntax error * fixed some more syntax errors * replaced missing bracket * Updated test so we use getblockheight instead of getblockchaininfo and only set up 1 node instaed of 2 * we now mine blocks so our coins mature for stkaing * now we check if the cold staking utxo is used for staking * adding in block generation so we confirm our tx to the cold stkaing address * ading more logs for debugging * more debugging * syncing blocks between nodes * Rejigged node setup, hopefully gets syncing working * get the utxo a different way * fixed syntax error * New method to get utxo * fixes some syntax errors * fixes other syntax errors * We check if the uxto is spent via staking * added some more staing address tests * added ore logging * updated arg name in send raw tx function, os it's more verbose * Updated function so we throw a custom exception we can explicitely catch * fixed exception throwing * fixed syntax err * fixing more syntax errors * playing around with exception catching * fixed typo * Static reward RC (#328) * static rewards added * initial test and test util added * added new test to rpc test file * test updated * adding sleep print * removed extra bracket * updated perms. * cleanup test * checking before the soft fork * creating a few blocks to start * removing pre check * Removed some logging, unused variables and commented out some printing as part of test clean up * added syncing to test * more test fixes * removed syncing * removed syncing * wrapped operation in rbackets * parse numbers asfloats * removed back slahses * fixed syntax error * we generate our blocks on node 0 now and just remove the block rewards value from our balance calculatins * added getcoldstaking error message * updated rpc test for new help text * adds modified coldstaking client testing doc * format fixes * format fixes * fix * added spending-from-coldstaking test * updated rpc-tests.py * removed extra file, updated coldstaking tests * Update qa/pull-tester/rpc-tests.py delete reference to deleted file * Updated release notes with a draft of the cold staking notes * added notes about Marcus's testing * fix word
1 parent 8aa7cdd commit b1c776c

61 files changed

Lines changed: 2352 additions & 291 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,5 +130,6 @@ src/secp256k1/build-aux/m4/ltversion.m4
130130
src/secp256k1/build-aux/m4/lt~obsolete.m4
131131
src/NavCoin4-Qt.creator.user
132132

133-
134-
.idea/*
133+
# IDE specific
134+
.idea/*
135+
.vscode

configure.ac

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

depends/packages/zlib.mk

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ $(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca11
77
define $(package)_set_vars
88
$(package)_build_opts= CC="$($(package)_cc)"
99
$(package)_build_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC"
10-
$(package)_build_opts+=AR="$($(package)_ar)"
1110
$(package)_build_opts+=RANLIB="$($(package)_ranlib)"
11+
$(package)_build_opts+=AR="$($(package)_ar)"
12+
$(package)_build_opts_darwin+=AR="$($(package)_libtool)"
13+
$(package)_build_opts_darwin+=ARFLAGS="-o"
1214
endef
1315

1416
define $(package)_config_cmds
@@ -21,4 +23,4 @@ endef
2123

2224
define $(package)_stage_cmds
2325
$(MAKE) DESTDIR=$($(package)_staging_dir) install $($(package)_build_opts)
24-
endef
26+
endef

doc/release-notes/release-notes-4.5.0-additional-testing-notes/modified-coldstaking-client-notes-4.5.0.md

Lines changed: 185 additions & 0 deletions
Large diffs are not rendered by default.

doc/release-notes/release-notes-4.5.0.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,40 @@
11
# NavCoin v4.5.0 Release Notes
22

3+
## Cold staking softfork
4+
5+
<[Pull Request 249](https://github.com/NAVCoin/navcoin-core/pull/249)>
6+
<[Commit ?](https://github.com/NAVCoin/navcoin-core/commit/ ? )>
7+
8+
This softfork will implement the [NPIP_0002](https://github.com/NAVCoin/npips/blob/master/npip-0002.mediawiki) which will allow for the creation of "cold staking" addresses.
9+
10+
[short explanation of cold staking]
11+
12+
- Adds cold staking softfork
13+
- Adds version bit 3
14+
- Adds new gui wizard for the creation of cold staking addresses
15+
- Adds new rpc command `getcoldstakingaddress`
16+
- Updates several rpc commands to provide results relating to cold staking.
17+
- Adds new RPC tests to test cold staking address creation and use
18+
- Added a 'Cold Staking' balance display to the wallet GUI
19+
- Restarted test net??
20+
21+
Full list of updated RPC commands:
22+
23+
(To be written)
24+
25+
### Manual testing with a maliciously modified wallet client
26+
27+
We also performed a number of tests against the cold staking code using a maliciously modified wallet client in an attempt to exploit potential weakness in the code. None of these attempts managed to find an exploit.
28+
Details can be found under [release-notes-4.5.0-additional-testing-notes/modified-coldstaking-client-notes-4.5.0.md](release-notes-4.5.0-additional-testing-notes/modified-coldstaking-client-notes-4.5.0.md)
29+
30+
### Reject this soft fork
31+
32+
To not vote for this soft fork, add the following line to your `navcoin.conf` file:
33+
`rejectversionbit=3`
34+
35+
You can also pass this as a launch argument:
36+
`./navcoin-qt -rejectversionbit=3`
37+
338
## Static rewards softfork
439

540
<[Pull Request 328](https://github.com/NAVCoin/navcoin-core/pull/328)>
@@ -11,6 +46,8 @@ This softfork will change the NavCoin Staking block reward to a fixed amount of
1146
- Adds version bit 15
1247
- Adds RPC tests for Static Rewards
1348

49+
### Reject this soft fork
50+
1451
To not vote for this soft fork, add the following line to your `navcoin.conf` file:
1552
`rejectversionbit=15`
1653

@@ -35,7 +72,7 @@ You can also pass this as a launch argument:
3572
<[Pull Request 335](https://github.com/NAVCoin/navcoin-core/pull/335)>
3673
<[Commit 210a22d](https://github.com/NAVCoin/navcoin-core/commit/210a22daaffbd36d90a5ee0121c0c4ce3de0ed75)>
3774

38-
The wallet will now only accept a minumum number of block headers from a single peer before banning them for misbehaving. This is an anti-spam measure and is customizable via the config file or via launch arguments.
75+
The wallet will now only accept a maximum number of block headers from a single peer before banning them for misbehaving. This is an anti-spam measure and is customizable via the config file or via launch arguments.
3976

4077
The new launch arguments are:
4178

qa/pull-tester/rpc-tests.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
#Tests
103103
testScripts = [
104104
# longest test should go first, to favor running tests in parallel
105-
# 'p2p-fullblocktest.py',
105+
# 'p2p-fullblocktest.py',
106106
# 'walletbackup.py',
107107
# 'bip68-112-113-p2p.py',
108108
# 'wallet.py',
@@ -160,8 +160,10 @@
160160
'cfund-proposalvotelist.py',
161161
'cfund-paymentrequestvotelist.py',
162162
'reject-version-bit.py',
163+
'getcoldstakingaddress.py',
164+
'coldstaking_staking.py',
165+
'coldstaking_spending.py',
163166
'staticr-staking-amount.py',
164-
165167
]
166168
#if ENABLE_ZMQ:
167169
# testScripts.append('zmq_test.py')
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
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+
import decimal
6+
from test_framework.test_framework import NavCoinTestFramework
7+
from test_framework.util import *
8+
9+
class SendingFromColdStaking(NavCoinTestFramework):
10+
"""Tests spending and staking to/from a spending wallet."""
11+
12+
# set up num of nodes
13+
def __init__(self):
14+
super().__init__()
15+
self.setup_clean_chain = True
16+
self.num_nodes = 2
17+
# set up nodes
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+
self.nodes[0].staking(False)
24+
25+
"""generate first 300 blocks to lock in softfork, verify coldstaking is active"""
26+
27+
slow_gen(self.nodes[0], 100)
28+
# verify that cold staking has started
29+
assert(self.nodes[0].getblockchaininfo()["bip9_softforks"]["coldstaking"]["status"] == "started")
30+
slow_gen(self.nodes[0], 100)
31+
# verify that cold staking is locked_in
32+
assert(self.nodes[0].getblockchaininfo()["bip9_softforks"]["coldstaking"]["status"] == "locked_in")
33+
slow_gen(self.nodes[0], 100)
34+
# verify that cold staking is active
35+
assert(self.nodes[0].getblockchaininfo()["bip9_softforks"]["coldstaking"]["status"] == "active")
36+
37+
"""set up transaction-related constants and addresses"""
38+
39+
# declare transaction-related constants
40+
SENDING_FEE= 0.00010000
41+
MIN_COLDSTAKING_SENDING_FEE = 0.00288400
42+
BLOCK_REWARD = 50
43+
# generate address owned by the wallet
44+
spending_address_public_key = self.nodes[0].getnewaddress()
45+
spending_address_private_key = self.nodes[0].dumpprivkey(spending_address_public_key)
46+
# declare third party addresses and keys
47+
staking_address_public_key = "mqyGZvLYfEH27Zk3z6JkwJgB1zpjaEHfiW"
48+
staking_address_private_key = "cMuNajSALbixZvApkcYVE4KgJoeQY92umhEVdQwqX9wSJUzkmdvF"
49+
address_Y_public_key = "mrfjgazyerYxDQHJAPDdUcC3jpmi8WZ2uv"
50+
address_Y_private_key = "cST2mj1kXtiRyk8VSXU3F9pnTp7GrGpyqHRv4Gtap8jo4LGUMvqo"
51+
# generate coldstaking address which we hold the spending key to
52+
coldstaking_address_spending = self.nodes[0].getcoldstakingaddress(staking_address_public_key, spending_address_public_key)
53+
54+
"""check wallet balance and staking weight"""
55+
56+
# get wallet balance and staking weight before sending some navcoin
57+
balance_before_send = self.nodes[0].getbalance()
58+
staking_weight_before_send = self.nodes[0].getstakinginfo()["weight"]
59+
# check wallet staking weight roughly equals wallet balance
60+
assert(round(staking_weight_before_send / 100000000.0, -5) == round(balance_before_send, -5))
61+
62+
"""send navcoin to our coldstaking address, grab balance & staking weight"""
63+
64+
# send funds to the cold staking address (leave some nav for fees) -- we specifically require
65+
# a transaction fee of minimum 0.002884 navcoin due to the complexity of this transaction
66+
self.nodes[0].sendtoaddress(coldstaking_address_spending, float(self.nodes[0].getbalance()) - MIN_COLDSTAKING_SENDING_FEE)
67+
# put transaction in new block & update blockchain
68+
slow_gen(self.nodes[0], 1)
69+
# create list for all coldstaking utxo recieved
70+
listunspent_txs = [n for n in self.nodes[0].listunspent() if n["address"] == coldstaking_address_spending]
71+
# asserts we have recieved funds to the coldstaking address
72+
assert(len(listunspent_txs) > 0)
73+
# asserts that the number of utxo recieved is only 1:
74+
assert(len(listunspent_txs) == 1)
75+
# asserts if amount recieved is what it should be; ~59812449.99711600 NAV
76+
assert(listunspent_txs[0]["amount"] == Decimal('59812449.99711600'))
77+
# grabs updated wallet balance and staking weight
78+
balance_post_send_one = self.nodes[0].getbalance()
79+
staking_weight_post_send = self.nodes[0].getstakinginfo()["weight"]
80+
81+
"""check balance decreased by just the fees"""
82+
83+
# difference between balance after sending and previous balance is the same when block reward is removed
84+
# values are converted to string and "00" is added to right of == operand because values must have equal num of
85+
# decimals
86+
assert(str(balance_post_send_one - BLOCK_REWARD) == (str(float(balance_before_send) - MIN_COLDSTAKING_SENDING_FEE) + "00"))
87+
88+
"""check staking weight now == 0 (we don't hold the staking key)"""
89+
90+
# sent ~all funds to coldstaking address where we do not own the staking key hence our
91+
# staking weight will be 0 as our recieved BLOCK_REWARD navcoin isn't mature enough to count towards
92+
# our staking weight
93+
assert(staking_weight_post_send / 100000000.0 == 0)
94+
95+
"""test spending from a cold staking address with the spending key"""
96+
97+
# send half of our balance to a third party address with sendtoaddress(), change sent to a newly generated change address
98+
# hence coldstakingaddress should be empty after
99+
# amount to be sent has to have 8 decimals
100+
to_be_sent = round(float(balance_post_send_one) * float(0.5) - SENDING_FEE, 8)
101+
self.nodes[0].sendtoaddress(address_Y_public_key, (to_be_sent))
102+
# put transaction in new block & update blockchain
103+
slow_gen(self.nodes[0], 1)
104+
# wallet balance after sending
105+
balance_post_send_two = self.nodes[0].getbalance()
106+
#check balance will not be less than ~half our balance before sending - this
107+
# will occurs if we send to an address we do not own
108+
assert(balance_post_send_two - BLOCK_REWARD >= (float(balance_post_send_one) * float(0.5) - SENDING_FEE))
109+
110+
"""send funds back to coldstaking address, send raw tx from coldstaking address"""
111+
112+
# resend to coldstaking, then re state listunspent_txs
113+
self.nodes[0].sendtoaddress(coldstaking_address_spending, round(float(balance_post_send_two) - SENDING_FEE, 8))
114+
slow_gen(self.nodes[0], 1)
115+
listunspent_txs = [n for n in self.nodes[0].listunspent() if n["address"] == coldstaking_address_spending]
116+
# send funds to a third party address using a signed raw transaction
117+
# get unspent tx inputs
118+
self.send_raw_transaction(decoded_raw_transaction = listunspent_txs[0], \
119+
to_address = address_Y_public_key, \
120+
change_address = coldstaking_address_spending, \
121+
amount = float(str(float(listunspent_txs[0]["amount"]) - MIN_COLDSTAKING_SENDING_FEE) + "00")\
122+
)
123+
# put transaction in new block & update blockchain
124+
slow_gen(self.nodes[0], 1)
125+
# get new balance
126+
balance_post_send_three = self.nodes[0].getbalance()
127+
# we expect our balance to be zero
128+
assert(balance_post_send_three - (BLOCK_REWARD * 2) == 0)
129+
# put transaction in new block & update blockchain
130+
slow_gen(self.nodes[0], 2)
131+
# send our entire wallet balance - minimum fee required to coldstaking address
132+
self.nodes[0].sendtoaddress(coldstaking_address_spending, float(str(float(self.nodes[0].getbalance()) - MIN_COLDSTAKING_SENDING_FEE) + "00"))
133+
# put transaction in new block & update blockchain
134+
slow_gen(self.nodes[0], 1)
135+
# send to our spending address (should work)
136+
send_worked = False
137+
current_balance = self.nodes[0].getbalance()
138+
try:
139+
#fails here - unsupported operand type(s) for *: 'decimal.decimal' and 'float'
140+
self.nodes[0].sendtoaddress(spending_address_public_key, float(current_balance) * 0.5 - 1)
141+
slow_gen(self.nodes[0], 1)
142+
# our balance should be the same minus fees, as we own the address we sent to
143+
assert(self.nodes[0].getbalance() >= current_balance - 1 + BLOCK_REWARD)
144+
send_worked = True
145+
except Exception as e:
146+
print(e)
147+
148+
assert(send_worked == True)
149+
150+
slow_gen(self.nodes[0], 1)
151+
152+
# send to our staking address
153+
send_worked = False
154+
current_balance = self.nodes[0].getbalance()
155+
156+
try:
157+
self.nodes[0].sendtoaddress(staking_address_public_key, float(self.nodes[0].getbalance()) * 0.5 - 1)
158+
slow_gen(self.nodes[0], 1)
159+
# our balance should be half minus fees, as we dont own the address we sent to
160+
assert(self.nodes[0].getbalance() - BLOCK_REWARD <= float(current_balance) * 0.5 - 1 + 2)
161+
send_worked = True
162+
except Exception as e:
163+
print(e)
164+
165+
assert(send_worked == True)
166+
167+
168+
def send_raw_transaction(self, decoded_raw_transaction, to_address, change_address, amount):
169+
# create a raw tx
170+
inputs = [{ "txid" : decoded_raw_transaction["txid"], "vout" : decoded_raw_transaction["vout"]}]
171+
outputs = {to_address : amount}
172+
rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
173+
# sign raw transaction
174+
signresult = self.nodes[0].signrawtransaction(rawtx)
175+
assert(signresult["complete"])
176+
# send raw transaction
177+
return self.nodes[0].sendrawtransaction(signresult['hex'])
178+
179+
180+
if __name__ == '__main__':
181+
SendingFromColdStaking().main()
182+
183+

0 commit comments

Comments
 (0)