Skip to content

Commit

Permalink
Cold staking (#249)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
alex v authored Dec 7, 2018
1 parent 8aa7cdd commit b1c776c
Show file tree
Hide file tree
Showing 61 changed files with 2,352 additions and 291 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,6 @@ src/secp256k1/build-aux/m4/ltversion.m4
src/secp256k1/build-aux/m4/lt~obsolete.m4
src/NavCoin4-Qt.creator.user


.idea/*
# IDE specific
.idea/*
.vscode
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 4)
define(_CLIENT_VERSION_MINOR, 4)
define(_CLIENT_VERSION_MINOR, 5)
define(_CLIENT_VERSION_REVISION, 0)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
Expand Down
6 changes: 4 additions & 2 deletions depends/packages/zlib.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ $(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca11
define $(package)_set_vars
$(package)_build_opts= CC="$($(package)_cc)"
$(package)_build_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC"
$(package)_build_opts+=AR="$($(package)_ar)"
$(package)_build_opts+=RANLIB="$($(package)_ranlib)"
$(package)_build_opts+=AR="$($(package)_ar)"
$(package)_build_opts_darwin+=AR="$($(package)_libtool)"
$(package)_build_opts_darwin+=ARFLAGS="-o"
endef

define $(package)_config_cmds
Expand All @@ -21,4 +23,4 @@ endef

define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install $($(package)_build_opts)
endef
endef

Large diffs are not rendered by default.

39 changes: 38 additions & 1 deletion doc/release-notes/release-notes-4.5.0.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
# NavCoin v4.5.0 Release Notes

## Cold staking softfork

<[Pull Request 249](https://github.com/NAVCoin/navcoin-core/pull/249)>
<[Commit ?](https://github.com/NAVCoin/navcoin-core/commit/ ? )>

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.

[short explanation of cold staking]

- Adds cold staking softfork
- Adds version bit 3
- Adds new gui wizard for the creation of cold staking addresses
- Adds new rpc command `getcoldstakingaddress`
- Updates several rpc commands to provide results relating to cold staking.
- Adds new RPC tests to test cold staking address creation and use
- Added a 'Cold Staking' balance display to the wallet GUI
- Restarted test net??

Full list of updated RPC commands:

(To be written)

### Manual testing with a maliciously modified wallet client

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.
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)

### Reject this soft fork

To not vote for this soft fork, add the following line to your `navcoin.conf` file:
`rejectversionbit=3`

You can also pass this as a launch argument:
`./navcoin-qt -rejectversionbit=3`

## Static rewards softfork

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

### Reject this soft fork

To not vote for this soft fork, add the following line to your `navcoin.conf` file:
`rejectversionbit=15`

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

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.
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.

The new launch arguments are:

Expand Down
6 changes: 4 additions & 2 deletions qa/pull-tester/rpc-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
#Tests
testScripts = [
# longest test should go first, to favor running tests in parallel
# 'p2p-fullblocktest.py',
# 'p2p-fullblocktest.py',
# 'walletbackup.py',
# 'bip68-112-113-p2p.py',
# 'wallet.py',
Expand Down Expand Up @@ -160,8 +160,10 @@
'cfund-proposalvotelist.py',
'cfund-paymentrequestvotelist.py',
'reject-version-bit.py',
'getcoldstakingaddress.py',
'coldstaking_staking.py',
'coldstaking_spending.py',
'staticr-staking-amount.py',

]
#if ENABLE_ZMQ:
# testScripts.append('zmq_test.py')
Expand Down
183 changes: 183 additions & 0 deletions qa/rpc-tests/coldstaking_spending.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#!/usr/bin/env python3
# copyright (c) 2018 the navcoin core developers
# distributed under the mit software license, see the accompanying
# file copying or http://www.opensource.org/licenses/mit-license.php.
import decimal
from test_framework.test_framework import NavCoinTestFramework
from test_framework.util import *

class SendingFromColdStaking(NavCoinTestFramework):
"""Tests spending and staking to/from a spending wallet."""

# set up num of nodes
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 2
# set up nodes
def setup_network(self, split=False):
self.nodes = self.setup_nodes()
self.is_network_split = split

def run_test(self):
self.nodes[0].staking(False)

"""generate first 300 blocks to lock in softfork, verify coldstaking is active"""

slow_gen(self.nodes[0], 100)
# verify that cold staking has started
assert(self.nodes[0].getblockchaininfo()["bip9_softforks"]["coldstaking"]["status"] == "started")
slow_gen(self.nodes[0], 100)
# verify that cold staking is locked_in
assert(self.nodes[0].getblockchaininfo()["bip9_softforks"]["coldstaking"]["status"] == "locked_in")
slow_gen(self.nodes[0], 100)
# verify that cold staking is active
assert(self.nodes[0].getblockchaininfo()["bip9_softforks"]["coldstaking"]["status"] == "active")

"""set up transaction-related constants and addresses"""

# declare transaction-related constants
SENDING_FEE= 0.00010000
MIN_COLDSTAKING_SENDING_FEE = 0.00288400
BLOCK_REWARD = 50
# generate address owned by the wallet
spending_address_public_key = self.nodes[0].getnewaddress()
spending_address_private_key = self.nodes[0].dumpprivkey(spending_address_public_key)
# declare third party addresses and keys
staking_address_public_key = "mqyGZvLYfEH27Zk3z6JkwJgB1zpjaEHfiW"
staking_address_private_key = "cMuNajSALbixZvApkcYVE4KgJoeQY92umhEVdQwqX9wSJUzkmdvF"
address_Y_public_key = "mrfjgazyerYxDQHJAPDdUcC3jpmi8WZ2uv"
address_Y_private_key = "cST2mj1kXtiRyk8VSXU3F9pnTp7GrGpyqHRv4Gtap8jo4LGUMvqo"
# generate coldstaking address which we hold the spending key to
coldstaking_address_spending = self.nodes[0].getcoldstakingaddress(staking_address_public_key, spending_address_public_key)

"""check wallet balance and staking weight"""

# get wallet balance and staking weight before sending some navcoin
balance_before_send = self.nodes[0].getbalance()
staking_weight_before_send = self.nodes[0].getstakinginfo()["weight"]
# check wallet staking weight roughly equals wallet balance
assert(round(staking_weight_before_send / 100000000.0, -5) == round(balance_before_send, -5))

"""send navcoin to our coldstaking address, grab balance & staking weight"""

# send funds to the cold staking address (leave some nav for fees) -- we specifically require
# a transaction fee of minimum 0.002884 navcoin due to the complexity of this transaction
self.nodes[0].sendtoaddress(coldstaking_address_spending, float(self.nodes[0].getbalance()) - MIN_COLDSTAKING_SENDING_FEE)
# put transaction in new block & update blockchain
slow_gen(self.nodes[0], 1)
# create list for all coldstaking utxo recieved
listunspent_txs = [n for n in self.nodes[0].listunspent() if n["address"] == coldstaking_address_spending]
# asserts we have recieved funds to the coldstaking address
assert(len(listunspent_txs) > 0)
# asserts that the number of utxo recieved is only 1:
assert(len(listunspent_txs) == 1)
# asserts if amount recieved is what it should be; ~59812449.99711600 NAV
assert(listunspent_txs[0]["amount"] == Decimal('59812449.99711600'))
# grabs updated wallet balance and staking weight
balance_post_send_one = self.nodes[0].getbalance()
staking_weight_post_send = self.nodes[0].getstakinginfo()["weight"]

"""check balance decreased by just the fees"""

# difference between balance after sending and previous balance is the same when block reward is removed
# values are converted to string and "00" is added to right of == operand because values must have equal num of
# decimals
assert(str(balance_post_send_one - BLOCK_REWARD) == (str(float(balance_before_send) - MIN_COLDSTAKING_SENDING_FEE) + "00"))

"""check staking weight now == 0 (we don't hold the staking key)"""

# sent ~all funds to coldstaking address where we do not own the staking key hence our
# staking weight will be 0 as our recieved BLOCK_REWARD navcoin isn't mature enough to count towards
# our staking weight
assert(staking_weight_post_send / 100000000.0 == 0)

"""test spending from a cold staking address with the spending key"""

# send half of our balance to a third party address with sendtoaddress(), change sent to a newly generated change address
# hence coldstakingaddress should be empty after
# amount to be sent has to have 8 decimals
to_be_sent = round(float(balance_post_send_one) * float(0.5) - SENDING_FEE, 8)
self.nodes[0].sendtoaddress(address_Y_public_key, (to_be_sent))
# put transaction in new block & update blockchain
slow_gen(self.nodes[0], 1)
# wallet balance after sending
balance_post_send_two = self.nodes[0].getbalance()
#check balance will not be less than ~half our balance before sending - this
# will occurs if we send to an address we do not own
assert(balance_post_send_two - BLOCK_REWARD >= (float(balance_post_send_one) * float(0.5) - SENDING_FEE))

"""send funds back to coldstaking address, send raw tx from coldstaking address"""

# resend to coldstaking, then re state listunspent_txs
self.nodes[0].sendtoaddress(coldstaking_address_spending, round(float(balance_post_send_two) - SENDING_FEE, 8))
slow_gen(self.nodes[0], 1)
listunspent_txs = [n for n in self.nodes[0].listunspent() if n["address"] == coldstaking_address_spending]
# send funds to a third party address using a signed raw transaction
# get unspent tx inputs
self.send_raw_transaction(decoded_raw_transaction = listunspent_txs[0], \
to_address = address_Y_public_key, \
change_address = coldstaking_address_spending, \
amount = float(str(float(listunspent_txs[0]["amount"]) - MIN_COLDSTAKING_SENDING_FEE) + "00")\
)
# put transaction in new block & update blockchain
slow_gen(self.nodes[0], 1)
# get new balance
balance_post_send_three = self.nodes[0].getbalance()
# we expect our balance to be zero
assert(balance_post_send_three - (BLOCK_REWARD * 2) == 0)
# put transaction in new block & update blockchain
slow_gen(self.nodes[0], 2)
# send our entire wallet balance - minimum fee required to coldstaking address
self.nodes[0].sendtoaddress(coldstaking_address_spending, float(str(float(self.nodes[0].getbalance()) - MIN_COLDSTAKING_SENDING_FEE) + "00"))
# put transaction in new block & update blockchain
slow_gen(self.nodes[0], 1)
# send to our spending address (should work)
send_worked = False
current_balance = self.nodes[0].getbalance()
try:
#fails here - unsupported operand type(s) for *: 'decimal.decimal' and 'float'
self.nodes[0].sendtoaddress(spending_address_public_key, float(current_balance) * 0.5 - 1)
slow_gen(self.nodes[0], 1)
# our balance should be the same minus fees, as we own the address we sent to
assert(self.nodes[0].getbalance() >= current_balance - 1 + BLOCK_REWARD)
send_worked = True
except Exception as e:
print(e)

assert(send_worked == True)

slow_gen(self.nodes[0], 1)

# send to our staking address
send_worked = False
current_balance = self.nodes[0].getbalance()

try:
self.nodes[0].sendtoaddress(staking_address_public_key, float(self.nodes[0].getbalance()) * 0.5 - 1)
slow_gen(self.nodes[0], 1)
# our balance should be half minus fees, as we dont own the address we sent to
assert(self.nodes[0].getbalance() - BLOCK_REWARD <= float(current_balance) * 0.5 - 1 + 2)
send_worked = True
except Exception as e:
print(e)

assert(send_worked == True)


def send_raw_transaction(self, decoded_raw_transaction, to_address, change_address, amount):
# create a raw tx
inputs = [{ "txid" : decoded_raw_transaction["txid"], "vout" : decoded_raw_transaction["vout"]}]
outputs = {to_address : amount}
rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
# sign raw transaction
signresult = self.nodes[0].signrawtransaction(rawtx)
assert(signresult["complete"])
# send raw transaction
return self.nodes[0].sendrawtransaction(signresult['hex'])


if __name__ == '__main__':
SendingFromColdStaking().main()


Loading

0 comments on commit b1c776c

Please sign in to comment.