diff --git a/qa/pull-tester/cc-tests.sh b/qa/pull-tester/cc-tests.sh new file mode 100755 index 000000000..4e8dde894 --- /dev/null +++ b/qa/pull-tester/cc-tests.sh @@ -0,0 +1,83 @@ +#!/bin/bash +set -e -o pipefail + +CURDIR=$(cd $(dirname "$0"); pwd) +# Get BUILDDIR and REAL_BITCOIND +. "${CURDIR}/tests-config.sh" + +export BITCOINCLI=${BUILDDIR}/qa/pull-tester/run-bitcoin-cli +export BITCOIND=${REAL_BITCOIND} + +#Run the tests +# FAUCET test should be permanently first!!! + +testScripts=( + 'cryptoconditions_faucet.py' + 'cryptoconditions_channels.py' + 'cryptoconditions_dice.py' + 'cryptoconditions_oracles.py' + 'cryptoconditions_rewards.py' + 'cryptoconditions_token.py' + 'cryptoconditions_gateways.py' +); + +extArg="-extended" +passOn=${@#$extArg} + +successCount=0 +declare -a failures + +function runTestScript +{ + local testName="$1" + shift + + echo -e "=== Running testscript ${testName} ===" + + if eval "$@" + then + successCount=$(expr $successCount + 1) + echo "--- Success: ${testName} ---" + else + failures[${#failures[@]}]="$testName" + echo "!!! FAIL: ${testName} !!!" + fi + + echo +} + +if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then + for (( i = 0; i < ${#testScripts[@]}; i++ )) + do + if [ -z "$1" ] || [ "${1:0:1}" == "-" ] || [ "$1" == "${testScripts[$i]}" ] || [ "$1.py" == "${testScripts[$i]}" ] + then + runTestScript \ + "${testScripts[$i]}" \ + "${BUILDDIR}/qa/rpc-tests/${testScripts[$i]}" \ + --srcdir "${BUILDDIR}/src" ${passOn} + fi + done + for (( i = 0; i < ${#testScriptsExt[@]}; i++ )) + do + if [ "$1" == $extArg ] || [ "$1" == "${testScriptsExt[$i]}" ] || [ "$1.py" == "${testScriptsExt[$i]}" ] + then + runTestScript \ + "${testScriptsExt[$i]}" \ + "${BUILDDIR}/qa/rpc-tests/${testScriptsExt[$i]}" \ + --srcdir "${BUILDDIR}/src" ${passOn} + fi + done + + echo -e "\n\nTests completed: $(expr $successCount + ${#failures[@]})" + echo "successes $successCount; failures: ${#failures[@]}" + + if [ ${#failures[@]} -gt 0 ] + then + echo -e "\nFailing tests: ${failures[*]}" + exit 1 + else + exit 0 + fi +else + echo "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled" +fi diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 006b1890f..226c16b11 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -13,14 +13,6 @@ export BITCOIND=${REAL_BITCOIND} testScripts=( 'ac_private.py' 'verushash.py' - 'cryptoconditions.py' - 'cryptoconditions_channels.py' - 'cryptoconditions_dice.py' - 'cryptoconditions_faucet.py' - 'cryptoconditions_gateways.py' - 'cryptoconditions_oracles.py' - 'cryptoconditions_rewards.py' - 'cryptoconditions_token.py' 'paymentdisclosure.py' 'prioritisetransaction.py' 'wallet_treestate.py' diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md index 17aee1967..e95d6a120 100644 --- a/qa/rpc-tests/README.md +++ b/qa/rpc-tests/README.md @@ -14,6 +14,8 @@ You can run a single test by calling `qa/pull-tester/rpc-tests.sh `. Run all possible tests with `qa/pull-tester/rpc-tests.sh -extended`. +Also it's possible to run CryptoConditions tests only by `qa/pull-tester/cc-tests.sh --noshutdown --tracerpc` + Possible options: ``` diff --git a/qa/rpc-tests/cryptoconditions_channels.py b/qa/rpc-tests/cryptoconditions_channels.py index 0010f825b..053b532cb 100755 --- a/qa/rpc-tests/cryptoconditions_channels.py +++ b/qa/rpc-tests/cryptoconditions_channels.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_framework import CryptoconditionsTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_greater_than, \ initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \ @@ -12,71 +12,7 @@ from test_framework.util import assert_equal, assert_greater_than, \ from cryptoconditions import assert_success, assert_error, generate_random_string -class CryptoconditionsChannelsTest(BitcoinTestFramework): - - def setup_chain(self): - print("Initializing CC test directory "+self.options.tmpdir) - self.num_nodes = 2 - initialize_chain_clean(self.options.tmpdir, self.num_nodes) - - def setup_network(self, split = False): - print("Setting up network...") - self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" - self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" - self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" - self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" - self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" - self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[[ - # always give -ac_name as first extra_arg and port as third - '-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', - '-port=64367', - '-rpcport=64368', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt' - ], - ['-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', - '-port=64365', - '-rpcport=64366', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey1, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '-addnode=127.0.0.1:64367', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt']] - ) - self.is_network_split = split - self.rpc = self.nodes[0] - self.rpc1 = self.nodes[1] - self.sync_all() - print("Done setting up network") - - def send_and_mine(self, xtn, rpc_connection): - txid = rpc_connection.sendrawtransaction(xtn) - assert txid, 'got txid' - # we need the tx above to be confirmed in the next block - rpc_connection.generate(1) - return txid +class CryptoconditionsChannelsTest(CryptoconditionsTestFramework): def run_channels_tests(self): @@ -159,7 +95,8 @@ class CryptoconditionsChannelsTest(BitcoinTestFramework): rpc = self.nodes[0] rpc1 = self.nodes[1] # utxos from block 1 become mature in block 101 - rpc.generate(101) + if not self.options.noshutdown: + rpc.generate(101) self.sync_all() rpc.getinfo() rpc1.getinfo() diff --git a/qa/rpc-tests/cryptoconditions_dice.py b/qa/rpc-tests/cryptoconditions_dice.py index 9957a8f2b..51fd18908 100755 --- a/qa/rpc-tests/cryptoconditions_dice.py +++ b/qa/rpc-tests/cryptoconditions_dice.py @@ -4,78 +4,15 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_framework import CryptoconditionsTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_greater_than, \ initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \ stop_nodes, sync_blocks, sync_mempools, wait_bitcoinds, rpc_port, assert_raises from cryptoconditions import assert_success, assert_error, generate_random_string -class CryptoconditionsDiceTest(BitcoinTestFramework): - def setup_chain(self): - print("Initializing CC test directory "+self.options.tmpdir) - self.num_nodes = 2 - initialize_chain_clean(self.options.tmpdir, self.num_nodes) - - def setup_network(self, split = False): - print("Setting up network...") - self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" - self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" - self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" - self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" - self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" - self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[[ - # always give -ac_name as first extra_arg and port as third - '-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', - '-port=64367', - '-rpcport=64368', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt' - ], - ['-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', - '-port=64365', - '-rpcport=64366', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey1, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '-addnode=127.0.0.1:64367', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt']] - ) - self.is_network_split = split - self.rpc = self.nodes[0] - self.rpc1 = self.nodes[1] - self.sync_all() - print("Done setting up network") - - def send_and_mine(self, xtn, rpc_connection): - txid = rpc_connection.sendrawtransaction(xtn) - assert txid, 'got txid' - # we need the tx above to be confirmed in the next block - rpc_connection.generate(1) - return txid +class CryptoconditionsDiceTest(CryptoconditionsTestFramework): def run_dice_tests(self): rpc = self.nodes[0] @@ -244,7 +181,8 @@ class CryptoconditionsDiceTest(BitcoinTestFramework): rpc = self.nodes[0] rpc1 = self.nodes[1] # utxos from block 1 become mature in block 101 - rpc.generate(101) + if not self.options.noshutdown: + rpc.generate(101) self.sync_all() rpc.getinfo() rpc1.getinfo() diff --git a/qa/rpc-tests/cryptoconditions_faucet.py b/qa/rpc-tests/cryptoconditions_faucet.py index 4f8cb42cf..a3cbdeb15 100755 --- a/qa/rpc-tests/cryptoconditions_faucet.py +++ b/qa/rpc-tests/cryptoconditions_faucet.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_framework import CryptoconditionsTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_greater_than, \ initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \ @@ -12,71 +12,7 @@ from test_framework.util import assert_equal, assert_greater_than, \ from cryptoconditions import assert_success, assert_error, generate_random_string -class CryptoconditionsFaucetTest(BitcoinTestFramework): - - def setup_chain(self): - print("Initializing CC test directory "+self.options.tmpdir) - self.num_nodes = 2 - initialize_chain_clean(self.options.tmpdir, self.num_nodes) - - def setup_network(self, split = False): - print("Setting up network...") - self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" - self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" - self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" - self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" - self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" - self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[[ - # always give -ac_name as first extra_arg and port as third - '-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', - '-port=64367', - '-rpcport=64368', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt' - ], - ['-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', - '-port=64365', - '-rpcport=64366', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey1, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '-addnode=127.0.0.1:64367', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt']] - ) - self.is_network_split = split - self.rpc = self.nodes[0] - self.rpc1 = self.nodes[1] - self.sync_all() - print("Done setting up network") - - def send_and_mine(self, xtn, rpc_connection): - txid = rpc_connection.sendrawtransaction(xtn) - assert txid, 'got txid' - # we need the tx above to be confirmed in the next block - rpc_connection.generate(1) - return txid +class CryptoconditionsFaucetTest(CryptoconditionsTestFramework): def run_faucet_tests(self): rpc = self.rpc diff --git a/qa/rpc-tests/cryptoconditions_gateways.py b/qa/rpc-tests/cryptoconditions_gateways.py index a48b8b3d8..a7f0cad2b 100755 --- a/qa/rpc-tests/cryptoconditions_gateways.py +++ b/qa/rpc-tests/cryptoconditions_gateways.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_framework import CryptoconditionsTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_greater_than, \ initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \ @@ -12,72 +12,7 @@ from test_framework.util import assert_equal, assert_greater_than, \ from cryptoconditions import assert_success, assert_error, generate_random_string -class CryptoconditionsGatewaysTest(BitcoinTestFramework): - - - def setup_chain(self): - print("Initializing CC test directory "+self.options.tmpdir) - self.num_nodes = 2 - initialize_chain_clean(self.options.tmpdir, self.num_nodes) - - def setup_network(self, split = False): - print("Setting up network...") - self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" - self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" - self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" - self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" - self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" - self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[[ - # always give -ac_name as first extra_arg and port as third - '-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', - '-port=64367', - '-rpcport=64368', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt' - ], - ['-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', - '-port=64365', - '-rpcport=64366', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey1, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '-addnode=127.0.0.1:64367', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt']] - ) - self.is_network_split = split - self.rpc = self.nodes[0] - self.rpc1 = self.nodes[1] - self.sync_all() - print("Done setting up network") - - def send_and_mine(self, xtn, rpc_connection): - txid = rpc_connection.sendrawtransaction(xtn) - assert txid, 'got txid' - # we need the tx above to be confirmed in the next block - rpc_connection.generate(1) - return txid +class CryptoconditionsGatewaysTest(CryptoconditionsTestFramework): def run_gateways_tests(self): rpc = self.nodes[0] @@ -137,12 +72,14 @@ class CryptoconditionsGatewaysTest(BitcoinTestFramework): result = rpc.gatewayslist() assert_equal(result[0], bind_txid) + def run_test(self): print("Mining blocks...") rpc = self.nodes[0] rpc1 = self.nodes[1] # utxos from block 1 become mature in block 101 - rpc.generate(101) + if not self.options.noshutdown: + rpc.generate(101) self.sync_all() rpc.getinfo() rpc1.getinfo() diff --git a/qa/rpc-tests/cryptoconditions_oracles.py b/qa/rpc-tests/cryptoconditions_oracles.py index 31712abbc..f295bf020 100755 --- a/qa/rpc-tests/cryptoconditions_oracles.py +++ b/qa/rpc-tests/cryptoconditions_oracles.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_framework import CryptoconditionsTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_greater_than, \ initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \ @@ -12,72 +12,7 @@ from test_framework.util import assert_equal, assert_greater_than, \ from cryptoconditions import assert_success, assert_error, generate_random_string -class CryptoconditionsOraclesTest(BitcoinTestFramework): - - - def setup_chain(self): - print("Initializing CC test directory "+self.options.tmpdir) - self.num_nodes = 2 - initialize_chain_clean(self.options.tmpdir, self.num_nodes) - - def setup_network(self, split = False): - print("Setting up network...") - self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" - self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" - self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" - self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" - self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" - self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[[ - # always give -ac_name as first extra_arg and port as third - '-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', - '-port=64367', - '-rpcport=64368', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt' - ], - ['-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', - '-port=64365', - '-rpcport=64366', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey1, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '-addnode=127.0.0.1:64367', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt']] - ) - self.is_network_split = split - self.rpc = self.nodes[0] - self.rpc1 = self.nodes[1] - self.sync_all() - print("Done setting up network") - - def send_and_mine(self, xtn, rpc_connection): - txid = rpc_connection.sendrawtransaction(xtn) - assert txid, 'got txid' - # we need the tx above to be confirmed in the next block - rpc_connection.generate(1) - return txid +class CryptoconditionsOraclesTest(CryptoconditionsTestFramework): def run_oracles_tests(self): rpc = self.nodes[0] @@ -269,8 +204,6 @@ class CryptoconditionsOraclesTest(BitcoinTestFramework): oraclesdata_Ihh = self.send_and_mine(result["hex"], rpc) result = rpc.oraclessamples(globals()["oracle_{}".format("Ihh")], oraclesdata_Ihh, "1") assert_equal("[u'0']", str(result["samples"][0]), "Data match") - assert_equal("[u'00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff']", str(result["samples"][1]), "Data match") - assert_equal("[u'00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff']", str(result["samples"][2]), "Data match") def run_test(self): @@ -278,7 +211,8 @@ class CryptoconditionsOraclesTest(BitcoinTestFramework): rpc = self.nodes[0] rpc1 = self.nodes[1] # utxos from block 1 become mature in block 101 - rpc.generate(101) + if not self.options.noshutdown: + rpc.generate(101) self.sync_all() rpc.getinfo() rpc1.getinfo() diff --git a/qa/rpc-tests/cryptoconditions_rewards.py b/qa/rpc-tests/cryptoconditions_rewards.py index 5538a399c..7bda54eaf 100755 --- a/qa/rpc-tests/cryptoconditions_rewards.py +++ b/qa/rpc-tests/cryptoconditions_rewards.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_framework import CryptoconditionsTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_greater_than, \ initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \ @@ -12,72 +12,7 @@ from test_framework.util import assert_equal, assert_greater_than, \ from cryptoconditions import assert_success, assert_error, generate_random_string -class CryptoconditionsRewardsTest(BitcoinTestFramework): - - - def setup_chain(self): - print("Initializing CC test directory "+self.options.tmpdir) - self.num_nodes = 2 - initialize_chain_clean(self.options.tmpdir, self.num_nodes) - - def setup_network(self, split = False): - print("Setting up network...") - self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" - self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" - self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" - self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" - self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" - self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[[ - # always give -ac_name as first extra_arg and port as third - '-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', - '-port=64367', - '-rpcport=64368', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt' - ], - ['-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', - '-port=64365', - '-rpcport=64366', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey1, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '-addnode=127.0.0.1:64367', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt']] - ) - self.is_network_split = split - self.rpc = self.nodes[0] - self.rpc1 = self.nodes[1] - self.sync_all() - print("Done setting up network") - - def send_and_mine(self, xtn, rpc_connection): - txid = rpc_connection.sendrawtransaction(xtn) - assert txid, 'got txid' - # we need the tx above to be confirmed in the next block - rpc_connection.generate(1) - return txid +class CryptoconditionsRewardsTest(CryptoconditionsTestFramework): def run_rewards_tests(self): rpc = self.nodes[0] @@ -194,7 +129,8 @@ class CryptoconditionsRewardsTest(BitcoinTestFramework): rpc = self.nodes[0] rpc1 = self.nodes[1] # utxos from block 1 become mature in block 101 - rpc.generate(101) + if not self.options.noshutdown: + rpc.generate(101) self.sync_all() rpc.getinfo() rpc1.getinfo() diff --git a/qa/rpc-tests/cryptoconditions_token.py b/qa/rpc-tests/cryptoconditions_token.py index 8120f23bf..630d8f6e3 100755 --- a/qa/rpc-tests/cryptoconditions_token.py +++ b/qa/rpc-tests/cryptoconditions_token.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_framework import CryptoconditionsTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_greater_than, \ initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \ @@ -12,72 +12,7 @@ from test_framework.util import assert_equal, assert_greater_than, \ from cryptoconditions import assert_success, assert_error, generate_random_string -class CryptoconditionsTokenTest(BitcoinTestFramework): - - - def setup_chain(self): - print("Initializing CC test directory "+self.options.tmpdir) - self.num_nodes = 2 - initialize_chain_clean(self.options.tmpdir, self.num_nodes) - - def setup_network(self, split = False): - print("Setting up network...") - self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" - self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" - self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" - self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" - self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" - self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[[ - # always give -ac_name as first extra_arg and port as third - '-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', - '-port=64367', - '-rpcport=64368', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt' - ], - ['-ac_name=REGTEST', - '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', - '-port=64365', - '-rpcport=64366', - '-regtest', - '-addressindex=1', - '-spentindex=1', - '-ac_supply=5555555', - '-ac_reward=10000000000000', - '-pubkey=' + self.pubkey1, - '-ac_cc=2', - '-whitelist=127.0.0.1', - '-debug', - '-addnode=127.0.0.1:64367', - '--daemon', - '-rpcuser=rt', - '-rpcpassword=rt']] - ) - self.is_network_split = split - self.rpc = self.nodes[0] - self.rpc1 = self.nodes[1] - self.sync_all() - print("Done setting up network") - - def send_and_mine(self, xtn, rpc_connection): - txid = rpc_connection.sendrawtransaction(xtn) - assert txid, 'got txid' - # we need the tx above to be confirmed in the next block - rpc_connection.generate(1) - return txid +class CryptoconditionsTokenTest(CryptoconditionsTestFramework): def run_token_tests(self): rpc = self.nodes[0] @@ -274,7 +209,8 @@ class CryptoconditionsTokenTest(BitcoinTestFramework): rpc = self.nodes[0] rpc1 = self.nodes[1] # utxos from block 1 become mature in block 101 - rpc.generate(101) + if not self.options.noshutdown: + rpc.generate(101) self.sync_all() rpc.getinfo() rpc1.getinfo() diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py index f545b4246..d1c3d87e3 100755 --- a/qa/rpc-tests/test_framework/test_framework.py +++ b/qa/rpc-tests/test_framework/test_framework.py @@ -180,3 +180,72 @@ class ComparisonTestFramework(BitcoinTestFramework): extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes, binary=[self.options.testbinary] + [self.options.refbinary]*(self.num_nodes-1)) + + +class CryptoconditionsTestFramework(BitcoinTestFramework): + + def __init__(self): + self.num_nodes = 2 + + def setup_chain(self): + print("Initializing CC test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, self.num_nodes) + + def setup_network(self, split = False): + print("Setting up network...") + self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" + self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" + self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" + self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" + self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" + self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, + extra_args=[[ + # always give -ac_name as first extra_arg and port as third + '-ac_name=REGTEST', + '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', + '-port=64367', + '-rpcport=64368', + '-regtest', + '-addressindex=1', + '-spentindex=1', + '-ac_supply=5555555', + '-ac_reward=10000000000000', + '-pubkey=' + self.pubkey, + '-ac_cc=2', + '-whitelist=127.0.0.1', + '-debug', + '--daemon', + '-rpcuser=rt', + '-rpcpassword=rt' + ], + ['-ac_name=REGTEST', + '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', + '-port=64365', + '-rpcport=64366', + '-regtest', + '-addressindex=1', + '-spentindex=1', + '-ac_supply=5555555', + '-ac_reward=10000000000000', + '-pubkey=' + self.pubkey1, + '-ac_cc=2', + '-whitelist=127.0.0.1', + '-debug', + '-addnode=127.0.0.1:64367', + '--daemon', + '-rpcuser=rt', + '-rpcpassword=rt']] + ) + self.is_network_split = split + self.rpc = self.nodes[0] + self.rpc1 = self.nodes[1] + self.sync_all() + print("Done setting up network") + + def send_and_mine(self, xtn, rpc_connection): + txid = rpc_connection.sendrawtransaction(xtn) + assert txid, 'got txid' + # we need the tx above to be confirmed in the next block + rpc_connection.generate(1) + return txid diff --git a/src/Makefile.am b/src/Makefile.am index 874c3a8b4..98cc79adf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -203,6 +203,7 @@ BITCOIN_CORE_H = \ mruset.h \ net.h \ netbase.h \ + notaries_staked.h \ noui.h \ paymentdisclosure.h \ paymentdisclosuredb.h \ @@ -309,6 +310,7 @@ libbitcoin_server_a_SOURCES = \ chain.cpp \ checkpoints.cpp \ crosschain.cpp \ + crosschain_authority.cpp \ crypto/haraka.h \ crypto/haraka_portable.h \ crypto/verus_hash.h \ @@ -323,6 +325,7 @@ libbitcoin_server_a_SOURCES = \ metrics.h \ miner.cpp \ net.cpp \ + notaries_staked.cpp \ noui.cpp \ notarisationdb.cpp \ paymentdisclosure.cpp \ diff --git a/src/assetchains.json b/src/assetchains.json index 1a0ae25e2..797f445b5 100644 --- a/src/assetchains.json +++ b/src/assetchains.json @@ -136,42 +136,51 @@ "ac_reward": "100000000" }, { - "ac_name": "SEC", - "ac_supply": "1000000000", - "ac_cc": "333" - }, - { - "ac_name": "CCL", - "ac_supply": "200000000", + "ac_name": "CFEKED", + "ac_supply": "1000", "ac_end": "1", - "ac_cc": "2", - "addressindex": "1", - "spentindex": "1", + "ac_reward": "1", + "ac_staked": "1", + "ac_cc": "102", "addnode": [ - "142.93.136.89", - "195.201.22.89" + "195.201.137.5", + "195.201.20.230" ] }, { - "ac_name": "PIRATE", - "ac_supply": "0", - "ac_reward": "25600000000", - "ac_halving": "77777", - "ac_private": "1", + "ac_name": "CFEKING", + "ac_supply": "1000", + "ac_end": "1", + "ac_reward": "1", + "ac_staked": "1", + "ac_cc": "102", "addnode": [ - "136.243.102.225" + "195.201.137.5", + "195.201.20.230" ] }, { - "ac_name": "MGNX", - "ac_supply": "12465003", - "ac_staked": "90", - "ac_reward": "2000000000", - "ac_halving": "525960", - "ac_cc": "2", - "ac_end": "2629800", + "ac_name": "CFEKLF", + "ac_supply": "1000", + "ac_end": "1", + "ac_reward": "1", + "ac_staked": "1", + "ac_cc": "102", "addnode": [ - "142.93.27.180" + "195.201.137.5", + "195.201.20.230" + ] + }, + { + "ac_name": "CFEKMLT", + "ac_supply": "1000", + "ac_end": "1", + "ac_reward": "1", + "ac_staked": "1", + "ac_cc": "102", + "addnode": [ + "195.201.137.5", + "195.201.20.230" ] }, { diff --git a/src/assetchains.old b/src/assetchains.old index c1419e7f5..6df854903 100755 --- a/src/assetchains.old +++ b/src/assetchains.old @@ -39,7 +39,7 @@ echo $pubkey ~/VerusCoin/src/komodod -pubkey=$pubkey -ac_name=VRSC -ac_algo=verushash -ac_cc=1 -ac_veruspos=50 -ac_supply=0 -ac_eras=3 -ac_reward=0,38400000000,2400000000 -ac_halving=1,43200,1051920 -ac_decay=100000000,0,0 -ac_end=10080,226080,0 -ac_timelockgte=19200000000 -ac_timeunlockfrom=129600 -ac_timeunlockto=1180800 -addnode=185.25.48.236 -addnode=185.64.105.111 & ./komodod -pubkey=$pubkey -ac_name=SEC -ac_cc=333 -ac_supply=1000000000 -addnode=185.148.145.43 & ./komodod -pubkey=$pubkey -ac_name=CCL -ac_supply=200000000 -ac_end=1 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=142.93.136.89 -addnode=195.201.22.89 & -./komodod -pubkey=$pubkey -ac_name=PIRATE -ac_supply=0 -ac_reward=25600000000 -ac_halving=77777 -ac_private=1 -addnode=136.243.102.225 & +./komodod -pubkey=$pubkey -ac_name=PIRATE -ac_supply=0 -ac_reward=25600000000 -ac_halving=77777 -ac_private=1 -addnode=178.63.77.56 & ./komodod -pubkey=$pubkey -ac_name=MGNX -ac_supply=12465003 -ac_staked=90 -ac_reward=2000000000 -ac_halving=525960 -ac_cc=2 -ac_end=2629800 -addnode=142.93.27.180 & ./komodod -pubkey=$pubkey -ac_name=PGT -ac_supply=10000000 -ac_end=1 -addnode=190.114.254.104 & ./komodod -pubkey=$pubkey -ac_name=KMDICE -ac_supply=10500000 -ac_reward=2500000000 -ac_halving=210000 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=144.76.217.232 & diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 64830d463..f8f0fe002 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -10,6 +10,7 @@ #include "util.h" #include "utilstrencodings.h" + #include #include diff --git a/src/cc/dapps/Makefile b/src/cc/dapps/Makefile new file mode 100644 index 000000000..6e7874788 --- /dev/null +++ b/src/cc/dapps/Makefile @@ -0,0 +1,11 @@ +# just type make to compile all dapps +all: zmigrate oraclefeed + +zmigrate: + $(CC) zmigrate.c -o zmigrate -lm + +oraclefeed: + $(CC) oraclefeed.c -o oraclefeed -lm + +clean: + rm zmigrate oraclefeed diff --git a/src/cc/dapps/README.md b/src/cc/dapps/README.md new file mode 100644 index 000000000..0d8b2cac2 --- /dev/null +++ b/src/cc/dapps/README.md @@ -0,0 +1,28 @@ +# CryptoCondition dApps + +## Compiling + +To compile all dapps in this directory: + + make + +## zmigrate - Sprout to Sapling Migration dApp + +This tool converts Sprout zaddress funds into Sapling funds in a new Sapling address. + +### Usage + + ./zmigrate zsaplingaddr + +The above command may need to be run multiple times to complete the process. + +This CLI implementation will be called by GUI wallets, average users do not +need to worry about using this low-level tool. + +## oraclefeed - feed of price data using oracles + +### Usage + + ./oraclefeed $ACNAME $ORACLETXID $MYPUBKEY $FORMAT $BINDTXID [refcoin_cli] + +Supported formats are L and Ihh. Price data from CoinDesk API. diff --git a/src/cc/dapps/zmigrate.c b/src/cc/dapps/zmigrate.c index a86b529ad..84cf4b057 100644 --- a/src/cc/dapps/zmigrate.c +++ b/src/cc/dapps/zmigrate.c @@ -670,6 +670,7 @@ int64_t find_onetime_amount(char *coinstr,char *coinaddr) coinaddr[0] = 0; if ( (array= get_listunspent(coinstr,"")) != 0 ) { + //printf("got listunspent.(%s)\n",jprint(array,0)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; i %s\n",srcaddr,params); if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_sendmany",addr,params,"","")) != 0 ) { printf("unexpected json z_sendmany.(%s)\n",jprint(retjson,0)); @@ -906,7 +908,7 @@ int32_t main(int32_t argc,char **argv) zsaddr = clonestr(argv[2]); printf("%s: %s %s\n",REFCOIN_CLI,coinstr,zsaddr); uint32_t lastopid; char coinaddr[64],zcaddr[128],opidstr[128]; int32_t finished; int64_t amount,stdamount,txfee; - stdamount = 1000 * SATOSHIDEN; + //stdamount = 500 * SATOSHIDEN; txfee = 10000; again: printf("start processing zmigrate\n"); @@ -916,7 +918,7 @@ again: { if ( have_pending_opid(coinstr,0) != 0 ) { - sleep(60); + sleep(10); continue; } if ( (amount= find_onetime_amount(coinstr,coinaddr)) > txfee ) @@ -930,14 +932,28 @@ again: if ( (amount= find_sprout_amount(coinstr,zcaddr)) > txfee ) { // generate taddr, send max of 10000.0001 - if ( amount > stdamount+txfee ) - amount = stdamount + txfee; + static int64_t lastamount,lastamount2,lastamount3,lastamount4,refamount = 5000 * SATOSHIDEN; + stdamount = refamount; + if ( amount == lastamount && amount == lastamount2 ) + { + stdamount /= 10; + if ( amount == lastamount3 && amount == lastamount4 ) + stdamount /= 10; + } + if ( stdamount < refamount ) + refamount = stdamount; + lastamount4 = lastamount3; + lastamount3 = lastamount2; + lastamount2 = lastamount; + lastamount = amount; + if ( amount > stdamount+2*txfee ) + amount = stdamount + 2*txfee; if ( getnewaddress(coinaddr,coinstr,"") == 0 ) { z_sendmany(opidstr,coinstr,"",zcaddr,coinaddr,amount-txfee); lastopid = (uint32_t)time(NULL); } else printf("couldnt getnewaddress!\n"); - sleep(30); + sleep(3); continue; } if ( time(NULL) > lastopid+600 ) diff --git a/src/cc/dice.cpp b/src/cc/dice.cpp index 45e101e9c..df60833ed 100644 --- a/src/cc/dice.cpp +++ b/src/cc/dice.cpp @@ -1213,6 +1213,9 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit } else { return(0); } + fprintf(stderr,"numentropy tx %d: %.8f\n",n,(double)totalinputs/COIN); + entropytxs = n; + return(totalinputs); } bool DicePlanExists(CScript &fundingPubKey,uint256 &fundingtxid,struct CCcontract_info *cp,uint64_t refsbits,CPubKey dicepk,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &timeoutblocks) @@ -1425,7 +1428,8 @@ std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet return(""); } if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 ) { - CCerror = "Diceinit error in bet, is your transaction confirmed?"; + + CCerror = "error in Diceinit"; return(""); } if ( bet < minbet || bet > maxbet || odds > maxodds ) @@ -1752,8 +1756,7 @@ double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettx CScript fundingPubKey,scriptPubKey; CTransaction spenttx,betTx,entropyTx; uint256 hentropyproof,entropyused,hash,proof,txid,hashBlock,spenttxid,bettorentropy; CPubKey mypk,dicepk,fundingpk; struct CCcontract_info *cp,C; int32_t i,entropyvout,flag,win,num,loss,duplicate=0,result,iswin,vout,n=0; int64_t minbet,maxbet,maxodds,timeoutblocks,sum=0; uint64_t sbits,refsbits; char coinaddr[64]; std::string res; uint8_t funcid; if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,refsbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 ) { - CCerror = "Diceinit error in status, is your transaction confirmed?"; - fprintf(stderr,"%s\n", CCerror.c_str() ); + CCerror = "Diceinit error in status"; return(0.); } win = loss = 0; diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 35644a82a..96b85a6dc 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -139,46 +139,17 @@ int32_t Eval::GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t time return komodo_notaries(pubkeys, height, timestamp); } - bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const { if (tx.vin.size() < 11) return false; - uint8_t seenNotaries[64] = {0}; - uint8_t notaries[64][33]; - int nNotaries = GetNotaries(notaries, height, timestamp); + CrosschainAuthority auth; + auth.requiredSigs = 11; + auth.size = GetNotaries(auth.notaries, height, timestamp); - BOOST_FOREACH(const CTxIn &txIn, tx.vin) - { - // Get notary pubkey - CTransaction tx; - uint256 hashBlock; - if (!GetTxUnconfirmed(txIn.prevout.hash, tx, hashBlock)) return false; - if (tx.vout.size() < txIn.prevout.n) return false; - CScript spk = tx.vout[txIn.prevout.n].scriptPubKey; - if (spk.size() != 35) return false; - std::vector scriptVec = std::vector(spk.begin(),spk.end()); - const unsigned char *pk = scriptVec.data(); - if (pk++[0] != 33) return false; - if (pk[33] != OP_CHECKSIG) return false; - - // Check it's a notary - for (int i=0; i params, const CTransaction &imp if (!UnmarshalImportTx(importTx, proof, burnTx, payouts)) return Invalid("invalid-params"); - + // Control all aspects of this transaction // It should not be at all malleable if (MakeImportCoinTransaction(proof, burnTx, payouts).GetHash() != importTx.GetHash()) @@ -83,5 +83,3 @@ bool Eval::ImportCoin(const std::vector params, const CTransaction &imp return Valid(); } - - diff --git a/src/cc/utils.h b/src/cc/utils.h index f0b91962d..69410adbb 100644 --- a/src/cc/utils.h +++ b/src/cc/utils.h @@ -20,6 +20,7 @@ #include "version.h" + /* * Serialisation boilerplate */ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a04e4131a..452e232a6 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -83,6 +83,7 @@ extern uint32_t ASSETCHAIN_INIT, ASSETCHAINS_MAGIC; extern int32_t VERUS_BLOCK_POSUNITS, ASSETCHAINS_LWMAPOS, ASSETCHAINS_SAPLING, ASSETCHAINS_OVERWINTER; extern uint64_t ASSETCHAINS_SUPPLY, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH; +extern int8_t is_STAKED(const char *chain_name); const arith_uint256 maxUint = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); class CMainParams : public CChainParams { @@ -257,7 +258,7 @@ void *chainparams_commandline(void *ptr) if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH) { // this is only good for 60 second blocks with an averaging window of 45. for other parameters, use: - // nLwmaAjustedWeight = (N+1)/2 * (0.9989^(500/nPowAveragingWindow)) * nPowTargetSpacing + // nLwmaAjustedWeight = (N+1)/2 * (0.9989^(500/nPowAveragingWindow)) * nPowTargetSpacing mainParams.consensus.nLwmaAjustedWeight = 1350; mainParams.consensus.nPowAveragingWindow = 45; mainParams.consensus.powAlternate = uint256S("00000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); @@ -632,7 +633,7 @@ public: BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); nEquihashN = N; nEquihashK = K; - + genesis = CreateGenesisBlock( 1296688602, uint256S("0x0000000000000000000000000000000000000000000000000000000000000009"), diff --git a/src/coins.h b/src/coins.h index 39d1e22fc..28667966e 100644 --- a/src/coins.h +++ b/src/coins.h @@ -26,7 +26,7 @@ #include "zcash/IncrementalMerkleTree.hpp" //#include "veruslaunch.h" -/** +/** * Pruned version of CTransaction: only retains metadata and unspent transaction outputs * * Serialized format: @@ -428,10 +428,10 @@ public: class CCoinsViewCache; -/** +/** * A reference to a mutable cache entry. Encapsulating it allows us to run * cleanup code after the modification is finished, and keeping track of - * concurrent modifications. + * concurrent modifications. */ class CCoinsModifier { @@ -488,7 +488,7 @@ protected: /** * Make mutable so that we can "fill the cache" even from Get-methods - * declared as "const". + * declared as "const". */ mutable uint256 hashBlock; mutable CCoinsMap cacheCoins; @@ -564,7 +564,7 @@ public: //! Calculate the size of the cache (in bytes) size_t DynamicMemoryUsage() const; - /** + /** * Amount of bitcoins coming in to a transaction * Note that lightweight clients may not know anything besides the hash of previous transactions, * so may not be able to calculate this. diff --git a/src/crosschain.cpp b/src/crosschain.cpp index e9444c607..a88eb9fb7 100644 --- a/src/crosschain.cpp +++ b/src/crosschain.cpp @@ -51,7 +51,7 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh int seenOwnNotarisations = 0; - bool txscl = IsTXSCL(symbol); + int authority = GetSymbolAuthority(symbol); for (int i=0; i kmdHeight) break; @@ -75,13 +75,20 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh if (seenOwnNotarisations == 1) { BOOST_FOREACH(Notarisation& nota, notarisations) { - if (IsTXSCL(nota.second.symbol) == txscl) - if (nota.second.ccId == targetCCid) - moms.push_back(nota.second.MoM); + if (GetSymbolAuthority(nota.second.symbol) == authority) + if (nota.second.ccId == targetCCid) { + moms.push_back(nota.second.MoM); + //fprintf(stderr, "added mom: %s\n",nota.second.MoM.GetHex().data()); + } } } } + // Not enough own notarisations found to return determinate MoMoM + destNotarisationTxid = uint256(); + moms.clear(); + return uint256(); + end: return GetMerkleRoot(moms); } diff --git a/src/crosschain.h b/src/crosschain.h index 1fbd7603a..b59037cc8 100644 --- a/src/crosschain.h +++ b/src/crosschain.h @@ -3,6 +3,18 @@ #include "cc/eval.h" +const int CROSSCHAIN_KOMODO = 1; +const int CROSSCHAIN_TXSCL = 2; +const int CROSSCHAIN_STAKED = 3; + +typedef struct CrosschainAuthority { + uint8_t notaries[64][33]; + int8_t size; + int8_t requiredSigs; +} CrosschainAuthority; + +int GetSymbolAuthority(const char* symbol); +bool CheckTxAuthority(const CTransaction &tx, CrosschainAuthority auth); /* On assetchain */ TxProof GetAssetchainProof(uint256 hash); diff --git a/src/crosschain_authority.cpp b/src/crosschain_authority.cpp new file mode 100644 index 000000000..b4379c010 --- /dev/null +++ b/src/crosschain_authority.cpp @@ -0,0 +1,71 @@ +#include "cc/eval.h" +#include "crosschain.h" +#include "notarisationdb.h" +#include "notaries_staked.h" + +int GetSymbolAuthority(const char* symbol) +{ + if (strncmp(symbol, "TXSCL", 5) == 0) + return CROSSCHAIN_TXSCL; + if (is_STAKED(symbol) != 0) { + //printf("RETURNED CROSSCHAIN STAKED AS TRUE\n"); + return CROSSCHAIN_STAKED; + } + //printf("RETURNED CROSSCHAIN KOMODO AS TRUE\n"); + return CROSSCHAIN_KOMODO; +} + + +bool CheckTxAuthority(const CTransaction &tx, CrosschainAuthority auth) +{ + EvalRef eval; + + if (tx.vin.size() < auth.requiredSigs) return false; + + uint8_t seen[64] = {0}; + + BOOST_FOREACH(const CTxIn &txIn, tx.vin) + { + // Get notary pubkey + CTransaction tx; + uint256 hashBlock; + if (!eval->GetTxUnconfirmed(txIn.prevout.hash, tx, hashBlock)) return false; + if (tx.vout.size() < txIn.prevout.n) return false; + CScript spk = tx.vout[txIn.prevout.n].scriptPubKey; + if (spk.size() != 35) return false; + const unsigned char *pk = &spk[0]; + if (pk++[0] != 33) return false; + if (pk[33] != OP_CHECKSIG) return false; + + // Check it's a notary + for (int i=0; iMoM,sp->MoMdepth); if ( ASSETCHAINS_SYMBOL[0] != 0 ) printf("[%s] ht.%d NOTARIZED.%d %s.%s %sTXID.%s lens.(%d %d) MoM.%s %d\n",ASSETCHAINS_SYMBOL,height,*notarizedheightp,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,srchash.ToString().c_str(),ASSETCHAINS_SYMBOL[0]==0?"BTC":"KMD",desttxid.ToString().c_str(),opretlen,len,sp->MoM.ToString().c_str(),sp->MoMdepth); + //if ( is_STAKED != 0 ) + //{ + // HERE we should add the notarisation to libscotts DB. + //} if ( ASSETCHAINS_SYMBOL[0] == 0 ) { if ( signedfp == 0 ) @@ -756,7 +761,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr printf("ISRATIFICATION (%s)\n",(char *)&scriptbuf[len+32*2+4]); } } - + if ( *isratificationp == 0 && (signedmask != 0 || (scriptbuf[len] != 'X' && scriptbuf[len] != 'A')) ) // && scriptbuf[len] != 'I') komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen,j,zero,0); } @@ -796,6 +801,8 @@ int32_t komodo_notarycmp(uint8_t *scriptPubKey,int32_t scriptlen,uint8_t pubkeys void komodo_connectblock(CBlockIndex *pindex,CBlock& block) { static int32_t hwmheight; + int32_t staked_era; static int32_t lastStakedEra; + uint64_t signedmask,voutmask; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; uint8_t scriptbuf[10001],pubkeys[64][33],rmd160[20],scriptPubKey[35]; uint256 zero,btctxid,txhash; int32_t i,j,k,numnotaries,notarized,scriptlen,isratification,nid,numvalid,specialtx,notarizedheight,notaryid,len,numvouts,numvins,height,txn_count; @@ -807,7 +814,29 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) fprintf(stderr,"unexpected null komodostateptr.[%s]\n",ASSETCHAINS_SYMBOL); return; } - //fprintf(stderr,"%s connect.%d\n",ASSETCHAINS_SYMBOL,pindex->GetHeight()); + //fprintf(stderr,"%s connect.%d\n",ASSETCHAINS_SYMBOL,pindex->nHeight); + if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 || IS_STAKED_NOTARY > -1 ) + { + staked_era = STAKED_era(pindex->GetBlockTime()); + if ( staked_era != lastStakedEra ) + { + uint8_t tmp_pubkeys[64][33]; + int8_t numSN = numStakedNotaries(tmp_pubkeys,staked_era); + UpdateNotaryAddrs(tmp_pubkeys,numSN); + STAKED_ERA = staked_era; + if ( NOTARYADDRS[0][0] != 0 && NOTARY_PUBKEY33[0] != 0 ) + { + if ( (IS_STAKED_NOTARY= updateStakedNotary()) > -1 ) + { + IS_KOMODO_NOTARY = 0; + if ( MIN_RECV_SATS == -1 ) + MIN_RECV_SATS = 100000000; + fprintf(stderr, "Staked Notary Protection Active! NotaryID.%d RADD.%s ERA.%d MIN_TX_VALUE.%lu \n",IS_STAKED_NOTARY,NOTARY_ADDRESS.c_str(),staked_era,MIN_RECV_SATS); + } + } + } + lastStakedEra = staked_era; + } numnotaries = komodo_notaries(pubkeys,pindex->GetHeight(),pindex->GetBlockTime()); calc_rmd160_sha256(rmd160,pubkeys[0],33); if ( pindex->GetHeight() > hwmheight ) @@ -830,6 +859,10 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) txn_count = block.vtx.size(); for (i=0; i= KOMODO_MINRATIFY) || + if ( ((height < 90000 || (signedmask & 1) != 0) && numvalid >= KOMODO_MINRATIFY) || (numvalid >= KOMODO_MINRATIFY && ASSETCHAINS_SYMBOL[0] != 0) || - numvalid > (numnotaries/5)) ) + numvalid > (numnotaries/5) ) { - if ( ASSETCHAINS_SYMBOL[0] != 0 ) + if ( ASSETCHAINS_SYMBOL[0] != 0) { static FILE *signedfp; if ( signedfp == 0 ) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 096590563..a342bb459 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1670,9 +1670,7 @@ int64_t komodo_checkcommission(CBlock *pblock,int32_t height) { checktoshis = komodo_commission(pblock,height); //fprintf(stderr,"height.%d commission %.8f\n",height,(double)checktoshis/COIN); - /*if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 ) jl777: not sure why this was here - return(-1); - else*/ if ( checktoshis != 0 ) + if ( checktoshis != 0 ) { script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0]; scriptlen = (int32_t)pblock->vtx[0].vout[1].scriptPubKey.size(); diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d42adc6b9..910fc24ec 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -90,7 +90,7 @@ struct pax_transaction *komodo_paxmark(int32_t height,uint256 txid,uint16_t vout pax->marked = mark; //if ( height > 214700 || pax->height > 214700 ) // printf("mark ht.%d %.8f %.8f\n",pax->height,dstr(pax->komodoshis),dstr(pax->fiatoshis)); - + } pthread_mutex_unlock(&komodo_mutex); return(pax); @@ -203,9 +203,9 @@ int32_t komodo_issued_opreturn(char *base,uint256 *txids,uint16_t *vouts,int64_t // return(0); incr = 34 + (iskomodo * (2*sizeof(fiatoshis) + 2*sizeof(height) + 20 + 4)); //41e77b91cb68dc2aa02fa88550eae6b6d44db676a7e935337b6d1392d9718f03cb0200305c90660400000000fbcbeb1f000000bde801006201000058e7945ad08ddba1eac9c9b6c8e1e97e8016a2d152 - + // 41e94d736ec69d88c08b5d238abeeca609c02357a8317e0d56c328bcb1c259be5d0200485bc80200000000404b4c000000000059470200b80b000061f22ba7d19fe29ac3baebd839af8b7127d1f9075553440046bb4cc7a3b5cd39dffe7206507a3482a00780e617f68b273cce9817ed69298d02001069ca1b0000000080f0fa02000000005b470200b90b000061f22ba7d19fe29ac3baebd839af8b7127d1f90755 - + //for (i=0; i= KOMODO_NOTARIES_HARDCODED || ASSETCHAINS_SYMBOL[0] != 0 ) + + // If this chain is not a staked chain, use the normal Komodo logic to determine notaries. This allows KMD to still sync and use its proper pubkeys for dPoW. + if (is_STAKED(ASSETCHAINS_SYMBOL) == 0) { + if ( height >= KOMODO_NOTARIES_HARDCODED || ASSETCHAINS_SYMBOL[0] != 0 ) + timestamp = 0; if ( (timestamp != 0 && timestamp <= KOMODO_NOTARIES_TIMESTAMP1) || (ASSETCHAINS_SYMBOL[0] == 0 && height <= KOMODO_NOTARIES_HEIGHT1) ) { if ( did0 == 0 ) { n0 = (int32_t)(sizeof(Notaries_elected0)/sizeof(*Notaries_elected0)); - for (i=0; i= KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP ) htind = (KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP) - 1; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 335d9a8cf..41e34bd6a 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1538,7 +1538,8 @@ uint16_t komodo_port(char *symbol,uint64_t supply,uint32_t *magicp,uint8_t *extr printf("ports\n"); }*/ -char *iguanafmtstr = (char *)"curl --url \"http://127.0.0.1:7776\" --data \"{\\\"conf\\\":\\\"%s.conf\\\",\\\"path\\\":\\\"${HOME#\"/\"}/.komodo/%s\\\",\\\"unitval\\\":\\\"20\\\",\\\"zcash\\\":1,\\\"RELAY\\\":-1,\\\"VALIDATE\\\":0,\\\"prefetchlag\\\":-1,\\\"poll\\\":100,\\\"active\\\":1,\\\"agent\\\":\\\"iguana\\\",\\\"method\\\":\\\"addcoin\\\",\\\"startpend\\\":4,\\\"endpend\\\":4,\\\"services\\\":129,\\\"maxpeers\\\":8,\\\"newcoin\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\",\\\"hasheaders\\\":1,\\\"useaddmultisig\\\":0,\\\"netmagic\\\":\\\"%s\\\",\\\"p2p\\\":%u,\\\"rpc\\\":%u,\\\"pubval\\\":60,\\\"p2shval\\\":85,\\\"wifval\\\":188,\\\"txfee_satoshis\\\":\\\"10000\\\",\\\"isPoS\\\":0,\\\"minoutput\\\":10000,\\\"minconfirms\\\":2,\\\"genesishash\\\":\\\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\\\",\\\"protover\\\":170002,\\\"genesisblock\\\":\\\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\\\",\\\"debug\\\":0,\\\"seedipaddr\\\":\\\"%s\\\"}\""; +char *iguanafmtstr = (char *)"curl --url \"http://127.0.0.1:7776\" --data \"{\\\"conf\\\":\\\"%s.conf\\\",\\\"path\\\":\\\"${HOME#\"/\"}/.komodo/%s\\\",\\\"unitval\\\":\\\"20\\\",\\\"zcash\\\":1,\\\"RELAY\\\":-1,\\\"VALIDATE\\\":0,\\\"prefetchlag\\\":-1,\\\"poll\\\":100,\\\"active\\\":1,\\\"agent\\\":\\\"iguana\\\",\\\"method\\\":\\\"addcoin\\\",\\\"startpend\\\":4,\\\"endpend\\\":4,\\\"services\\\":129,\\\"maxpeers\\\":8,\\\"newcoin\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\",\\\"hasheaders\\\":1,\\\"useaddmultisig\\\":0,\\\"netmagic\\\":\\\"%s\\\",\\\"p2p\\\":%u,\\\"rpc\\\":%u,\\\"pubval\\\":60,\\\"p2shval\\\":85,\\\"wifval\\\":188,\\\"txfee_satoshis\\\":\\\"10000\\\",\\\"isPoS\\\":0,\\\"minoutput\\\":10000,\\\"minconfirms\\\":2,\\\"genesishash\\\":\\\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\\\",\\\"protover\\\":170002,\\\"genesisblock\\\":\\\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\\\",\\\"debug\\\":0,\\\"seedipaddr\\\":\\\"%s\\\",\\\"sapling\\\":1}\""; + int32_t komodo_whoami(char *pubkeystr,int32_t height,uint32_t timestamp) @@ -1655,14 +1656,18 @@ void komodo_args(char *argv0) { extern const char *Notaries_elected1[][2]; std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,baseid,len,n,extralen = 0; - IS_KOMODO_NOTARY = GetBoolArg("-notary", false); - + IS_KOMODO_NOTARY = GetBoolArg("-notary", false); + IS_STAKED_NOTARY = GetArg("-stakednotary", -1); + if ( IS_STAKED_NOTARY != -1 && IS_KOMODO_NOTARY == true ) { + fprintf(stderr, "Cannot be STAKED and KMD notary at the same time!\n"); + exit(0); + } + MIN_RECV_SATS = GetArg("-mintxvalue",-1); + WHITELIST_ADDRESS = GetArg("-whitelistaddress",""); if ( GetBoolArg("-gen", false) != 0 ) { KOMODO_MININGTHREADS = GetArg("-genproclimit",-1); } - else KOMODO_MININGTHREADS = 0; - if ( (KOMODO_EXCHANGEWALLET= GetBoolArg("-exchange", false)) != 0 ) fprintf(stderr,"KOMODO_EXCHANGEWALLET mode active\n"); DONATION_PUBKEY = GetArg("-donation", ""); @@ -1679,13 +1684,13 @@ void komodo_args(char *argv0) IS_KOMODO_NOTARY = 1; KOMODO_MININGTHREADS = 1; mapArgs ["-genproclimit"] = itostr(KOMODO_MININGTHREADS); + IS_STAKED_NOTARY = -1; fprintf(stderr,"running as notary.%d %s\n",i,Notaries_elected1[i][0]); break; } } - //KOMODO_PAX = 1; - } //else KOMODO_PAX = GetArg("-pax",0); - name = GetArg("-ac_name",""); + } + name = GetArg("-ac_name",""); if ( argv0 != 0 ) { len = (int32_t)strlen(argv0); @@ -1709,7 +1714,7 @@ void komodo_args(char *argv0) { printf("KOMODO_REWIND %d\n",KOMODO_REWIND); } - if ( name.c_str()[0] != 0 ) + if ( name.c_str()[0] != 0 ) { std::string selectedAlgo = GetArg("-ac_algo", std::string(ASSETCHAINS_ALGORITHMS[0])); @@ -1773,7 +1778,6 @@ void komodo_args(char *argv0) ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0); ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey",""); ASSETCHAINS_SCRIPTPUB = GetArg("-ac_script",""); - //ASSETCHAINS_FOUNDERS_PERIOD = GetArg("-ac_period",0); if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 ) ASSETCHAINS_STAKED = 100; @@ -1807,7 +1811,7 @@ void komodo_args(char *argv0) ASSETCHAINS_COMMISSION = 53846154; // maps to 35% printf("ASSETCHAINS_COMMISSION defaulted to 35%% when founders reward active\n"); } - else + else { ASSETCHAINS_OVERRIDE_PUBKEY.clear(); printf("-ac_perc must be set with -ac_pubkey\n"); @@ -1819,12 +1823,12 @@ void komodo_args(char *argv0) if ( ASSETCHAINS_COMMISSION != 0 ) { ASSETCHAINS_COMMISSION = 0; - printf("ASSETCHAINS_COMMISSION needs an ASETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n"); + printf("ASSETCHAINS_COMMISSION needs an ASSETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n"); } if ( ASSETCHAINS_FOUNDERS != 0 ) { ASSETCHAINS_FOUNDERS = 0; - printf("ASSETCHAINS_FOUNDERS needs an ASETCHAINS_OVERRIDE_PUBKEY\n"); + printf("ASSETCHAINS_FOUNDERS needs an ASSETCHAINS_OVERRIDE_PUBKEY or ASSETCHAINS_SCRIPTPUB\n"); } } if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 ) diff --git a/src/main.cpp b/src/main.cpp index b29b20ac9..1385ab69b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "main.h" - +#include "notaries_staked.h" #include "sodium.h" #include "addrman.h" @@ -33,6 +33,7 @@ #include "validationinterface.h" #include "wallet/asyncrpcoperation_sendmany.h" #include "wallet/asyncrpcoperation_shieldcoinbase.h" +#include "notaries_staked.h" #include #include @@ -1020,10 +1021,9 @@ bool ContextualCheckTransaction( // If Sprout rules apply, reject transactions which are intended for Overwinter and beyond if (isSprout && tx.fOverwintered) { - return state.DoS(isInitBlockDownload() ? 0 : dosLevel, - error("ContextualCheckTransaction(): ht.%d activates.%d dosLevel.%d overwinter is not active yet", - nHeight, Params().GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight, dosLevel), - REJECT_INVALID, "tx-overwinter-not-active"); + int32_t ht = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight; + return state.DoS((ht < 0 || nHeight < ht) ? 0 : dosLevel,error("ContextualCheckTransaction(): ht.%d activates.%d dosLevel.%d overwinter is not active yet",nHeight, Params().GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight, dosLevel),REJECT_INVALID, "tx-overwinter-not-active"); + //return state.DoS(isInitBlockDownload() ? 0 : dosLevel,error("ContextualCheckTransaction(): ht.%d activates.%d dosLevel.%d overwinter is not active yet",nHeight, Params().GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight, dosLevel),REJECT_INVALID, "tx-overwinter-not-active"); } if (saplingActive) { @@ -1080,8 +1080,8 @@ bool ContextualCheckTransaction( if (overwinterActive) { // Reject transactions intended for Sprout if (!tx.fOverwintered) { - return state.DoS(dosLevel, error("ContextualCheckTransaction: overwinter is active"), - REJECT_INVALID, "tx-overwinter-active"); + int32_t ht = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight; + return state.DoS((ht < 0 || nHeight < ht) ? 0 : dosLevel, error("ContextualCheckTransaction: overwinter is active"),REJECT_INVALID, "tx-overwinter-active"); } // Check that all transactions are unexpired @@ -1237,25 +1237,40 @@ bool CheckTransaction(uint32_t tiptime,const CTransaction& tx, CValidationState } } +extern char NOTARYADDRS[64][36]; +extern uint8_t NUM_NOTARIES; + int32_t komodo_isnotaryvout(char *coinaddr) // from ac_private chains only { - static int32_t didinit; static char notaryaddrs[sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) + 1][64]; - int32_t i; - if ( didinit == 0 ) - { - uint8_t pubkey33[33]; - for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++) - { - if ( i < sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) ) - decode_hex(pubkey33,33,(char *)Notaries_elected1[i][1]); - else decode_hex(pubkey33,33,(char *)CRYPTO777_PUBSECPSTR); - pubkey2addr((char *)notaryaddrs[i],(uint8_t *)pubkey33); - } - didinit = 1; - } - for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++) + if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 ) + { + if ( NOTARYADDRS[0][0] != 0 && NUM_NOTARIES != 0 ) + { + for (int32_t i=0; i<=NUM_NOTARIES; i++) + if ( strcmp(coinaddr,NOTARYADDRS[i]) == 0 ) + return(1); + } + } + else + { + static int32_t didinit; static char notaryaddrs[sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) + 1][64]; + int32_t i; + if ( didinit == 0 ) + { + uint8_t pubkey33[33]; + for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++) + { + if ( i < sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) ) + decode_hex(pubkey33,33,(char *)Notaries_elected1[i][1]); + else decode_hex(pubkey33,33,(char *)CRYPTO777_PUBSECPSTR); + pubkey2addr((char *)notaryaddrs[i],(uint8_t *)pubkey33); + } + didinit = 1; + } + for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++) if ( strcmp(coinaddr,notaryaddrs[i]) == 0 ) return(1); + } return(0); } @@ -1309,9 +1324,11 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio // Transactions containing empty `vin` must have either non-empty // `vjoinsplit` or non-empty `vShieldedSpend`. - if (tx.vin.empty() && tx.vjoinsplit.empty() && tx.vShieldedSpend.empty()) + if (tx.vin.empty() && tx.vjoinsplit.empty() && tx.vShieldedSpend.empty()) { + fprintf(stderr,"vin empty for tx: %s\n",tx.GetHash().ToString().c_str()); return state.DoS(10, error("CheckTransaction(): vin empty"), REJECT_INVALID, "bad-txns-vin-empty"); + } // Transactions containing empty `vout` must have either non-empty // `vjoinsplit` or non-empty `vShieldedOutput`. if (tx.vout.empty() && tx.vjoinsplit.empty() && tx.vShieldedOutput.empty()) @@ -1447,7 +1464,7 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio { static uint32_t counter; if ( counter++ < 10 ) - fprintf(stderr,"found taddr in private chain: z_z.%d z_t.%d t_z.%d\n",z_z,z_t,t_z); + fprintf(stderr,"found taddr in private chain: z_z.%d z_t.%d t_z.%d vinsize.%d\n",z_z,z_t,t_z,(int32_t)tx.vin.size()); if ( z_t == 0 || z_z != 0 || t_z != 0 || tx.vin.size() != 0 ) return state.DoS(100, error("CheckTransaction(): this is a private chain, only sprout -> taddr allowed until deadline"),REJECT_INVALID, "bad-txns-acprivacy-chain"); } @@ -1469,6 +1486,24 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio } } + if ( ASSETCHAINS_TXPOW != 0 && tx.vjoinsplit.size() == 0 ) + { + // genesis coinbase 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + uint256 txid = tx.GetHash(); + if ( ((ASSETCHAINS_TXPOW & 2) != 0 && iscoinbase != 0) || ((ASSETCHAINS_TXPOW & 1) != 0 && iscoinbase == 0) ) + { + if ( ((uint8_t *)&txid)[0] != 0 || ((uint8_t *)&txid)[31] != 0 ) + { + uint256 genesistxid = uint256S("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); + if ( txid != genesistxid ) + { + fprintf(stderr,"private chain iscoinbase.%d invalid txpow.%d txid.%s\n",iscoinbase,ASSETCHAINS_TXPOW,txid.GetHex().c_str()); + return state.DoS(100, error("CheckTransaction(): this is a txpow chain, must have 0x00 ends"),REJECT_INVALID, "bad-txns-actxpow-chain"); + } + } + } + } + // Ensure input values do not exceed MAX_MONEY // We have not resolved the txin values at this stage, // but we do know what the joinsplits claim to add @@ -1568,7 +1603,6 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree) { - extern int32_t KOMODO_ON_DEMAND; { LOCK(mempool.cs); uint256 hash = tx.GetHash(); @@ -1754,6 +1788,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa //fprintf(stderr,"accept failure.2\n"); return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met"); } + // Bring the best block into scope view.GetBestBlock(); @@ -1894,8 +1929,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa KOMODO_CONNECTING = -1; // Store transaction in memory - if ( komodo_is_notarytx(tx) == 0 ) - KOMODO_ON_DEMAND++; pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); if (!tx.IsCoinImport()) @@ -3275,13 +3308,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin { if (!view.HaveInputs(tx)) { - return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), + return state.DoS(100, error("ConnectBlock(): inputs missing/spent %s",tx.GetHash().ToString().c_str()), REJECT_INVALID, "bad-txns-inputs-missingorspent"); } // are the JoinSplit's requirements met? if (!view.HaveJoinSplitRequirements(tx)) return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"), REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met"); + if (fAddressIndex || fSpentIndex) { for (size_t j = 0; j < tx.vin.size(); j++) { @@ -3810,13 +3844,16 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), newSaplingTree)); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: + std::vector TxToRemove; for (int i = 0; i < block.vtx.size(); i++) { CTransaction &tx = block.vtx[i]; //if ((i == (block.vtx.size() - 1)) && ((ASSETCHAINS_LWMAPOS && block.IsVerusPOSBlock()) || (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block) != 0)))) if ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block) != 0))) { - EraseFromWallets(tx.GetHash()); +#ifdef ENABLE_WALLET + pwalletMain->EraseFromWallet(tx.GetHash()); +#endif } else { @@ -3884,9 +3921,7 @@ int32_t komodo_activate_sapling(CBlockIndex *pindex) } if ( activation != 0 ) { -//#if KOMODO_SAPLING_ACTIVATION != 1544832000 komodo_setactivation(activation); -//#endif fprintf(stderr,"%s sapling activation at %d\n",ASSETCHAINS_SYMBOL,activation); ASSETCHAINS_SAPLING = activation; } @@ -6535,7 +6570,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } -//fprintf(stderr,"netmsg: %s\n", strCommand.c_str()); + //fprintf(stderr,"netmsg: %s\n", strCommand.c_str()); if (strCommand == "version") { @@ -6552,16 +6587,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CAddress addrFrom; uint64_t nNonce = 1; int nVersion; // use temporary for version, don't set version number until validated as connected + int minVersion = MIN_PEER_PROTO_VERSION; + if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 ) + minVersion = STAKEDMIN_PEER_PROTO_VERSION; vRecv >> nVersion >> pfrom->nServices >> nTime >> addrMe; if (nVersion == 10300) nVersion = 300; - - if (nVersion < MIN_PEER_PROTO_VERSION) + if (nVersion < minVersion) { // disconnect from peers older than this proto version LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)); + strprintf("Version must be %d or greater", minVersion)); pfrom->fDisconnect = true; return false; } diff --git a/src/miner.cpp b/src/miner.cpp index 5c8109f40..bce67d116 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -122,11 +122,11 @@ extern bool VERUS_MINTBLOCKS; extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[]; extern const char *ASSETCHAINS_ALGORITHMS[]; extern int32_t VERUS_MIN_STAKEAGE, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_LWMAPOS, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[]; -extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],NOTARYADDRS[64][36]; extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY,ASSETCHAINS_SCRIPTPUB; void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len); -extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33]; +extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],NUM_NOTARIES; uint32_t Mining_start,Mining_height; int32_t My_notaryid = -1; int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp); @@ -140,6 +140,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig, CPubKey &pk); int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33); int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); +int32_t komodo_is_notarytx(const CTransaction& tx); CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake) { @@ -264,12 +265,17 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount, double dPriority = 0; CAmount nTotalIn = 0; bool fMissingInputs = false; + bool fNotarisation = false; if (tx.IsCoinImport()) { CAmount nValueIn = GetCoinImportValue(tx); nTotalIn += nValueIn; dPriority += (double)nValueIn * 1000; // flat multiplier } else { + int numNotaryVins = 0; bool fToCryptoAddress = false; + if ( komodo_is_notarytx(tx) == 1 ) + fToCryptoAddress = true; + BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Read prev transaction @@ -308,8 +314,23 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount, int nConf = nHeight - coins->nHeight; + if ( NOTARYADDRS[0][0] != 0 && NUM_NOTARIES != 0 && fToCryptoAddress ) + { + uint256 hash; CTransaction tx1; CTxDestination address; + if (GetTransaction(txin.prevout.hash,tx1,hash,false)) + { + if (ExtractDestination(tx1.vout[txin.prevout.n].scriptPubKey, address)) { + for (int i = 0; i < NUM_NOTARIES; i++) { + if ( strcmp(NOTARYADDRS[i],CBitcoinAddress(address).ToString().c_str()) == 0 ) + numNotaryVins++; + } + } + } + } dPriority += (double)nValueIn * nConf; } + if ( NUM_NOTARIES != 0 && numNotaryVins >= NUM_NOTARIES / 5 ) + fNotarisation = true; nTotalIn += tx.GetShieldedValueIn(); } @@ -324,6 +345,11 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount, CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize); + if (fNotarisation) { + dPriority = 1e16; + fprintf(stderr, "Notarisation.%s set to maximum priority.\n",hash.ToString().c_str()); + } + if (porphan) { porphan->dPriority = dPriority; @@ -734,8 +760,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, { //fprintf(stderr,"use notary pubkey\n"); scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; - } - else + } else { //if ( !isStake || ASSETCHAINS_STAKED != 0 ) { @@ -746,10 +771,10 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, scriptPubKey.resize(35); ptr = (uint8_t *)pubkey.begin(); scriptPubKey[0] = 33; - for (i=0; i<33; i++) + for (i=0; i<33; i++) { scriptPubKey[i+1] = ptr[i]; + } scriptPubKey[34] = OP_CHECKSIG; - //scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; } } return CreateNewBlock(scriptPubKey, gpucount, isStake); @@ -1542,16 +1567,16 @@ void static BitcoinMiner() } //else fprintf(stderr,"duplicate at j.%d\n",j); } else Mining_start = 0; } else Mining_start = 0; - if ( ASSETCHAINS_STAKED != 0 ) + if ( ASSETCHAINS_STAKED > 0 ) { int32_t percPoS,z; bool fNegative,fOverflow; HASHTarget_POW = komodo_PoWtarget(&percPoS,HASHTarget,Mining_height,ASSETCHAINS_STAKED); HASHTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); if ( ASSETCHAINS_STAKED < 100 ) { - for (z=31; z>=0; z--) - fprintf(stderr,"%02x",((uint8_t *)&HASHTarget_POW)[z]); - fprintf(stderr," PoW for staked coin PoS %d%% vs target %d%%\n",percPoS,(int32_t)ASSETCHAINS_STAKED); + //for (z=31; z>=0; z--) + // fprintf(stderr,"%02x",((uint8_t *)&HASHTarget_POW)[z]); + LogPrintf("Block %d : PoS %d%% vs target %d%% \n",Mining_height,percPoS,(int32_t)ASSETCHAINS_STAKED); } } while (true) @@ -1612,7 +1637,7 @@ void static BitcoinMiner() if ( h > hashTarget ) { //if ( ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0 ) - // sleep(1); + // MilliSleep(30); return false; } if ( IS_KOMODO_NOTARY != 0 && B.nTime > GetAdjustedTime() ) diff --git a/src/net.cpp b/src/net.cpp index 85bb8a13e..87abe8e85 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1260,9 +1260,17 @@ void ThreadSocketHandler() } } - void ThreadDNSAddressSeed() { + extern int8_t is_STAKED(const char *chain_name); + extern char ASSETCHAINS_SYMBOL[65]; + // skip DNS seeds for staked chains. + if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 ) + { + fprintf(stderr, "STAKED CHAIN DISABLED ALL SEEDS!\n"); + return; + } + // goal: only query DNS seeds if address need is acute if ((addrman.size() > 0) && (!GetBoolArg("-forcednsseed", false))) { @@ -1372,13 +1380,19 @@ void ThreadOpenConnections() // Add seed nodes if DNS seeds are all down (an infrastructure attack?). // if (addrman.size() == 0 && (GetTime() - nStart > 60)) { - if (GetTime() - nStart > 60) { - static bool done = false; - if (!done) { - //LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); - LogPrintf("Adding fixed seed nodes.\n"); - addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1")); - done = true; + extern int8_t is_STAKED(const char *chain_name); + extern char ASSETCHAINS_SYMBOL[65]; + // skip DNS seeds for staked chains. + if ( is_STAKED(ASSETCHAINS_SYMBOL) == 0 ) + { + if (GetTime() - nStart > 60) { + static bool done = false; + if (!done) { + //LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); + LogPrintf("Adding fixed seed nodes.\n"); + addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1")); + done = true; + } } } diff --git a/src/netbase.cpp b/src/netbase.cpp index 7369b0167..baae83e4a 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -511,7 +511,8 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe else #endif { - LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); + if ( NetworkErrorString(WSAGetLastError()) != "Network is unreachable (101)") + LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); CloseSocket(hSocket); return false; } diff --git a/src/notaries_staked.cpp b/src/notaries_staked.cpp new file mode 100644 index 000000000..e53553b23 --- /dev/null +++ b/src/notaries_staked.cpp @@ -0,0 +1,171 @@ + +#include "notaries_staked.h" +#include "crosschain.h" +#include "cc/CCinclude.h" +#include + +extern char NOTARYADDRS[64][36]; +extern std::string NOTARY_ADDRESS,NOTARY_PUBKEY; +extern int32_t STAKED_ERA,IS_STAKED_NOTARY,IS_KOMODO_NOTARY; +extern pthread_mutex_t staked_mutex; +extern uint8_t NOTARY_PUBKEY33[33],NUM_NOTARIES; + +int8_t is_STAKED(const char *chain_name) { + int STAKED = 0; + if ( (strcmp(chain_name, "LABS") == 0) || (strncmp(chain_name, "LABS", 4) == 0) ) + STAKED = 1; + else if ( (strcmp(chain_name, "LAB") == 0) || (strncmp(chain_name, "LAB", 3) == 0) ) + STAKED = 2; + else if ( (strcmp(chain_name, "CFEK") == 0) || (strncmp(chain_name, "CFEK", 4) == 0) ) + STAKED = 3; + //fprintf(stderr, "This chain is: %s which is: %d\n", chain_name,STAKED); + return(STAKED); +}; + +int32_t STAKED_era(int timestamp) +{ + int8_t era = 0; + if (timestamp <= STAKED_NOTARIES_TIMESTAMP[0]) + return(1); + for (int32_t i = 1; i < NUM_STAKED_ERAS; i++) + { + if (timestamp <= STAKED_NOTARIES_TIMESTAMP[i] && timestamp >= (STAKED_NOTARIES_TIMESTAMP[i-1] + STAKED_ERA_GAP)) + return(i+1); + } + // if we are in a gap, return era 0, this allows to invalidate notarizations when in GAP. + return(0); +}; + +int8_t updateStakedNotary() { + std::string notaryname; + char Raddress[18]; uint8_t pubkey33[33]; + decode_hex(pubkey33,33,(char *)NOTARY_PUBKEY.c_str()); + pubkey2addr((char *)Raddress,(uint8_t *)pubkey33); + NOTARY_ADDRESS.clear(); + NOTARY_ADDRESS.assign(Raddress); + return(StakedNotaryID(notaryname,Raddress)); +} + +int8_t StakedNotaryID(std::string ¬aryname, char *Raddress) { + if ( STAKED_ERA != 0 ) + { + for (int8_t i = 0; i < num_notaries_STAKED[STAKED_ERA-1]; i++) { + if ( strcmp(Raddress,NOTARYADDRS[i]) == 0 ) { + notaryname.assign(notaries_STAKED[STAKED_ERA-1][i][0]); + return(i); + } + } + } + return(-1); +} + +int8_t numStakedNotaries(uint8_t pubkeys[64][33],int8_t era) { + int i; int8_t retval = 0; + static uint8_t staked_pubkeys1[64][33],staked_pubkeys2[64][33],didstaked1,didstaked2; + static uint8_t staked_pubkeys3[64][33],staked_pubkeys4[64][33],didstaked3,didstaked4; + static char ChainName[65]; + + if ( ChainName[0] == 0 ) + { + if ( ASSETCHAINS_SYMBOL[0] == 0 ) + strcpy(ChainName,"KMD"); + else + strcpy(ChainName,ASSETCHAINS_SYMBOL); + } + + if ( era != 0 ) { + switch (era) { + case 1: + if ( didstaked1 == 0 ) + { + for (i=0; i @@ -17,31 +19,52 @@ NotarisationsInBlock ScanBlockNotarisations(const CBlock &block, int nHeight) { EvalRef eval; NotarisationsInBlock vNotarisations; + CrosschainAuthority auth_STAKED; + int timestamp = block.nTime; for (unsigned int i = 0; i < block.vtx.size(); i++) { CTransaction tx = block.vtx[i]; - // Special case for TXSCL. Should prob be removed at some point. - bool isTxscl = 0; - { - NotarisationData data; - if (ParseNotarisationOpReturn(tx, data)) - if (IsTXSCL(data.symbol)) - isTxscl = 1; + NotarisationData data; + bool parsed = ParseNotarisationOpReturn(tx, data); + if (!parsed) data = NotarisationData(); + if (strlen(data.symbol) == 0) + continue; + + //printf("Checked notarisation data for %s \n",data.symbol); + int authority = GetSymbolAuthority(data.symbol); + + if (authority == CROSSCHAIN_KOMODO) { + if (!eval->CheckNotaryInputs(tx, nHeight, block.nTime)) + continue; + //printf("Authorised notarisation data for %s \n",data.symbol); + } else if (authority == CROSSCHAIN_STAKED) { + // We need to create auth_STAKED dynamically here based on timestamp + int32_t staked_era = STAKED_era(timestamp); + printf("ERA.(%d) \n",staked_era); + if (staked_era == 0) { + // this is an ERA GAP, so we will ignore this notarization + printf("Notarization for %s occured inside an ERA GAP, we will ignore it! \n",data.symbol); + continue; + } else { + // pass era slection off to notaries_staked.cpp file + auth_STAKED = Choose_auth_STAKED(staked_era); + } + printf("minsigs.%i era.%i authsize.%i\n",auth_STAKED.requiredSigs,staked_era,auth_STAKED.size); + if (!CheckTxAuthority(tx, auth_STAKED)) + continue; + printf("Authorised notarisation data for %s \n",data.symbol); } - if (isTxscl || eval->CheckNotaryInputs(tx, nHeight, block.nTime)) { - NotarisationData data; - if (ParseNotarisationOpReturn(tx, data)) { - vNotarisations.push_back(std::make_pair(tx.GetHash(), data)); - //printf("Parsed a notarisation for: %s, txid:%s, ccid:%i, momdepth:%i\n", - // data.symbol, tx.GetHash().GetHex().data(), data.ccId, data.MoMDepth); - //if (!data.MoMoM.IsNull()) printf("MoMoM:%s\n", data.MoMoM.GetHex().data()); - } - else - LogPrintf("WARNING: Couldn't parse notarisation for tx: %s at height %i\n", - tx.GetHash().GetHex().data(), nHeight); - } + if (parsed) { + vNotarisations.push_back(std::make_pair(tx.GetHash(), data)); + printf("Added notarisation data for %s \n",data.symbol); + //printf("Parsed a notarisation for: %s, txid:%s, ccid:%i, momdepth:%i\n", + // data.symbol, tx.GetHash().GetHex().data(), data.ccId, data.MoMDepth); + //if (!data.MoMoM.IsNull()) printf("MoMoM:%s\n", data.MoMoM.GetHex().data()); + } else + LogPrintf("WARNING: Couldn't parse notarisation for tx: %s at height %i\n", + tx.GetHash().GetHex().data(), nHeight); } return vNotarisations; } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index a69a4ebb3..f2bf20e3e 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -606,6 +606,68 @@ UniValue getblockhash(const UniValue& params, bool fHelp) return pblockindex->GetBlockHash().GetHex(); } +extern uint64_t ASSETCHAINS_STAKED; +int32_t komodo_isPoS(CBlock *pblock); +uint32_t komodo_segid32(char *coinaddr); + +UniValue getlastsegidstakes(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getlastsegidstakes depth\n" + "\nReturns object containing the counts of the last X blocks staked by each segid.\n" + "\nArguments:\n" + "1. depth (numeric, required) The amount of blocks to scan back." + "\nResult:\n" + "{\n" + " \"0\" : n, (numeric) number of stakes from segid 0 in the last X blocks.\n" + " .....\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getlastsegidstakes", "1000") + + HelpExampleRpc("getlastsegidstakes", "1000") + ); + + if ( ASSETCHAINS_STAKED == 0 ) + throw runtime_error("Only applies to ac_staked chains\n"); + + LOCK(cs_main); + + int depth = params[0].get_int(); + int32_t segids[64] = {0}; + + for (int64_t i = chainActive.Height(); i > chainActive.Height()-depth; i--) + { + CBlockIndex* pblockindex = chainActive[i]; + CBlock block; + + if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); + + if(!ReadBlockFromDisk(block, pblockindex,1)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + + if ( komodo_isPoS((CBlock *)&block) != 0 ) + { + CTxDestination voutaddress; int32_t segid; + if ( ExtractDestination(block.vtx[block.vtx.size()-1].vout[0].scriptPubKey,voutaddress) ) + { + segid = (int32_t)komodo_segid32((char *)CBitcoinAddress(voutaddress).ToString().c_str()) & 0x3f; + segids[segid] += 1; + } + } + } + + UniValue ret(UniValue::VOBJ); + for (int8_t i = 0; i < 64; i++) + { + char str[4]; + sprintf(str, "%d", i); + ret.push_back(Pair(str,segids[i])); + } + return ret; +} + /*uint256 _komodo_getblockhash(int32_t nHeight) { uint256 hash; @@ -859,7 +921,7 @@ UniValue kvsearch(const UniValue& params, bool fHelp) " \"currentheight\": xxxxx, (numeric) current height of the chain\n" " \"key\": \"xxxxx\", (string) key\n" " \"keylen\": xxxxx, (string) length of the key \n" - " \"owner\": \"xxxxx\" (string) hex string representing the owner of the key \n" + " \"owner\": \"xxxxx\" (string) hex string representing the owner of the key \n" " \"height\": xxxxx, (numeric) height the key was stored at\n" " \"expiration\": xxxxx, (numeric) height the key will expire\n" " \"flags\": x (numeric) 1 if the key was created with a password; 0 otherwise.\n" diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index c4eb16e0e..b60ac8ed3 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -36,6 +36,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "sendtoaddress", 1 }, { "sendtoaddress", 4 }, { "settxfee", 0 }, + { "getnotarysendmany", 0 }, + { "getnotarysendmany", 1 }, { "getreceivedbyaddress", 1 }, { "getreceivedbyaccount", 1 }, { "listreceivedbyaddress", 0 }, @@ -72,6 +74,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listunspent", 2 }, { "getblock", 1 }, { "getblockheader", 1 }, + { "getlastsegidstakes", 0 }, { "gettransaction", 1 }, { "getrawtransaction", 1 }, { "createrawtransaction", 0 }, diff --git a/src/rpc/crosschain.cpp b/src/rpc/crosschain.cpp index dd604124c..7d299fc1a 100644 --- a/src/rpc/crosschain.cpp +++ b/src/rpc/crosschain.cpp @@ -92,7 +92,7 @@ UniValue height_MoM(const UniValue& params, bool fHelp) ret.push_back(Pair("kmdendi",kmdendi)); } } else ret.push_back(Pair("error",(char *)"no MoM for height")); - + return ret; } @@ -171,9 +171,14 @@ UniValue migrate_converttoexport(const UniValue& params, bool fHelp) if (targetSymbol.size() == 0 || targetSymbol.size() > 32) throw runtime_error("targetSymbol length must be >0 and <=32"); + if (strcmp(ASSETCHAINS_SYMBOL,targetSymbol.c_str()) == 0) + throw runtime_error("cant send a coin to the same chain"); + CAmount burnAmount = AmountFromValue(params[2]); if (burnAmount <= 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for export"); + if (burnAmount > 1000000LL*COIN) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for export, cannot export more than 1 million coins per export."); { CAmount needed = 0; for (int i=0; i> burnTx)) throw runtime_error("Couldn't parse burnTx"); - - + + vector payouts; if (!E_UNMARSHAL(ParseHexV(params[1], "argument 2"), ss >> payouts)) throw runtime_error("Couldn't parse payouts"); @@ -242,7 +247,7 @@ UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp) throw runtime_error("migrate_completeimporttransaction importTx\n\n" "Takes a cross chain import tx with proof generated on assetchain " "and extends proof to target chain proof root"); - + if (ASSETCHAINS_SYMBOL[0] != 0) throw runtime_error("Must be called on KMD"); @@ -296,7 +301,7 @@ UniValue scanNotarisationsDB(const UniValue& params, bool fHelp) if (height == 0) { height = chainActive.Height(); } - + Notarisation nota; int matchedHeight = ScanNotarisationsDB(height, symbol, limit, nota); if (!matchedHeight) return NullUniValue; diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 042dd9b00..0bd0ff576 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -332,7 +332,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp) if (params.size() > 0) fGenerate = params[0].get_bool(); - int nGenProcLimit = GetArg("-genproclimit", -1);; + int nGenProcLimit = GetArg("-genproclimit", 0);; if (params.size() > 1) { nGenProcLimit = params[1].get_int(); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 26c273236..007521836 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -13,6 +13,7 @@ #include "timedata.h" #include "txmempool.h" #include "util.h" +#include "notaries_staked.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" #include "wallet/walletdb.h" @@ -51,11 +52,12 @@ bool komodo_txnotarizedconfirmed(uint256 txid); uint32_t komodo_chainactive_timestamp(); int32_t komodo_whoami(char *pubkeystr,int32_t height,uint32_t timestamp); extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; -extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN; +extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN,IS_STAKED_NOTARY,IS_KOMODO_NOTARY,STAKED_ERA; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; uint32_t komodo_segid32(char *coinaddr); int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height); int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp); +int8_t StakedNotaryID(std::string ¬aryname, char *Raddress); #define KOMODO_VERSION "0.3.1" #define VERUS_VERSION "0.4.0g" extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; @@ -64,7 +66,84 @@ extern uint32_t ASSETCHAINS_MAGIC; extern uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY,ASSETCHAINS_LASTERA; extern int32_t ASSETCHAINS_LWMAPOS,ASSETCHAINS_SAPLING; extern uint64_t ASSETCHAINS_ENDSUBSIDY[],ASSETCHAINS_REWARD[],ASSETCHAINS_HALVING[],ASSETCHAINS_DECAY[]; -extern std::string NOTARY_PUBKEY; extern uint8_t NOTARY_PUBKEY33[]; +extern std::string NOTARY_PUBKEY,NOTARY_ADDRESS; extern uint8_t NOTARY_PUBKEY33[]; + +int32_t getera(int now) +{ + for (int32_t i = 0; i < NUM_STAKED_ERAS; i++) { + if ( now <= STAKED_NOTARIES_TIMESTAMP[i] ) { + return(i); + } + } +} + +UniValue getiguanajson(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error("getiguanajson\nreturns json for iguana, for the current ERA."); + + UniValue json(UniValue::VOBJ); + UniValue seeds(UniValue::VARR); + UniValue notaries(UniValue::VARR); + // get the current era, use local time for now. + // should ideally take blocktime of last known block? + int now = time(NULL); + int32_t era = getera(now); + + // loop over seeds array and push back to json array for seeds + for (int8_t i = 0; i < 8; i++) { + seeds.push_back(iguanaSeeds[i][0]); + } + + // loop over era's notaries and push back each pair to the notary array + for (int8_t i = 0; i < num_notaries_STAKED[era]; i++) { + UniValue notary(UniValue::VOBJ); + notary.push_back(Pair(notaries_STAKED[era][i][0],notaries_STAKED[era][i][1])); + notaries.push_back(notary); + } + + // get the min sigs .. this always rounds UP so mine sigs in iguana is +1 min sigs in komodod, due to some rounding error. + int minsigs; + if ( num_notaries_STAKED[era]/5 > overrideMinSigs ) + minsigs = (num_notaries_STAKED[era] / 5) + 1; + else + minsigs = overrideMinSigs; + + json.push_back(Pair("port",iguanaPort)); + json.push_back(Pair("BTCminsigs",BTCminsigs)); + json.push_back(Pair("minsigs",minsigs)); + json.push_back(Pair("seeds", seeds)); + json.push_back(Pair("notaries",notaries)); + return json; +} + +UniValue getnotarysendmany(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getnotarysendmany\n" + "Returns a sendmany JSON array with all current notaries Raddress's.\n" + "\nExamples:\n" + + HelpExampleCli("getnotarysendmany", "10") + + HelpExampleRpc("getnotarysendmany", "10") + ); + int amount = 0; + if ( params.size() == 1 ) { + amount = params[0].get_int(); + } + + int era = getera(time(NULL)); + + UniValue ret(UniValue::VOBJ); + for (int i = 0; iGetHeight(),komodo_chainactive_timestamp())) >= 0 ) - { + if ( NOTARY_PUBKEY33[0] != 0 ) { + char pubkeystr[65]; int32_t notaryid; std::string notaryname; + if ( (notaryid= StakedNotaryID(notaryname, (char *)NOTARY_ADDRESS.c_str())) != -1 ) { + obj.push_back(Pair("notaryid", notaryid)); + obj.push_back(Pair("notaryname", notaryname)); + } else if( (notaryid= komodo_whoami(pubkeystr,(int32_t)chainActive.LastTip()->GetHeight(),komodo_chainactive_timestamp())) >= 0 ) { obj.push_back(Pair("notaryid", notaryid)); - obj.push_back(Pair("pubkey", pubkeystr)); if ( KOMODO_LASTMINED != 0 ) - obj.push_back(Pair("lastmined", KOMODO_LASTMINED)); - } else if ( NOTARY_PUBKEY33[0] != 0 ) { - obj.push_back(Pair("pubkey", NOTARY_PUBKEY)); + obj.push_back(Pair("lastmined", KOMODO_LASTMINED)); } + obj.push_back(Pair("pubkey", NOTARY_PUBKEY)); } if ( ASSETCHAINS_CC != 0 ) obj.push_back(Pair("CCid", (int)ASSETCHAINS_CC)); @@ -183,6 +262,8 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("rpcport", ASSETCHAINS_RPCPORT)); if ( ASSETCHAINS_SYMBOL[0] != 0 ) { + if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 ) + obj.push_back(Pair("StakedEra", STAKED_ERA)); //obj.push_back(Pair("name", ASSETCHAINS_SYMBOL)); obj.push_back(Pair("magic", (int)ASSETCHAINS_MAGIC)); obj.push_back(Pair("premine", ASSETCHAINS_SUPPLY)); @@ -1303,22 +1384,22 @@ UniValue txnotarizedconfirmed(const UniValue& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 1) { string msg = "txnotarizedconfirmed txid\n" - "\nReturns true if transaction is notarized on chain that has dPoW or if confirmation number is greater than 60 on chain taht does not have dPoW.\n" + "\nReturns true if transaction is notarized on chain that has dPoW or if confirmation number is greater than 60 on chain taht does not have dPoW.\n" "\nArguments:\n" - "1. txid (string, required) Transaction id.\n" + "1. txid (string, required) Transaction id.\n" "\nResult:\n" "{\n" - " true, (bool) The value the check.\n" - "}\n" + " true, (bool) The value the check.\n" + "}\n" ; throw runtime_error(msg); } txid = uint256S((char *)params[0].get_str().c_str()); notarizedconfirmed=komodo_txnotarizedconfirmed(txid); UniValue result(UniValue::VOBJ); - result.push_back(Pair("result", notarizedconfirmed)); + result.push_back(Pair("result", notarizedconfirmed)); return result; } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 21a6e26cd..ff9b57956 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -547,7 +547,7 @@ int32_t gettxout_scriptPubKey(uint8_t *scriptPubKey,int32_t maxsize,uint256 txid uint256 hashBlock; if ( GetTransaction(txid,tx,hashBlock,false) == 0 ) return(-1); - else if ( n < tx.vout.size() ) + else if ( n < tx.vout.size() ) { ptr = (uint8_t *)&tx.vout[n].scriptPubKey[0]; m = tx.vout[n].scriptPubKey.size(); @@ -1286,7 +1286,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) } } else if (fHaveChain) { throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); - } + } RelayTransaction(tx); return hashTx.GetHex(); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 1b6856be5..eb3cc80a0 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -276,6 +276,8 @@ static const CRPCCommand vRPCCommands[] = // --------------------- ------------------------ ----------------------- ---------- /* Overall control/query calls */ { "control", "help", &help, true }, + { "control", "getiguanajson", &getiguanajson, true }, + { "control", "getnotarysendmany", &getnotarysendmany, true }, { "control", "stop", &stop, true }, /* P2P networking */ @@ -302,6 +304,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getblockhashes", &getblockhashes, true }, { "blockchain", "getblockhash", &getblockhash, true }, { "blockchain", "getblockheader", &getblockheader, true }, + { "blockchain", "getlastsegidstakes", &getlastsegidstakes, true }, { "blockchain", "getchaintips", &getchaintips, true }, { "blockchain", "getdifficulty", &getdifficulty, true }, { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, @@ -364,16 +367,16 @@ static const CRPCCommand vRPCCommands[] = // auction { "auction", "auctionaddress", &auctionaddress, true }, - + // lotto { "lotto", "lottoaddress", &lottoaddress, true }, - + // fsm { "FSM", "FSMaddress", &FSMaddress, true }, { "FSM", "FSMcreate", &FSMcreate, true }, { "FSM", "FSMlist", &FSMlist, true }, { "FSM", "FSMinfo", &FSMinfo, true }, - + // rewards { "rewards", "rewardslist", &rewardslist, true }, { "rewards", "rewardsinfo", &rewardsinfo, true }, @@ -382,7 +385,7 @@ static const CRPCCommand vRPCCommands[] = { "rewards", "rewardslock", &rewardslock, true }, { "rewards", "rewardsunlock", &rewardsunlock, true }, { "rewards", "rewardsaddress", &rewardsaddress, true }, - + // faucet { "faucet", "faucetinfo", &faucetinfo, true }, { "faucet", "faucetfund", &faucetfund, true }, @@ -399,7 +402,7 @@ static const CRPCCommand vRPCCommands[] = { "channels", "channelspayment", &channelspayment, true }, { "channels", "channelsclose", &channelsclose, true }, { "channels", "channelsrefund", &channelsrefund, true }, - + // Oracles { "oracles", "oraclesaddress", &oraclesaddress, true }, { "oracles", "oracleslist", &oracleslist, true }, @@ -508,6 +511,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "getaccountaddress", &getaccountaddress, true }, { "wallet", "getaccount", &getaccount, true }, { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true }, + { "wallet", "cleanwallettransactions", &cleanwallettransactions, false }, { "wallet", "getbalance", &getbalance, false }, { "wallet", "getbalance64", &getbalance64, false }, { "wallet", "getnewaddress", &getnewaddress, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 6638024b8..e64216116 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -317,6 +317,7 @@ extern UniValue signmessage(const UniValue& params, bool fHelp); extern UniValue verifymessage(const UniValue& params, bool fHelp); extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp); extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp); +extern UniValue cleanwallettransactions(const UniValue& params, bool fHelp); extern UniValue getbalance(const UniValue& params, bool fHelp); extern UniValue getbalance64(const UniValue& params, bool fHelp); extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp); @@ -341,6 +342,8 @@ extern UniValue encryptwallet(const UniValue& params, bool fHelp); extern UniValue validateaddress(const UniValue& params, bool fHelp); extern UniValue txnotarizedconfirmed(const UniValue& params, bool fHelp); extern UniValue getinfo(const UniValue& params, bool fHelp); +extern UniValue getiguanajson(const UniValue& params, bool fHelp); +extern UniValue getnotarysendmany(const UniValue& params, bool fHelp); extern UniValue setpubkey(const UniValue& params, bool fHelp); extern UniValue getwalletinfo(const UniValue& params, bool fHelp); extern UniValue getblockchaininfo(const UniValue& params, bool fHelp); @@ -382,6 +385,7 @@ extern UniValue getblockhashes(const UniValue& params, bool fHelp); extern UniValue getblockdeltas(const UniValue& params, bool fHelp); extern UniValue getblockhash(const UniValue& params, bool fHelp); extern UniValue getblockheader(const UniValue& params, bool fHelp); +extern UniValue getlastsegidstakes(const UniValue& params, bool fHelp); extern UniValue getblock(const UniValue& params, bool fHelp); extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp); extern UniValue gettxout(const UniValue& params, bool fHelp); diff --git a/src/rpcblockchain.old b/src/rpcblockchain.old index 359df15ce..a91f73a63 100644 --- a/src/rpcblockchain.old +++ b/src/rpcblockchain.old @@ -836,7 +836,7 @@ UniValue kvsearch(const UniValue& params, bool fHelp) " \"currentheight\": xxxxx, (numeric) current height of the chain\n" " \"key\": \"xxxxx\", (string) key\n" " \"keylen\": xxxxx, (string) length of the key \n" - " \"owner\": \"xxxxx\" (string) hex string representing the owner of the key \n" + " \"owner\": \"xxxxx\" (string) hex string representing the owner of the key \n" " \"height\": xxxxx, (numeric) height the key was stored at\n" " \"expiration\": xxxxx, (numeric) height the key will expire\n" " \"flags\": x (numeric) 1 if the key was created with a password; 0 otherwise.\n" diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 3b57afd9d..b94cc3504 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -392,7 +392,7 @@ bool ExtractDestination(const CScript& _scriptPubKey, CTxDestination& addressRet addressRet = CScriptID(uint160(vSolutions[0])); return true; } - + else if (IsCryptoConditionsEnabled() != 0 && whichType == TX_CRYPTOCONDITION) { if (vSolutions.size() > 1) diff --git a/src/txdb.cpp b/src/txdb.cpp index 63e00dcd8..caf80d5f1 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -45,7 +45,7 @@ static const char DB_LAST_BLOCK = 'l'; CCoinsViewDB::CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe) { } -CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) +CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) { } @@ -107,7 +107,7 @@ uint256 CCoinsViewDB::GetBestBlock() const { uint256 CCoinsViewDB::GetBestAnchor(ShieldedType type) const { uint256 hashBestAnchor; - + switch (type) { case SPROUT: if (!db.Read(DB_BEST_SPROUT_ANCHOR, hashBestAnchor)) @@ -421,6 +421,7 @@ bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type, } bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address); +uint32_t komodo_segid32(char *coinaddr); UniValue CBlockTreeDB::Snapshot(int top) { @@ -433,23 +434,23 @@ UniValue CBlockTreeDB::Snapshot(int top) result.push_back(Pair("start_time", (int) time(NULL))); std::map ignoredMap = { - {"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1}, - {"RMUF3UDmzWFLSKV82iFbMaqzJpUnrWjcT4", 1}, - {"RA5imhVyJa7yHhggmBytWuDr923j2P1bxx", 1}, - {"RBM5LofZFodMeewUzoMWcxedm3L3hYRaWg", 1}, - {"RAdcko2d94TQUcJhtFHZZjMyWBKEVfgn4J", 1}, - {"RLzUaZ934k2EFCsAiVjrJqM8uU1vmMRFzk", 1}, - {"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, - {"RUDrX1v5toCsJMUgtvBmScKjwCB5NaR8py", 1}, - {"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, - {"RRvwmbkxR5YRzPGL5kMFHMe1AH33MeD8rN", 1}, - {"RQLQvSgpPAJNPgnpc8MrYsbBhep95nCS8L", 1}, - {"RK8JtBV78HdvEPvtV5ckeMPSTojZPzHUTe", 1}, - {"RHVs2KaCTGUMNv3cyWiG1jkEvZjigbCnD2", 1}, - {"RE3SVaDgdjkRPYA6TRobbthsfCmxQedVgF", 1}, - {"RW6S5Lw5ZCCvDyq4QV9vVy7jDHfnynr5mn", 1}, - {"RTkJwAYtdXXhVsS3JXBAJPnKaBfMDEswF8", 1}, - {"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} //Burnaddress for null privkey + {"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1}, + {"RMUF3UDmzWFLSKV82iFbMaqzJpUnrWjcT4", 1}, + {"RA5imhVyJa7yHhggmBytWuDr923j2P1bxx", 1}, + {"RBM5LofZFodMeewUzoMWcxedm3L3hYRaWg", 1}, + {"RAdcko2d94TQUcJhtFHZZjMyWBKEVfgn4J", 1}, + {"RLzUaZ934k2EFCsAiVjrJqM8uU1vmMRFzk", 1}, + {"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, + {"RUDrX1v5toCsJMUgtvBmScKjwCB5NaR8py", 1}, + {"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, + {"RRvwmbkxR5YRzPGL5kMFHMe1AH33MeD8rN", 1}, + {"RQLQvSgpPAJNPgnpc8MrYsbBhep95nCS8L", 1}, + {"RK8JtBV78HdvEPvtV5ckeMPSTojZPzHUTe", 1}, + {"RHVs2KaCTGUMNv3cyWiG1jkEvZjigbCnD2", 1}, + {"RE3SVaDgdjkRPYA6TRobbthsfCmxQedVgF", 1}, + {"RW6S5Lw5ZCCvDyq4QV9vVy7jDHfnynr5mn", 1}, + {"RTkJwAYtdXXhVsS3JXBAJPnKaBfMDEswF8", 1}, + {"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} //Burnaddress for null privkey }; int64_t startingHeight = chainActive.Height(); @@ -511,29 +512,31 @@ UniValue CBlockTreeDB::Snapshot(int top) //fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses); for (std::pair element : addressAmounts) { - vaddr.push_back( make_pair(element.second, element.first) ); + vaddr.push_back( make_pair(element.second, element.first) ); } std::sort(vaddr.rbegin(), vaddr.rend()); UniValue obj(UniValue::VOBJ); UniValue addressesSorted(UniValue::VARR); int topN = 0; - for (std::vector>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) { - UniValue obj(UniValue::VOBJ); - obj.push_back( make_pair("addr", it->second.c_str() ) ); - char amount[32]; - sprintf(amount, "%.8f", (double) it->first / COIN); - obj.push_back( make_pair("amount", amount) ); - total += it->first; - addressesSorted.push_back(obj); - topN++; - // If requested, only show top N addresses in output JSON - if (top == topN) - break; + for (std::vector>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) + { + UniValue obj(UniValue::VOBJ); + obj.push_back( make_pair("addr", it->second.c_str() ) ); + char amount[32]; + sprintf(amount, "%.8f", (double) it->first / COIN); + obj.push_back( make_pair("amount", amount) ); + obj.push_back( make_pair("segid",(int32_t)komodo_segid32((char *)it->second.c_str()) & 0x3f) ); + total += it->first; + addressesSorted.push_back(obj); + topN++; + // If requested, only show top N addresses in output JSON + if (top == topN) + break; } if (top) - totalAddresses = top; + totalAddresses = top; if (totalAddresses > 0) { // Array of all addreses with balances diff --git a/src/version.h b/src/version.h index 72ddac446..cfc084690 100644 --- a/src/version.h +++ b/src/version.h @@ -19,6 +19,7 @@ static const int GETHEADERS_VERSION = 31800; //! disconnect from peers older than this proto version static const int MIN_PEER_PROTO_VERSION = 170002; +static const int STAKEDMIN_PEER_PROTO_VERSION = 170006; //! nTime field added to CAddress, starting with this version; //! if possible, avoid requesting addresses nodes older than this diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c34466a39..2f6455701 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -22,6 +22,7 @@ #include "zcbenchmarks.h" #include "script/interpreter.h" #include "zcash/zip32.h" +#include "notaries_staked.h" #include "utiltime.h" #include "asyncrpcoperation.h" @@ -48,9 +49,9 @@ using namespace std; using namespace libzcash; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +extern std::string ASSETCHAINS_OVERRIDE_PUBKEY; const std::string ADDR_TYPE_SPROUT = "sprout"; const std::string ADDR_TYPE_SAPLING = "sapling"; - extern UniValue TxJoinSplitToJSON(const CTransaction& tx); extern uint8_t ASSETCHAINS_PRIVATE; extern int32_t USE_EXTERNAL_PUBKEY; @@ -1015,6 +1016,108 @@ CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminef return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); } +UniValue cleanwallettransactions(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() > 1 ) + throw runtime_error( + "cleanwallettransactions \"txid\"\n" + "\nRemove all txs that are spent. You can clear all txs bar one, by specifiying a txid.\n" + "\nPlease backup your wallet.dat before running this command.\n" + "\nArguments:\n" + "1. \"txid\" (string, optional) The transaction id to keep.\n" + "\nResult:\n" + "{\n" + " \"total_transactons\" : n, (numeric) Transactions in wallet of " + strprintf("%s",komodo_chainname()) + "\n" + " \"remaining_transactons\" : n, (numeric) Transactions in wallet after clean.\n" + " \"removed_transactons\" : n, (numeric) The number of transactions removed.\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("cleanwallettransactions", "") + + HelpExampleCli("cleanwallettransactions","\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + + HelpExampleRpc("cleanwallettransactions", "") + + HelpExampleRpc("cleanwallettransactions","\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + UniValue ret(UniValue::VOBJ); + uint256 exception; int32_t txs = pwalletMain->mapWallet.size(); + std::vector TxToRemove; + if (params.size() == 1) + { + exception.SetHex(params[0].get_str()); + uint256 tmp_hash; CTransaction tmp_tx; + if (GetTransaction(exception,tmp_tx,tmp_hash,false)) + { + if ( !pwalletMain->IsMine(tmp_tx) ) + { + throw runtime_error("\nThe transaction is not yours!\n"); + } + else + { + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if ( wtx.GetHash() != exception ) + { + TxToRemove.push_back(wtx.GetHash()); + } + } + } + } + else + { + throw runtime_error("\nThe transaction could not be found!\n"); + } + } + else + { + // get all locked utxos to relock them later. + vector vLockedUTXO; + pwalletMain->ListLockedCoins(vLockedUTXO); + // unlock all coins so that the following call containes all utxos. + pwalletMain->UnlockAllCoins(); + // listunspent call... this gets us all the txids that are unspent, we search this list for the oldest tx, + vector vecOutputs; + assert(pwalletMain != NULL); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); + int32_t oldestTxDepth = 0; + BOOST_FOREACH(const COutput& out, vecOutputs) + { + if ( out.nDepth > oldestTxDepth ) + oldestTxDepth = out.nDepth; + } + oldestTxDepth = oldestTxDepth + 1; // add extra block just for safety. + // lock all the previouly locked coins. + BOOST_FOREACH(COutPoint &outpt, vLockedUTXO) { + pwalletMain->LockCoin(outpt); + } + + // then add all txs in the wallet before this block to the list to remove. + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (wtx.GetDepthInMainChain() > oldestTxDepth) + TxToRemove.push_back(wtx.GetHash()); + } + } + + // erase txs + BOOST_FOREACH (uint256& hash, TxToRemove) + { + pwalletMain->EraseFromWallet(hash); + LogPrintf("Erased %s from wallet.\n",hash.ToString().c_str()); + } + + // build return JSON for stats. + int remaining = pwalletMain->mapWallet.size(); + ret.push_back(Pair("total_transactons", (int)txs)); + ret.push_back(Pair("remaining_transactons", (int)remaining)); + ret.push_back(Pair("removed_transactions", (int)(txs-remaining))); + return (ret); +} UniValue getbalance(const UniValue& params, bool fHelp) { @@ -1674,7 +1777,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY)) entry.push_back(Pair("involvesWatchonly", true)); entry.push_back(Pair("account", account)); - + CTxDestination dest; if (CScriptExt::ExtractVoutDestination(wtx, r.vout, dest)) MaybePushAddress(entry, dest); @@ -2920,11 +3023,11 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) // User did not provide zaddrs, so use default i.e. all addresses std::set sproutzaddrs = {}; pwalletMain->GetSproutPaymentAddresses(sproutzaddrs); - + // Sapling support std::set saplingzaddrs = {}; pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs); - + zaddrs.insert(sproutzaddrs.begin(), sproutzaddrs.end()); zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end()); } @@ -2936,7 +3039,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) std::vector saplingEntries; pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false); std::set> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs); - + for (auto & entry : sproutEntries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid", entry.jsop.hash.ToString())); @@ -2954,7 +3057,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) } results.push_back(obj); } - + for (auto & entry : saplingEntries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid", entry.op.hash.ToString())); @@ -4531,89 +4634,91 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + string enableArg = "zmergetoaddress"; auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, true); std::string strDisabledMsg = ""; if (!fEnableMergeToAddress) { strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg); } - - if (fHelp || params.size() < 2 || params.size() > 6) + + if (fHelp || params.size() < 2 || params.size() > 7) throw runtime_error( - "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n" - + strDisabledMsg + - "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`" - "\nto combine those into a single note." - "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they" - "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs." - "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit" - "\nparameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit option will determine the" - "\nnumber of UTXOs. Any limit is constrained by the consensus rule defining a maximum transaction size of" - + strprintf("\n%d bytes before Sapling, and %d bytes once Sapling activates.", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING) - + HelpRequiringPassphrase() + "\n" - "\nArguments:\n" - "1. fromaddresses (string, required) A JSON array with addresses.\n" - " The following special strings are accepted inside the array:\n" - " - \"ANY_TADDR\": Merge UTXOs from any t-addrs belonging to the wallet.\n" - " - \"ANY_SPROUT\": Merge notes from any Sprout z-addrs belonging to the wallet.\n" - " - \"ANY_SAPLING\": Merge notes from any Sapling z-addrs belonging to the wallet.\n" - " If a special string is given, any given addresses of that type will be ignored.\n" - " [\n" - " \"address\" (string) Can be a t-addr or a z-addr\n" - " ,...\n" - " ]\n" - "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n" - "3. fee (numeric, optional, default=" - + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n" - "4. transparent_limit (numeric, optional, default=" - + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n" - "4. shielded_limit (numeric, optional, default=" - + strprintf("%d Sprout or %d Sapling Notes", MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT, MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n" - "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n" - "\nResult:\n" - "{\n" - " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n" - " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n" - " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n" - " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n" - " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n" - " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n" - " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n" - " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n" - " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf") - + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"") - ); - + "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n" + + strDisabledMsg + + "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`" + "\nto combine those into a single note." + "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they" + "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs." + "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit" + "\nparameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit option will determine the" + "\nnumber of UTXOs. Any limit is constrained by the consensus rule defining a maximum transaction size of" + + strprintf("\n%d bytes before Sapling, and %d bytes once Sapling activates.", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING) + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" + "1. fromaddresses (string, required) A JSON array with addresses.\n" + " The following special strings are accepted inside the array:\n" + " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n" + " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n" + " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n" + " If a special string is given, any given addresses of that type will be ignored.\n" + " [\n" + " \"address\" (string) Can be a t-addr or a z-addr\n" + " ,...\n" + " ]\n" + "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n" + "3. fee (numeric, optional, default=" + + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n" + "4. transparent_limit (numeric, optional, default=" + + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n" + "4. shielded_limit (numeric, optional, default=" + + strprintf("%d Sprout or %d Sapling Notes", MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT, MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n" + "5. maximum_utxo_size (numeric, optional) eg, 0.0001 anything under 10000 satoshies will be merged, ignores p2pk utxo!\n" + "6. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n" + + "\nResult:\n" + "{\n" + " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n" + " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n" + " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n" + " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n" + " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n" + " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n" + " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n" + " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n" + " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf") + + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + ); + if (!fEnableMergeToAddress) { throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled."); } - + LOCK2(cs_main, pwalletMain->cs_wallet); - + bool useAnyUTXO = false; bool useAnySprout = false; bool useAnySapling = false; std::set taddrs = {}; std::set zaddrs = {}; - + UniValue addresses = params[0].get_array(); if (addresses.size()==0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty."); - + // Keep track of addresses to spot duplicates std::set setAddress; - + // Sources for (const UniValue& o : addresses.getValues()) { if (!o.isStr()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string"); - + std::string address = o.get_str(); - + if (address == "ANY_TADDR") { useAnyUTXO = true; } else if (address == "ANY_SPROUT") { @@ -4633,23 +4738,23 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) } } } - + if (setAddress.count(address)) throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address); setAddress.insert(address); } - + if (useAnyUTXO && taddrs.size() > 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific t-addrs when using \"ANY_TADDR\""); } if ((useAnySprout || useAnySapling) && zaddrs.size() > 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific z-addrs when using \"ANY_SPROUT\" or \"ANY_SAPLING\""); } - + const int nextBlockHeight = chainActive.Height() + 1; const bool overwinterActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); const bool saplingActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING); - + // Validate the destination address auto destaddress = params[1].get_str(); bool isToSproutZaddr = false; @@ -4671,7 +4776,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress ); } } - + // Convert fee from currency format to zatoshis CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE; if (params.size() > 2) { @@ -4681,7 +4786,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) nFee = AmountFromValue( params[2] ); } } - + int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT; if (params.size() > 3) { nUTXOLimit = params[3].get_int(); @@ -4689,7 +4794,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative"); } } - + int sproutNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT; int saplingNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT; if (params.size() > 4) { @@ -4700,10 +4805,20 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) sproutNoteLimit = nNoteLimit; saplingNoteLimit = nNoteLimit; } - - std::string memo; + + CAmount maximum_utxo_size; if (params.size() > 5) { - memo = params[5].get_str(); + maximum_utxo_size = AmountFromValue( params[5] ); + if (maximum_utxo_size < 10) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Maximum size must be bigger than 0.00000010."); + } + } else { + maximum_utxo_size = 0; + } + + std::string memo; + if (params.size() > 6) { + memo = params[6].get_str(); if (!(isToSproutZaddr || isToSaplingZaddr)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr."); } else if (!IsHex(memo)) { @@ -4713,9 +4828,9 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE )); } } - + MergeToAddressRecipient recipient(destaddress, memo); - + // Prepare to get UTXOs and notes std::vector utxoInputs; std::vector sproutNoteInputs; @@ -4729,7 +4844,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) bool maxedOutUTXOsFlag = false; bool maxedOutNotesFlag = false; size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0)); - + unsigned int max_tx_size = saplingActive ? MAX_TX_SIZE_AFTER_SAPLING : MAX_TX_SIZE_BEFORE_SAPLING; size_t estimatedTxSize = 200; // tx overhead + wiggle room if (isToSproutZaddr) { @@ -4737,20 +4852,20 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) } else if (isToSaplingZaddr) { estimatedTxSize += OUTPUTDESCRIPTION_SIZE; } - + if (useAnyUTXO || taddrs.size() > 0) { // Get available utxos vector vecOutputs; pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false); - + // Find unspent utxos and update estimated size for (const COutput& out : vecOutputs) { if (!out.fSpendable) { continue; } - + CScript scriptPubKey = out.tx->vout[out.i].scriptPubKey; - + CTxDestination address; if (!ExtractDestination(scriptPubKey, address)) { continue; @@ -4759,10 +4874,21 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) if (taddrs.size() > 0 && !taddrs.count(address)) { continue; } - - utxoCounter++; + CAmount nValue = out.tx->vout[out.i].nValue; - + + if (maximum_utxo_size != 0) { + if (nValue > maximum_utxo_size) { + continue; + } else { + if (out.tx->vout[out.i].scriptPubKey.size() == 35 && nValue == 10000) { + continue; + } + } + } + + utxoCounter++; + if (!maxedOutUTXOsFlag) { size_t increase = (boost::get(&address) != nullptr) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE; if (estimatedTxSize + increase >= max_tx_size || @@ -4776,19 +4902,19 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) mergedUTXOValue += nValue; } } - + if (maxedOutUTXOsFlag) { remainingUTXOValue += nValue; } } } - + if (useAnySprout || useAnySapling || zaddrs.size() > 0) { // Get available notes std::vector sproutEntries; std::vector saplingEntries; pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs); - + // If Sapling is not active, do not allow sending from a sapling addresses. if (!saplingActive && saplingEntries.size() > 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated"); @@ -4805,12 +4931,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) RPC_INVALID_PARAMETER, "Cannot send between Sprout and Sapling addresses using z_mergetoaddress"); } - + // Find unspent notes and update estimated size for (const CSproutNotePlaintextEntry& entry : sproutEntries) { noteCounter++; CAmount nValue = entry.plaintext.value(); - + if (!maxedOutNotesFlag) { // If we haven't added any notes yet and the merge is to a // z-address, we have already accounted for the first JoinSplit. @@ -4828,12 +4954,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) mergedNoteValue += nValue; } } - + if (maxedOutNotesFlag) { remainingNoteValue += nValue; } } - + for (const SaplingNoteEntry& entry : saplingEntries) { noteCounter++; CAmount nValue = entry.note.value(); @@ -4853,20 +4979,20 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) mergedNoteValue += nValue; } } - + if (maxedOutNotesFlag) { remainingNoteValue += nValue; } } } - + size_t numUtxos = utxoInputs.size(); size_t numNotes = sproutNoteInputs.size() + saplingNoteInputs.size(); - - if (numUtxos == 0 && numNotes == 0) { + + if (numUtxos < 2 && numNotes == 0) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge."); } - + // Sanity check: Don't do anything if: // - We only have one from address // - It's equal to toaddress @@ -4874,26 +5000,26 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged."); } - + CAmount mergedValue = mergedUTXOValue + mergedNoteValue; if (mergedValue < nFee) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strprintf("Insufficient funds, have %s, which is less than miners fee %s", FormatMoney(mergedValue), FormatMoney(nFee))); } - + // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee) CAmount netAmount = mergedValue - nFee; if (nFee > netAmount) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount))); } - + // Keep record of parameters in context object UniValue contextInfo(UniValue::VOBJ); contextInfo.push_back(Pair("fromaddresses", params[0])); contextInfo.push_back(Pair("toaddress", params[1])); contextInfo.push_back(Pair("fee", ValueFromAmount(nFee))); - + // Contextual transaction we will build on CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction( Params().GetConsensus(), @@ -4902,7 +5028,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) if (contextualTx.nVersion == 1 && isSproutShielded) { contextualTx.nVersion = 2; // Tx format should support vjoinsplit } - + // Builder (used if Sapling addresses are involved) boost::optional builder; if (isToSaplingZaddr || saplingNoteInputs.size() > 0) { @@ -4914,7 +5040,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, sproutNoteInputs, saplingNoteInputs, recipient, nFee, contextInfo) ); q->addOperation(operation); AsyncRPCOperationId operationId = operation->getId(); - + // Return continuation information UniValue o(UniValue::VOBJ); o.push_back(Pair("remainingUTXOs", static_cast(utxoCounter - numUtxos))); @@ -5043,8 +5169,8 @@ int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33) // ((uint8_t *)&revtxid)[i] = ((uint8_t *)&utxotxid)[31 - i]; txNew.vin[0].prevout.hash = utxotxid; //revtxid; txNew.vin[0].prevout.n = utxovout; - txNew.vout[0].scriptPubKey = CScript() << ParseHex(CRYPTO777_PUBSECPSTR) << OP_CHECKSIG; txNew.vout[0].nValue = utxovalue - txfee; + txNew.vout[0].scriptPubKey = CScript() << ParseHex(CRYPTO777_PUBSECPSTR) << OP_CHECKSIG; CTransaction txNewConst(txNew); signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, utxovalue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) @@ -5262,7 +5388,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt } } //else fprintf(stderr,"utxo not eligible\n"); } - if ( numkp < 10000 && array != 0 ) + if ( numkp < 1000 && array != 0 ) { free(array); array = 0; @@ -5371,11 +5497,14 @@ UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector 1 ) throw runtime_error( "setpubkey\n" "\nSets the -pubkey if the daemon was not started with it, if it was already set, it returns the pubkey, and its Raddress.\n" @@ -5392,16 +5521,10 @@ UniValue setpubkey(const UniValue& params, bool fHelp) + HelpExampleRpc("setpubkey", "02f7597468703c1c5c8465dd6d43acaae697df9df30bed21494d193412a1ea193e") ); -#ifdef ENABLE_WALLET LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); -#else - LOCK(cs_main); -#endif char Raddress[18]; uint8_t pubkey33[33]; - extern uint8_t NOTARY_PUBKEY33[]; - extern std::string NOTARY_PUBKEY; if ( NOTARY_PUBKEY33[0] == 0 ) { if (strlen(params[0].get_str().c_str()) == 66) { decode_hex(pubkey33,33,(char *)params[0].get_str().c_str()); @@ -5414,27 +5537,39 @@ UniValue setpubkey(const UniValue& params, bool fHelp) if (isValid) { CTxDestination dest = address.Get(); - string currentAddress = address.ToString(); - result.push_back(Pair("address", currentAddress)); -#ifdef ENABLE_WALLET isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO; - result.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); -#endif + if ( mine == ISMINE_NO ) { + result.push_back(Pair("WARNING", "privkey for this pubkey is not imported to wallet!")); + } else { + result.push_back(Pair("ismine", "true")); + std::string notaryname; + if ( (IS_STAKED_NOTARY= StakedNotaryID(notaryname, Raddress)) > -1 ) { + result.push_back(Pair("IsNotary", notaryname)); + IS_KOMODO_NOTARY = 0; + } + } + NOTARY_PUBKEY = params[0].get_str(); + decode_hex(NOTARY_PUBKEY33,33,(char *)NOTARY_PUBKEY.c_str()); + USE_EXTERNAL_PUBKEY = 1; + NOTARY_ADDRESS = address.ToString(); + } else { + result.push_back(Pair("error", "pubkey entered is invalid.")); } - NOTARY_PUBKEY = params[0].get_str(); - decode_hex(NOTARY_PUBKEY33,33,(char *)NOTARY_PUBKEY.c_str()); - USE_EXTERNAL_PUBKEY = 1; } } else { result.push_back(Pair("error", "pubkey is wrong length, must be 66 char hex string.")); } } else { - result.push_back(Pair("error", "Can only set pubkey once, to change it you need to restart your daemon, pubkey in use is below.")); - pubkey2addr((char *)Raddress,(uint8_t *)NOTARY_PUBKEY33); - std::string address_ret; address_ret.assign(Raddress); - result.push_back(Pair("address",address_ret)); + if ( NOTARY_ADDRESS.empty() ) { + pubkey2addr((char *)Raddress,(uint8_t *)NOTARY_PUBKEY33); + NOTARY_ADDRESS.assign(Raddress); + } + result.push_back(Pair("error", "Can only set pubkey once, to change it you need to restart your daemon.")); + } + if ( NOTARY_PUBKEY33[0] != 0 && !NOTARY_ADDRESS.empty() ) { + result.push_back(Pair("address", NOTARY_ADDRESS)); + result.push_back(Pair("pubkey", NOTARY_PUBKEY)); } - result.push_back(Pair("pubkey", NOTARY_PUBKEY)); return result; } @@ -5465,6 +5600,7 @@ UniValue channelsaddress(const UniValue& params, bool fHelp) return(result); } + UniValue oraclesaddress(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; std::vector pubkey; @@ -6015,7 +6151,7 @@ UniValue gatewaysbind(const UniValue& params, bool fHelp) if ( params.size() < 6+i+1 ) throw runtime_error("not enough parameters for N pubkeys\n"); pubkey = ParseHex(params[6+i].get_str().c_str()); - if (pubkey.size()!= 33) + if (pubkey.size()!= 33) throw runtime_error("invalid destination pubkey"); pubkeys.push_back(pubkey2pk(pubkey)); } @@ -6049,8 +6185,8 @@ UniValue gatewaysdeposit(const UniValue& params, bool fHelp) amount = atof((char *)params[8].get_str().c_str()) * COIN + 0.00000000499999; if ( amount <= 0 || claimvout < 0 ) throw runtime_error("invalid param: amount, numpks or claimvout\n"); - if (destpub.size()!= 33) - throw runtime_error("invalid destination pubkey"); + if (destpub.size()!= 33) + throw runtime_error("invalid destination pubkey"); hex = GatewaysDeposit(0,bindtxid,height,coin,cointxid,claimvout,deposithex,proof,pubkey2pk(destpub),amount); RETURN_IF_ERROR(CCerror); @@ -6075,9 +6211,9 @@ UniValue gatewaysclaim(const UniValue& params, bool fHelp) coin = params[1].get_str(); deposittxid = Parseuint256((char *)params[2].get_str().c_str()); destpub = ParseHex(params[3].get_str()); - amount = atof((char *)params[4].get_str().c_str()) * COIN + 0.00000000499999; - if (destpub.size()!= 33) - throw runtime_error("invalid destination pubkey"); + amount = atof((char *)params[4].get_str().c_str()) * COIN + 0.00000000499999; + if (destpub.size()!= 33) + throw runtime_error("invalid destination pubkey"); hex = GatewaysClaim(0,bindtxid,coin,deposittxid,pubkey2pk(destpub),amount); RETURN_IF_ERROR(CCerror); if ( hex.size() > 0 ) @@ -6100,9 +6236,9 @@ UniValue gatewayswithdraw(const UniValue& params, bool fHelp) bindtxid = Parseuint256((char *)params[0].get_str().c_str()); coin = params[1].get_str(); withdrawpub = ParseHex(params[2].get_str()); - amount = atof((char *)params[3].get_str().c_str()) * COIN + 0.00000000499999; - if (withdrawpub.size()!= 33) - throw runtime_error("invalid destination pubkey"); + amount = atof((char *)params[3].get_str().c_str()) * COIN + 0.00000000499999; + if (withdrawpub.size()!= 33) + throw runtime_error("invalid destination pubkey"); hex = GatewaysWithdraw(0,bindtxid,coin,pubkey2pk(withdrawpub),amount); RETURN_IF_ERROR(CCerror); if ( hex.size() > 0 ) @@ -6121,7 +6257,7 @@ UniValue gatewayspartialsign(const UniValue& params, bool fHelp) if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwalletMain->cs_wallet); txid = Parseuint256((char *)params[0].get_str().c_str()); coin = params[1].get_str(); parthex = params[2].get_str(); @@ -6166,7 +6302,7 @@ UniValue gatewaysmarkdone(const UniValue& params, bool fHelp) const CKeyStore& keystore = *pwalletMain; LOCK2(cs_main, pwalletMain->cs_wallet); completetxid = Parseuint256((char *)params[0].get_str().c_str()); - coin = params[1].get_str(); + coin = params[1].get_str(); hex = GatewaysMarkDone(0,completetxid,coin); RETURN_IF_ERROR(CCerror); if ( hex.size() > 0 ) @@ -7170,7 +7306,7 @@ UniValue tokenfillask(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); tokenid = Parseuint256((char *)params[0].get_str().c_str()); asktxid = Parseuint256((char *)params[1].get_str().c_str()); - //fillunits = atol(params[2].get_str().c_str()); + //fillunits = atol(params[2].get_str().c_str()); fillunits = atoll(params[2].get_str().c_str()); // dimxy changed to prevent loss of significance if ( fillunits <= 0 ) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 3857f7090..9b92eb943 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -161,7 +161,7 @@ SaplingPaymentAddress CWallet::GenerateNewSaplingZKey() return addr; } -// Add spending key to keystore +// Add spending key to keystore bool CWallet::AddSaplingZKey( const libzcash::SaplingExtendedSpendingKey &sk, const libzcash::SaplingPaymentAddress &defaultAddr) @@ -171,7 +171,7 @@ bool CWallet::AddSaplingZKey( if (!CCryptoKeyStore::AddSaplingSpendingKey(sk, defaultAddr)) { return false; } - + if (!fFileBacked) { return true; } @@ -180,7 +180,7 @@ bool CWallet::AddSaplingZKey( auto ivk = sk.expsk.full_viewing_key().in_viewing_key(); return CWalletDB(strWalletFile).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]); } - + return true; } @@ -562,10 +562,10 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, return false; } -void CWallet::ChainTip(const CBlockIndex *pindex, +void CWallet::ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, - SaplingMerkleTree saplingTree, + SaplingMerkleTree saplingTree, bool added) { if (added) { @@ -1145,7 +1145,7 @@ bool DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t n if (nd->witnesses.size() > 0) { nd->witnesses.pop_front(); } - // indexHeight is the height of the block being removed, so + // indexHeight is the height of the block being removed, so // the new witness cache height is one below it. nd->witnessHeight = indexHeight - 1; } @@ -1387,8 +1387,8 @@ int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNe return 0; } - bool signSuccess; - SignatureData sigdata; + bool signSuccess; + SignatureData sigdata; uint64_t txfee; auto consensusBranchId = CurrentEpochBranchId(stakeHeight, Params().GetConsensus()); @@ -1727,10 +1727,19 @@ bool CWallet::UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx) * pblock is optional, but should be provided if the transaction is known to be in a block. * If fUpdate is true, existing transactions will be updated. */ +extern uint8_t NOTARY_PUBKEY33[33]; +extern std::string NOTARY_ADDRESS,WHITELIST_ADDRESS; +extern int32_t IS_STAKED_NOTARY; +extern uint64_t MIN_RECV_SATS; + bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) { { AssertLockHeld(cs_wallet); + if ( tx.IsCoinBase() && tx.vout[0].nValue == 0 ) + return false; + if ( tx.vin.empty() ) + return false; bool fExisted = mapWallet.count(tx.GetHash()) != 0; if (fExisted && !fUpdate) return false; auto sproutNoteData = FindMySproutNotes(tx); @@ -1744,6 +1753,70 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl } if (fExisted || IsMine(tx) || IsFromMe(tx) || sproutNoteData.size() > 0 || saplingNoteData.size() > 0) { + if ( !tx.IsCoinBase() && !NOTARY_ADDRESS.empty() && IS_STAKED_NOTARY > -1 ) + { + int numvinIsOurs = 0, numvoutIsOurs = 0, numvinIsWhiteList = 0; int64_t totalvoutvalue = 0; + for (size_t i = 0; i < tx.vin.size(); i++) + { + uint256 hash; CTransaction txin; CTxDestination address; + if (GetTransaction(tx.vin[i].prevout.hash,txin,hash,false)) + { + if (ExtractDestination(txin.vout[tx.vin[i].prevout.n].scriptPubKey, address)) + { + if ( CBitcoinAddress(address).ToString() == NOTARY_ADDRESS ) + numvinIsOurs++; + if ( !WHITELIST_ADDRESS.empty() ) + { + //fprintf(stderr, "white list address: %s recv address: %s\n", WHITELIST_ADDRESS.c_str(),CBitcoinAddress(address).ToString().c_str()); + if ( CBitcoinAddress(address).ToString() == WHITELIST_ADDRESS ) { + //fprintf(stderr, "whitlisted is set to true here.\n"); + numvinIsWhiteList++; + } + } + } + } + } + // Now we know if it was a tx sent to us, that wasnt from ourself or the whitelist address if set.. + if ( numvinIsOurs != 0 ) + fprintf(stderr, "We sent from address: %s vins: %d\n",NOTARY_ADDRESS.c_str(),numvinIsOurs); + if ( numvinIsWhiteList != 0 ) + fprintf(stderr, "We received from whitelisted address: %s\n",WHITELIST_ADDRESS.c_str()); + // Count vouts, check if OUR notary address is the receiver. + if ( numvinIsOurs == 0 && numvinIsWhiteList == 0 ) + { + for (size_t i = 0; i < tx.vout.size() ; i++) + { + CTxDestination address2; + if ( ExtractDestination(tx.vout[i].scriptPubKey, address2)) + { + if ( CBitcoinAddress(address2).ToString() == NOTARY_ADDRESS ) + { + numvoutIsOurs++; + totalvoutvalue += tx.vout[i].nValue; + } + } + } + // if MIN_RECV_SATS is 0, we are on full lock down mode, accept NO transactions. + if ( MIN_RECV_SATS == 0 ) { + fprintf(stderr, "This node is on full lock down all txs are ignored! \n"); + return false; + } + // If no vouts are to the notary address we will ignore them. + if ( numvoutIsOurs == 0 ) { + fprintf(stderr, "Received transaction to address other than notary address, ignored! \n"); + return false; + } + fprintf(stderr, "address: %s received %ld sats from %d vouts.\n",NOTARY_ADDRESS.c_str(),totalvoutvalue,numvoutIsOurs); + // here we add calculation for number if vouts received, average size and determine if we accept them to wallet or not. + int64_t avgVoutSize = totalvoutvalue / numvoutIsOurs; + if ( avgVoutSize < MIN_RECV_SATS ) { + // average vout size is less than set minimum, default is 1 coin, we will ignore it + fprintf(stderr, "ignored: %d vouts average size of %ld sats.\n",numvoutIsOurs, avgVoutSize); + return false; + } + } + } + CWalletTx wtx(this,tx); if (sproutNoteData.size() > 0) { @@ -2160,7 +2233,7 @@ isminetype CWallet::IsMine(const CTransaction& tx, uint32_t voutNum) case TX_SCRIPTHASH: scriptID = CScriptID(uint160(vSolutions[0])); - if (this->GetCScript(scriptID, subscript)) + if (this->GetCScript(scriptID, subscript)) { // if this is a CLTV, handle it differently if (subscript.IsCheckLockTimeVerify()) @@ -3214,7 +3287,7 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const int nDepth = pcoin->GetDepthInMainChain(); if (nDepth < 0) continue; - + for (int i = 0; i < pcoin->vout.size(); i++) { isminetype mine = IsMine(pcoin->vout[i]); @@ -4852,7 +4925,7 @@ void CWallet::GetFilteredNotes( } /** - * Find notes in the wallet filtered by payment addresses, min depth, max depth, + * Find notes in the wallet filtered by payment addresses, min depth, max depth, * if the note is spent, if a spending key is required, and if the notes are locked. * These notes are decrypted and added to the output parameter vector, outEntries. */ @@ -5105,10 +5178,10 @@ SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingE m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp; } return KeyAdded; - } + } } } -SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const { +SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); } diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 41c0de4b2..4dedab834 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -918,8 +918,8 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) { // Leave other errors alone, if we try to fix them we might make things worse. fNoncriticalErrors = true; // ... but do warn the user there is something wrong. - if (strType == "tx") - // Rescan if there is a bad transaction record: + if (strType == "tx" ) + // Rescan if there is a bad transaction record.. SoftSetBoolArg("-rescan", true); } } @@ -967,7 +967,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (wss.fAnyUnordered) result = ReorderTransactions(pwallet); - + return result; }