diff --git a/build.sh b/build.sh
new file mode 100755
index 000000000..2ae8514c3
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# Copyright (c) 2019-2020 The Hush developers
+
+set -eu -o pipefail
+./zcutil/build.sh $@
diff --git a/configure.ac b/configure.ac
index cf712cc67..e3be0c9dd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 3)
-define(_CLIENT_VERSION_MINOR, 3)
-define(_CLIENT_VERSION_REVISION, 2)
+define(_CLIENT_VERSION_MINOR, 4)
+define(_CLIENT_VERSION_REVISION, 0)
define(_CLIENT_VERSION_BUILD, 50)
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
diff --git a/contrib/block_time.pl b/contrib/block_time.pl
index dff43ea4e..17da3c461 100755
--- a/contrib/block_time.pl
+++ b/contrib/block_time.pl
@@ -1,5 +1,5 @@
#!/usr/bin/perl
-# Copyright 2019 The Hush developers
+# Copyright 2019-2020 The Hush developers
# Released under the GPLv3
use warnings;
use strict;
@@ -9,6 +9,11 @@ my $block = shift || die "Usage: $0 123";
my $hush = "./src/hush-cli";
my $blockcount = qx{$hush getblockcount};
+unless ($blockcount = int($blockcount)) {
+ print "Invalid response from hush-cli\n";
+ exit 1;
+}
+
if ($block <= $blockcount) {
die "That block has already happened!";
} else {
diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk
index 48c60710d..3112ca7be 100644
--- a/depends/packages/boost.mk
+++ b/depends/packages/boost.mk
@@ -1,7 +1,7 @@
package=boost
$(package)_version=1_72_0
-$(package)_download_path=https://dl.bintray.com/boostorg/release/1.72.0/source/
+$(package)_download_path=https://github.com/MyHush/boost/releases/download/v1.72.0/
$(package)_sha256_hash=59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722
$(package)_file_name=$(package)_$($(package)_version).tar.bz2
diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk
index b3693cc6f..64fee77ba 100644
--- a/depends/packages/native_ccache.mk
+++ b/depends/packages/native_ccache.mk
@@ -1,8 +1,8 @@
package=native_ccache
-$(package)_version=3.7.7
+$(package)_version=3.7.9
$(package)_download_path=https://github.com/ccache/ccache/releases/download/v$($(package)_version)
-$(package)_file_name=ccache-$($(package)_version).tar.xz
-$(package)_sha256_hash=b7c1d6d6fe42f18e424de92746af863e0bc85794da3d69e44300840c478c98cd
+$(package)_file_name=ccache-$($(package)_version).tar.gz
+$(package)_sha256_hash=92838e2133c9e704fdab9ee2608dad86c99021278b9ac47d065aa8ff2ea8ce36
define $(package)_set_vars
$(package)_config_opts=
diff --git a/doc/man/hush-cli.1 b/doc/man/hush-cli.1
index 0c9080b59..5d87d8205 100644
--- a/doc/man/hush-cli.1
+++ b/doc/man/hush-cli.1
@@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10.
-.TH HUSH-CLI "1" "March 2020" "hush-cli v3.3.2" "User Commands"
+.TH HUSH-CLI "1" "June 2020" "hush-cli v3.4.0" "User Commands"
.SH NAME
-hush-cli \- manual page for hush-cli v3.3.2
+hush-cli \- manual page for hush-cli v3.4.0
.SH DESCRIPTION
-Komodo RPC client version v3.3.2\-699b59037
+Komodo RPC client version v3.4.0\-2fbcca416\-dirty
.PP
In order to ensure you are adequately protecting your privacy when using Hush,
please see .
@@ -71,7 +71,7 @@ Timeout in seconds during HTTP requests, or 0 for no timeout. (default:
Read extra arguments from standard input, one per line until EOF/Ctrl\-D
(recommended for sensitive information such as passphrases)
.SH COPYRIGHT
-Hush Daemon version v3.3.2-699b59037
+Hush Daemon version v3.4.0-2fbcca416-dirty
In order to ensure you are adequately protecting your privacy when using Hush,
please see .
diff --git a/doc/man/hush-tx.1 b/doc/man/hush-tx.1
index 9004dcade..a6d3be7ef 100644
--- a/doc/man/hush-tx.1
+++ b/doc/man/hush-tx.1
@@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10.
-.TH HUSH-TX "1" "March 2020" "hush-tx v3.3.2" "User Commands"
+.TH HUSH-TX "1" "June 2020" "hush-tx v3.4.0" "User Commands"
.SH NAME
-hush-tx \- manual page for hush-tx v3.3.2
+hush-tx \- manual page for hush-tx v3.4.0
.SH DESCRIPTION
-Hush komodo\-tx utility version v3.3.2\-699b59037
+Hush komodo\-tx utility version v3.4.0\-2fbcca416\-dirty
.SS "Usage:"
.TP
komodo\-tx [options] [commands]
@@ -84,7 +84,7 @@ set=NAME:JSON\-STRING
.IP
Set register NAME to given JSON\-STRING
.SH COPYRIGHT
-Hush Daemon version v3.3.2-699b59037
+Hush Daemon version v3.4.0-2fbcca416-dirty
In order to ensure you are adequately protecting your privacy when using Hush,
please see .
diff --git a/doc/man/hushd.1 b/doc/man/hushd.1
index 0cde080df..6e57386b7 100644
--- a/doc/man/hushd.1
+++ b/doc/man/hushd.1
@@ -1,10 +1,10 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10.
-.TH HUSHD "1" "March 2020" "hushd v3.3.2" "User Commands"
+.TH HUSHD "1" "June 2020" "hushd v3.4.0" "User Commands"
.SH NAME
-hushd \- manual page for hushd v3.3.2
+hushd \- manual page for hushd v3.4.0
.SH DESCRIPTION
Found binary: ./komodod
-Hush Daemon version v3.3.2\-699b59037
+Hush Daemon version v3.4.0\-2fbcca416\-dirty
.PP
In order to ensure you are adequately protecting your privacy when using Hush,
please see .
@@ -87,6 +87,11 @@ leave that many cores free, default: 0)
.IP
Specify pid file (default: komodod.pid)
.HP
+\fB\-txexpirynotify=\fR
+.IP
+Execute command when transaction expires (%s in cmd is replaced by
+transaction id)
+.HP
\fB\-prune=\fR
.IP
Reduce storage requirements by pruning (deleting) old blocks. This mode
@@ -295,6 +300,11 @@ Keep the last transactions (default: 200)
.IP
Keep transactions for at least blocks (default: 10000)
.HP
+\fB\-opretmintxfee=\fR
+.IP
+Minimum fee (in KMD/kB) to allow for OP_RETURN transactions (default:
+400000)
+.HP
\fB\-paytxfee=\fR
.IP
Fee (in KMD/kB) to add to transactions you send (default: 0.00)
@@ -629,7 +639,7 @@ Starting supply, default is 0
.IP
Enforce transaction\-rate limit, default 0
.SH COPYRIGHT
-Hush Daemon version v3.3.2-699b59037
+Hush Daemon version v3.4.0-2fbcca416-dirty
In order to ensure you are adequately protecting your privacy when using Hush,
please see .
diff --git a/doc/payment-disclosure.md b/doc/payment-disclosure.md
deleted file mode 100644
index 02b4167da..000000000
--- a/doc/payment-disclosure.md
+++ /dev/null
@@ -1,107 +0,0 @@
-# Payment Disclosure (Experimental Feature)
-
-**Summary**
-
-Use RPC calls `z_getpaymentdisclosure` and `z_validatepaymentdisclosure` to reveal details of a shielded payment.
-
-**Who should read this document**
-
-Frequent users of shielded transactions, payment processors, exchanges, block explorer
-
-### Experimental Feature
-
-This is an experimental feature. Enable it by launching `zcashd` with flags:
-
- zcashd -experimentalfeatures -paymentdisclosure -debug=paymentdisclosure -txindex=1
-
-These flags can also be set as options in `zcash.conf`.
-
-All nodes that generate or validate payment disclosures must run with `txindex=1` enabled.
-
-### Background
-
-Payment Disclosure is an implementation of the work-in-progress Payment Disclosure ZIP [1].
-
-The ZIP describes a method of proving that a payment was sent to a shielded address. In the typical case, this means enabling a sender to present a proof that they transferred funds to a recipient's shielded address.
-
-[1] https://github.com/zcash/zips/pull/119
-
-### Example Use Case
-
-Alice the customer sends 10 HUSH to Bob the merchant at the shielded address shown on their website. However, Bob is not sure if he received the funds.
-
-Alice's node is running with payment disclosure enabled, so Alice generates a payment disclosure and provides it to Bob, who verifies the payment was made.
-
-If Bob is a bad merchant, Alice can present the payment disclosure to a third party to validate that payment was indeed made.
-
-### Solution
-
-A payment disclosure can be generated for any output of a JoinSplit using the RPC call:
-
- z_getpaymentdisclosure txid js_index output_index (message)
-
-An optional message can be supplied. This could be used for a refund address or some other reference, as currently it is not common practice to (ahead of time) include a refund address in the memo field when making a payment.
-
-To validate a payment disclosure, the following RPC call can be used:
-
- z_validatepaymentdisclosure hexdata
-
-### Example
-
-Generate a payment disclosure for the first joinsplit, second output (index starts from zero):
-
- hush-cli z_getpaymentdisclosure 79189528d611e811a1c7bb0358dd31343033d14b4c1e998d7c4799c40f8b652b 0 1 "Hello"
-
-This returns a payment disclosure in the form of a hex string:
-
- 706462ff000a3722aafa8190cdf9710bfad6da2af6d3a74262c1fc96ad47df814b0cd5641c2b658b0fc499477c8d991e4c4bd133303431dd5803bbc7a111e811d6289518790000000000000000017e861adb829d8cb1cbcf6330b8c2e25fb0d08041a67a857815a136f0227f8a5342bce5b3c0d894e2983000eb594702d3c1580817d0374e15078528e56bb6f80c0548656c6c6f59a7085395c9e706d82afe3157c54ad4ae5bf144fcc774a8d9c921c58471402019c156ec5641e2173c4fb6467df5f28530dc4636fa71f4d0e48fc5c560fac500
-
-To validate the payment disclosure:
-
- hush-cli z_validatepaymentdisclosure HEXDATA
-
-This returns data related to the payment and the payment disclosure:
-
- {
- "txid": "79189528d611e811a1c7bb0358dd31343033d14b4c1e998d7c4799c40f8b652b",
- "jsIndex": 0,
- "outputIndex": 1,
- "version": 0,
- "onetimePrivKey": "1c64d50c4b81df47ad96fcc16242a7d3f62adad6fa0b71f9cd9081faaa22370a",
- "message": "Hello",
- "joinSplitPubKey": "d1c465d16166b602992479acfac18e87dc18065f6cefde6a002e70bc371b9faf",
- "signatureVerified": true,
- "paymentAddress": "ztaZJXy8iX8nrk2ytXKDBoTWqPkhQcj6E2ifARnD3wfkFwsxXs5SoX7NGmrjkzSiSKn8VtLHTJae48vX5NakvmDhtGNY5eb",
- "memo": "f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
- "value": 12.49900000,
- "commitmentMatch": true,
- "valid": true
- }
-
-The `signatureVerified` field confirms that the payment disclosure was generated and signed with the joinSplitPrivKey, which should only be known by the node generating and sending the transaction 7918...652b in question.
-
-### Where is the data stored?
-
-For all nodes, payment disclosure does not touch `wallet.dat` in any way.
-
-For nodes that only validate payment disclosures, no data is stored locally.
-
-For nodes that generate payment disclosures, a LevelDB database is created in the node's datadir. For most users, this would be in the folder:
-
- $HOME/.zcash/paymentdisclosure
-
-If you decide you don't want to use payment disclosure, it is safe to shut down your node and delete the database folder.
-
-### Security Properties
-
-Please consult the work-in-progress ZIP for details about the protocol, security properties and caveats.
-
-### Reminder
-
-Feedback is most welcome!
-
-This is an experimental feature so there are no guarantees that the protocol, database format, RPC interface etc. will remain the same in the future.
-
-### Notes
-
-Currently there is no user friendly way to help senders identify which joinsplit output index maps to a given payment they made. It is possible to construct this from `debug.log`. Ideas and feedback are most welcome on how to improve the user experience.
diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh
index a23f2908d..35bf5a7e9 100755
--- a/qa/pull-tester/rpc-tests.sh
+++ b/qa/pull-tester/rpc-tests.sh
@@ -17,14 +17,12 @@ testScripts=(
'dpow.py'
'dpowconfs.py'
'ac_private.py'
- 'paymentdisclosure.py'
'prioritisetransaction.py'
'wallet_treestate.py'
'wallet_anchorfork.py'
'wallet_changeindicator.py'
'wallet_import_export.py'
'wallet_protectcoinbase.py'
- 'wallet_shieldcoinbase_sprout.py'
'wallet_shieldcoinbase_sapling.py'
'wallet_listreceived.py'
'wallet_mergetoaddress.py'
@@ -65,14 +63,11 @@ testScripts=(
'decodescript.py'
'blockchain.py'
'disablewallet.py'
- 'zcjoinsplit.py'
- 'zcjoinsplitdoublespend.py'
'ivk_import_export.py'
'zkey_import_export.py'
'getblocktemplate.py'
'bip65-cltv-p2p.py'
'bipdersig-p2p.py'
- 'p2p_nu_peer_management.py'
'rewind_index.py'
'p2p_txexpiry_dos.py'
'p2p_node_bloom.py'
diff --git a/qa/rpc-tests/p2p_nu_peer_management.py b/qa/rpc-tests/p2p_nu_peer_management.py
deleted file mode 100755
index 6cedf66bb..000000000
--- a/qa/rpc-tests/p2p_nu_peer_management.py
+++ /dev/null
@@ -1,192 +0,0 @@
-#!/usr/bin/env python2
-# Copyright (c) 2018 The Zcash developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-from test_framework.mininode import (
- NodeConn,
- NodeConnCB,
- NetworkThread,
- msg_ping,
- SPROUT_PROTO_VERSION,
- OVERWINTER_PROTO_VERSION,
- SAPLING_PROTO_VERSION,
-)
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import initialize_chain_clean, start_nodes, \
- p2p_port, assert_equal
-
-import time
-
-#
-# In this test we connect Sprout, Overwinter, and Sapling mininodes to a Zcashd
-# node which will activate Overwinter at block 10 and Sapling at block 15.
-#
-# We test:
-# 1. the mininodes stay connected to Zcash with Sprout consensus rules
-# 2. when Overwinter activates, the Sprout mininodes are dropped
-# 3. new Overwinter and Sapling nodes can connect to Zcash
-# 4. new Sprout nodes cannot connect to Zcash
-# 5. when Sapling activates, the Overwinter mininodes are dropped
-# 6. new Sapling nodes can connect to Zcash
-# 7. new Sprout and Overwinter nodes cannot connect to Zcash
-#
-# This test *does not* verify that prior to each activation, the Zcashd
-# node will prefer connections with NU-aware nodes, with an eviction process
-# that prioritizes non-NU-aware connections.
-#
-
-
-class TestManager(NodeConnCB):
- def __init__(self):
- NodeConnCB.__init__(self)
- self.create_callback_map()
-
- def on_close(self, conn):
- pass
-
- def on_reject(self, conn, message):
- conn.rejectMessage = message
-
-
-class NUPeerManagementTest(BitcoinTestFramework):
-
- def setup_chain(self):
- print "Initializing test directory "+self.options.tmpdir
- initialize_chain_clean(self.options.tmpdir, 1)
-
- def setup_network(self):
- self.nodes = start_nodes(1, self.options.tmpdir, extra_args=[[
- '-nuparams=5ba81b19:10', # Overwinter
- '-nuparams=76b809bb:15', # Sapling
- '-debug',
- '-whitelist=127.0.0.1',
- ]])
-
- def run_test(self):
- test = TestManager()
-
- # Launch Sprout, Overwinter, and Sapling mininodes
- nodes = []
- for x in xrange(10):
- nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0],
- test, "regtest", SPROUT_PROTO_VERSION))
- nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0],
- test, "regtest", OVERWINTER_PROTO_VERSION))
- nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0],
- test, "regtest", SAPLING_PROTO_VERSION))
-
- # Start up network handling in another thread
- NetworkThread().start()
-
- # Sprout consensus rules apply at block height 9
- self.nodes[0].generate(9)
- assert_equal(9, self.nodes[0].getblockcount())
-
- # Verify mininodes are still connected to zcashd node
- peerinfo = self.nodes[0].getpeerinfo()
- versions = [x["version"] for x in peerinfo]
- assert_equal(10, versions.count(SPROUT_PROTO_VERSION))
- assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION))
- assert_equal(10, versions.count(SAPLING_PROTO_VERSION))
-
- # Overwinter consensus rules activate at block height 10
- self.nodes[0].generate(1)
- assert_equal(10, self.nodes[0].getblockcount())
- print('Overwinter active')
-
- # Mininodes send ping message to zcashd node.
- pingCounter = 1
- for node in nodes:
- node.send_message(msg_ping(pingCounter))
- pingCounter = pingCounter + 1
-
- time.sleep(3)
-
- # Verify Sprout mininodes have been dropped, while Overwinter and
- # Sapling mininodes are still connected.
- peerinfo = self.nodes[0].getpeerinfo()
- versions = [x["version"] for x in peerinfo]
- assert_equal(0, versions.count(SPROUT_PROTO_VERSION))
- assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION))
- assert_equal(10, versions.count(SAPLING_PROTO_VERSION))
-
- # Extend the Overwinter chain with another block.
- self.nodes[0].generate(1)
-
- # Connect a new Overwinter mininode to the zcashd node, which is accepted.
- nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", OVERWINTER_PROTO_VERSION))
- time.sleep(3)
- assert_equal(21, len(self.nodes[0].getpeerinfo()))
-
- # Connect a new Sapling mininode to the zcashd node, which is accepted.
- nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SAPLING_PROTO_VERSION))
- time.sleep(3)
- assert_equal(22, len(self.nodes[0].getpeerinfo()))
-
- # Try to connect a new Sprout mininode to the zcashd node, which is rejected.
- sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SPROUT_PROTO_VERSION)
- nodes.append(sprout)
- time.sleep(3)
- assert("Version must be 170003 or greater" in str(sprout.rejectMessage))
-
- # Verify that only Overwinter and Sapling mininodes are connected.
- peerinfo = self.nodes[0].getpeerinfo()
- versions = [x["version"] for x in peerinfo]
- assert_equal(0, versions.count(SPROUT_PROTO_VERSION))
- assert_equal(11, versions.count(OVERWINTER_PROTO_VERSION))
- assert_equal(11, versions.count(SAPLING_PROTO_VERSION))
-
- # Sapling consensus rules activate at block height 15
- self.nodes[0].generate(4)
- assert_equal(15, self.nodes[0].getblockcount())
- print('Sapling active')
-
- # Mininodes send ping message to zcashd node.
- pingCounter = 1
- for node in nodes:
- node.send_message(msg_ping(pingCounter))
- pingCounter = pingCounter + 1
-
- time.sleep(3)
-
- # Verify Sprout and Overwinter mininodes have been dropped, while
- # Sapling mininodes are still connected.
- peerinfo = self.nodes[0].getpeerinfo()
- versions = [x["version"] for x in peerinfo]
- assert_equal(0, versions.count(SPROUT_PROTO_VERSION))
- assert_equal(0, versions.count(OVERWINTER_PROTO_VERSION))
- assert_equal(11, versions.count(SAPLING_PROTO_VERSION))
-
- # Extend the Sapling chain with another block.
- self.nodes[0].generate(1)
-
- # Connect a new Sapling mininode to the zcashd node, which is accepted.
- nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SAPLING_PROTO_VERSION))
- time.sleep(3)
- assert_equal(12, len(self.nodes[0].getpeerinfo()))
-
- # Try to connect a new Sprout mininode to the zcashd node, which is rejected.
- sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SPROUT_PROTO_VERSION)
- nodes.append(sprout)
- time.sleep(3)
- assert("Version must be 170006 or greater" in str(sprout.rejectMessage))
-
- # Try to connect a new Overwinter mininode to the zcashd node, which is rejected.
- sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", OVERWINTER_PROTO_VERSION)
- nodes.append(sprout)
- time.sleep(3)
- assert("Version must be 170006 or greater" in str(sprout.rejectMessage))
-
- # Verify that only Sapling mininodes are connected.
- peerinfo = self.nodes[0].getpeerinfo()
- versions = [x["version"] for x in peerinfo]
- assert_equal(0, versions.count(SPROUT_PROTO_VERSION))
- assert_equal(0, versions.count(OVERWINTER_PROTO_VERSION))
- assert_equal(12, versions.count(SAPLING_PROTO_VERSION))
-
- for node in nodes:
- node.disconnect_node()
-
-if __name__ == '__main__':
- NUPeerManagementTest().main()
diff --git a/qa/rpc-tests/paymentdisclosure.py b/qa/rpc-tests/paymentdisclosure.py
deleted file mode 100755
index 48d4712a9..000000000
--- a/qa/rpc-tests/paymentdisclosure.py
+++ /dev/null
@@ -1,215 +0,0 @@
-#!/usr/bin/env python2
-# Copyright (c) 2017 The Zcash developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.authproxy import JSONRPCException
-from test_framework.util import assert_equal, initialize_chain_clean, \
- start_node, connect_nodes_bi, wait_and_assert_operationid_status
-
-from decimal import Decimal
-
-class PaymentDisclosureTest (BitcoinTestFramework):
-
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 4)
-
- def setup_network(self, split=False):
- args = ['-debug=zrpcunsafe,paymentdisclosure', '-experimentalfeatures', '-paymentdisclosure', '-txindex=1']
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, args))
- self.nodes.append(start_node(1, self.options.tmpdir, args))
- # node 2 does not enable payment disclosure
- args2 = ['-debug=zrpcunsafe', '-experimentalfeatures', '-txindex=1']
- self.nodes.append(start_node(2, self.options.tmpdir, args2))
- connect_nodes_bi(self.nodes,0,1)
- connect_nodes_bi(self.nodes,1,2)
- connect_nodes_bi(self.nodes,0,2)
- self.is_network_split=False
- self.sync_all()
-
- def run_test (self):
- print "Mining blocks..."
-
- self.nodes[0].generate(4)
- walletinfo = self.nodes[0].getwalletinfo()
- assert_equal(walletinfo['immature_balance'], 40)
- assert_equal(walletinfo['balance'], 0)
- self.sync_all()
- self.nodes[2].generate(3)
- self.sync_all()
- self.nodes[1].generate(101)
- self.sync_all()
- assert_equal(self.nodes[0].getbalance(), 40)
- assert_equal(self.nodes[1].getbalance(), 10)
- assert_equal(self.nodes[2].getbalance(), 30)
-
- mytaddr = self.nodes[0].getnewaddress()
- myzaddr = self.nodes[0].z_getnewaddress()
-
- # Check that Node 2 has payment disclosure disabled.
- try:
- self.nodes[2].z_getpaymentdisclosure("invalidtxid", 0, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("payment disclosure is disabled" in errorString)
-
- # Check that Node 0 returns an error for an unknown txid
- try:
- self.nodes[0].z_getpaymentdisclosure("invalidtxid", 0, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("No information available about transaction" in errorString)
-
- # Shield coinbase utxos from node 0 of value 40, standard fee of 0.00010000
- recipients = [{"address":myzaddr, "amount":Decimal('40.0')-Decimal('0.0001')}]
- myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
- txid = wait_and_assert_operationid_status(self.nodes[0], myopid)
-
- # Check the tx has joinsplits
- assert( len(self.nodes[0].getrawtransaction("" + txid, 1)["vjoinsplit"]) > 0 )
-
- # Sync mempools
- self.sync_all()
-
- # Confirm that you can't create a payment disclosure for an unconfirmed tx
- try:
- self.nodes[0].z_getpaymentdisclosure(txid, 0, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Transaction has not been confirmed yet" in errorString)
-
- try:
- self.nodes[1].z_getpaymentdisclosure(txid, 0, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Transaction has not been confirmed yet" in errorString)
-
- # Mine tx
- self.nodes[0].generate(1)
- self.sync_all()
-
- # Confirm that Node 1 cannot create a payment disclosure for a transaction which does not impact its wallet
- try:
- self.nodes[1].z_getpaymentdisclosure(txid, 0, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Transaction does not belong to the wallet" in errorString)
-
- # Check that an invalid joinsplit index is rejected
- try:
- self.nodes[0].z_getpaymentdisclosure(txid, 1, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Invalid js_index" in errorString)
-
- try:
- self.nodes[0].z_getpaymentdisclosure(txid, -1, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Invalid js_index" in errorString)
-
- # Check that an invalid output index is rejected
- try:
- self.nodes[0].z_getpaymentdisclosure(txid, 0, 2)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Invalid output_index" in errorString)
-
- try:
- self.nodes[0].z_getpaymentdisclosure(txid, 0, -1)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Invalid output_index" in errorString)
-
- # Ask Node 0 to create and validate a payment disclosure for output 0
- message = "Here is proof of my payment!"
- pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0, message)
- result = self.nodes[0].z_validatepaymentdisclosure(pd)
- assert(result["valid"])
- output_value_sum = Decimal(result["value"])
-
- # Ask Node 1 to confirm the payment disclosure is valid
- result = self.nodes[1].z_validatepaymentdisclosure(pd)
- assert(result["valid"])
- assert_equal(result["message"], message)
- assert_equal(result["value"], output_value_sum)
-
- # Confirm that payment disclosure begins with prefix zpd:
- assert(pd.startswith("zpd:"))
-
- # Confirm that payment disclosure without prefix zpd: fails validation
- try:
- self.nodes[1].z_validatepaymentdisclosure(pd[4:])
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("payment disclosure prefix not found" in errorString)
-
- # Check that total value of output index 0 and index 1 should equal shielding amount of 40 less standard fee.
- pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 1)
- result = self.nodes[0].z_validatepaymentdisclosure(pd)
- output_value_sum += Decimal(result["value"])
- assert_equal(output_value_sum, Decimal('39.99990000'))
-
- # Create a z->z transaction, sending shielded funds from node 0 to node 1
- node1zaddr = self.nodes[1].z_getnewaddress()
- recipients = [{"address":node1zaddr, "amount":Decimal('1')}]
- myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
- txid = wait_and_assert_operationid_status(self.nodes[0], myopid)
- self.sync_all()
- self.nodes[0].generate(1)
- self.sync_all()
-
- # Confirm that Node 0 can create a valid payment disclosure
- pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0, "a message of your choice")
- result = self.nodes[0].z_validatepaymentdisclosure(pd)
- assert(result["valid"])
-
- # Confirm that Node 1, even as recipient of shielded funds, cannot create a payment disclosure
- # as the transaction was created by Node 0 and Node 1's payment disclosure database does not
- # contain the necessary data to do so, where the data would only have been available on Node 0
- # when executing z_shieldcoinbase.
- try:
- self.nodes[1].z_getpaymentdisclosure(txid, 0, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Could not find payment disclosure info for the given joinsplit output" in errorString)
-
- # Payment disclosures cannot be created for transparent transactions.
- txid = self.nodes[2].sendtoaddress(mytaddr, 1.0)
- self.sync_all()
-
- # No matter the type of transaction, if it has not been confirmed, it is ignored.
- try:
- self.nodes[0].z_getpaymentdisclosure(txid, 0, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Transaction has not been confirmed yet" in errorString)
-
- self.nodes[0].generate(1)
- self.sync_all()
-
- # Confirm that a payment disclosure can only be generated for a shielded transaction.
- try:
- self.nodes[0].z_getpaymentdisclosure(txid, 0, 0)
- assert(False)
- except JSONRPCException as e:
- errorString = e.error['message']
- assert("Transaction is not a shielded transaction" in errorString)
-
-if __name__ == '__main__':
- PaymentDisclosureTest().main()
diff --git a/qa/rpc-tests/regtest_signrawtransaction.py b/qa/rpc-tests/regtest_signrawtransaction.py
index 2e0273677..78ec1fbc8 100755
--- a/qa/rpc-tests/regtest_signrawtransaction.py
+++ b/qa/rpc-tests/regtest_signrawtransaction.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python2
+# Copyright (c) 2019-2020 The Hush developers
# Copyright (c) 2018 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,7 +19,7 @@ class RegtestSignrawtransactionTest (BitcoinTestFramework):
self.nodes[0].generate(1)
self.sync_all()
taddr = self.nodes[1].getnewaddress()
- zaddr1 = self.nodes[1].z_getnewaddress('sprout')
+ zaddr1 = self.nodes[1].z_getnewaddress('sapling')
self.nodes[0].sendtoaddress(taddr, 2.0)
self.nodes[0].generate(1)
diff --git a/qa/rpc-tests/wallet_listnotes.py b/qa/rpc-tests/wallet_listnotes.py
index 5cd89c661..90fbcced1 100755
--- a/qa/rpc-tests/wallet_listnotes.py
+++ b/qa/rpc-tests/wallet_listnotes.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python2
+# Copyright (c) 2019-2020 The Hush developers
# Copyright (c) 2018 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,89 +21,9 @@ class WalletListNotes(BitcoinTestFramework):
def run_test(self):
# Current height = 200 -> Sprout
assert_equal(200, self.nodes[0].getblockcount())
- sproutzaddr = self.nodes[0].z_getnewaddress('sprout')
# test that we can create a sapling zaddr before sapling activates
saplingzaddr = self.nodes[0].z_getnewaddress('sapling')
-
- # we've got lots of coinbase (taddr) but no shielded funds yet
- assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private']))
-
- # Set current height to 201 -> Sprout
- self.nodes[0].generate(1)
- self.sync_all()
- assert_equal(201, self.nodes[0].getblockcount())
-
- mining_addr = self.nodes[0].listunspent()[0]['address']
-
- # Shield coinbase funds (must be a multiple of 10, no change allowed pre-sapling)
- receive_amount_10 = Decimal('10.0') - Decimal('0.0001')
- recipients = [{"address":sproutzaddr, "amount":receive_amount_10}]
- myopid = self.nodes[0].z_sendmany(mining_addr, recipients)
- txid_1 = wait_and_assert_operationid_status(self.nodes[0], myopid)
- self.sync_all()
-
- # No funds (with (default) one or more confirmations) in sproutzaddr yet
- assert_equal(0, len(self.nodes[0].z_listunspent()))
- assert_equal(0, len(self.nodes[0].z_listunspent(1)))
-
- # no private balance because no confirmations yet
- assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private']))
-
- # list private unspent, this time allowing 0 confirmations
- unspent_cb = self.nodes[0].z_listunspent(0)
- assert_equal(1, len(unspent_cb))
- assert_equal(False, unspent_cb[0]['change'])
- assert_equal(txid_1, unspent_cb[0]['txid'])
- assert_equal(True, unspent_cb[0]['spendable'])
- assert_equal(sproutzaddr, unspent_cb[0]['address'])
- assert_equal(receive_amount_10, unspent_cb[0]['amount'])
-
- # list unspent, filtering by address, should produce same result
- unspent_cb_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr])
- assert_equal(unspent_cb, unspent_cb_filter)
-
- # Generate a block to confirm shield coinbase tx
- self.nodes[0].generate(1)
- self.sync_all()
-
- # Current height = 202 -> Overwinter. Default address type remains Sprout
- assert_equal(202, self.nodes[0].getblockcount())
-
- # Send 1.0 (actually 0.9999) from sproutzaddr to a new zaddr
- sproutzaddr2 = self.nodes[0].z_getnewaddress()
- receive_amount_1 = Decimal('1.0') - Decimal('0.0001')
- change_amount_9 = receive_amount_10 - Decimal('1.0')
- assert_equal('sprout', self.nodes[0].z_validateaddress(sproutzaddr2)['type'])
- recipients = [{"address": sproutzaddr2, "amount":receive_amount_1}]
- myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients)
- txid_2 = wait_and_assert_operationid_status(self.nodes[0], myopid)
- self.sync_all()
-
- # list unspent, allowing 0conf txs
- unspent_tx = self.nodes[0].z_listunspent(0)
- assert_equal(len(unspent_tx), 2)
- # sort low-to-high by amount (order of returned entries is not guaranteed)
- unspent_tx = sorted(unspent_tx, key=lambda k: k['amount'])
- assert_equal(False, unspent_tx[0]['change'])
- assert_equal(txid_2, unspent_tx[0]['txid'])
- assert_equal(True, unspent_tx[0]['spendable'])
- assert_equal(sproutzaddr2, unspent_tx[0]['address'])
- assert_equal(receive_amount_1, unspent_tx[0]['amount'])
-
- assert_equal(True, unspent_tx[1]['change'])
- assert_equal(txid_2, unspent_tx[1]['txid'])
- assert_equal(True, unspent_tx[1]['spendable'])
- assert_equal(sproutzaddr, unspent_tx[1]['address'])
- assert_equal(change_amount_9, unspent_tx[1]['amount'])
-
- unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr2])
- assert_equal(1, len(unspent_tx_filter))
- assert_equal(unspent_tx[0], unspent_tx_filter[0])
-
- unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr])
- assert_equal(1, len(unspent_tx_filter))
- assert_equal(unspent_tx[1], unspent_tx_filter[0])
# Set current height to 204 -> Sapling
self.nodes[0].generate(2)
diff --git a/qa/rpc-tests/zcjoinsplit.py b/qa/rpc-tests/zcjoinsplit.py
deleted file mode 100755
index b3ca745f8..000000000
--- a/qa/rpc-tests/zcjoinsplit.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python2
-
-#
-# Test joinsplit semantics
-#
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, start_node, \
- gather_inputs
-
-
-class JoinSplitTest(BitcoinTestFramework):
- def setup_network(self):
- self.nodes = []
- self.is_network_split = False
- self.nodes.append(start_node(0, self.options.tmpdir))
-
- def run_test(self):
- zckeypair = self.nodes[0].zcrawkeygen()
- zcsecretkey = zckeypair["zcsecretkey"]
- zcaddress = zckeypair["zcaddress"]
-
- (total_in, inputs) = gather_inputs(self.nodes[0], 40)
- protect_tx = self.nodes[0].createrawtransaction(inputs, {})
- joinsplit_result = self.nodes[0].zcrawjoinsplit(protect_tx, {}, {zcaddress:39.99}, 39.99, 0)
-
- receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
- assert_equal(receive_result["exists"], False)
-
- protect_tx = self.nodes[0].signrawtransaction(joinsplit_result["rawtxn"])
- self.nodes[0].sendrawtransaction(protect_tx["hex"])
- self.nodes[0].generate(1)
- self.sync_all()
-
- receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
- assert_equal(receive_result["exists"], True)
-
- # The pure joinsplit we create should be mined in the next block
- # despite other transactions being in the mempool.
- addrtest = self.nodes[0].getnewaddress()
- for xx in range(0,10):
- self.nodes[0].generate(1)
- self.sync_all()
- for x in range(0,50):
- self.nodes[0].sendtoaddress(addrtest, 0.01);
-
- joinsplit_tx = self.nodes[0].createrawtransaction([], {})
- joinsplit_result = self.nodes[0].zcrawjoinsplit(joinsplit_tx, {receive_result["note"] : zcsecretkey}, {zcaddress: 39.98}, 0, 0.01)
-
- self.nodes[0].sendrawtransaction(joinsplit_result["rawtxn"])
- self.nodes[0].generate(1)
- self.sync_all()
-
- print "Done!"
- receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
- assert_equal(receive_result["exists"], True)
-
-if __name__ == '__main__':
- JoinSplitTest().main()
diff --git a/qa/rpc-tests/zcjoinsplitdoublespend.py b/qa/rpc-tests/zcjoinsplitdoublespend.py
deleted file mode 100755
index b56e7475a..000000000
--- a/qa/rpc-tests/zcjoinsplitdoublespend.py
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/usr/bin/env python2
-
-#
-# Tests a joinsplit double-spend and a subsequent reorg.
-#
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.authproxy import JSONRPCException
-from test_framework.util import assert_equal, connect_nodes, \
- gather_inputs, sync_blocks
-
-import time
-
-class JoinSplitTest(BitcoinTestFramework):
- def setup_network(self):
- # Start with split network:
- return super(JoinSplitTest, self).setup_network(True)
-
- def txid_in_mempool(self, node, txid):
- exception_triggered = False
-
- try:
- node.getrawtransaction(txid)
- except JSONRPCException:
- exception_triggered = True
-
- return not exception_triggered
-
- def cannot_joinsplit(self, node, txn):
- exception_triggered = False
-
- try:
- node.sendrawtransaction(txn)
- except JSONRPCException:
- exception_triggered = True
-
- return exception_triggered
-
- def expect_cannot_joinsplit(self, node, txn):
- assert_equal(self.cannot_joinsplit(node, txn), True)
-
- def run_test(self):
- # All nodes should start with 250 HUSH:
- starting_balance = 250
- for i in range(4):
- assert_equal(self.nodes[i].getbalance(), starting_balance)
- self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress!
-
- # Generate zcaddress keypairs
- zckeypair = self.nodes[0].zcrawkeygen()
- zcsecretkey = zckeypair["zcsecretkey"]
- zcaddress = zckeypair["zcaddress"]
-
- pool = [0, 1, 2, 3]
- for i in range(4):
- (total_in, inputs) = gather_inputs(self.nodes[i], 40)
- pool[i] = self.nodes[i].createrawtransaction(inputs, {})
- pool[i] = self.nodes[i].zcrawjoinsplit(pool[i], {}, {zcaddress:39.99}, 39.99, 0)
- signed = self.nodes[i].signrawtransaction(pool[i]["rawtxn"])
-
- # send the tx to both halves of the network
- self.nodes[0].sendrawtransaction(signed["hex"])
- self.nodes[0].generate(1)
- self.nodes[2].sendrawtransaction(signed["hex"])
- self.nodes[2].generate(1)
- pool[i] = pool[i]["encryptednote1"]
-
- sync_blocks(self.nodes[0:2])
- sync_blocks(self.nodes[2:4])
-
- # Confirm that the protects have taken place
- for i in range(4):
- enc_note = pool[i]
- receive_result = self.nodes[0].zcrawreceive(zcsecretkey, enc_note)
- assert_equal(receive_result["exists"], True)
- pool[i] = receive_result["note"]
-
- # Extra confirmations
- receive_result = self.nodes[1].zcrawreceive(zcsecretkey, enc_note)
- assert_equal(receive_result["exists"], True)
-
- receive_result = self.nodes[2].zcrawreceive(zcsecretkey, enc_note)
- assert_equal(receive_result["exists"], True)
-
- receive_result = self.nodes[3].zcrawreceive(zcsecretkey, enc_note)
- assert_equal(receive_result["exists"], True)
-
- blank_tx = self.nodes[0].createrawtransaction([], {})
- # Create joinsplit {A, B}->{*}
- joinsplit_AB = self.nodes[0].zcrawjoinsplit(blank_tx,
- {pool[0] : zcsecretkey, pool[1] : zcsecretkey},
- {zcaddress:(39.99*2)-0.01},
- 0, 0.01)
-
- # Create joinsplit {B, C}->{*}
- joinsplit_BC = self.nodes[0].zcrawjoinsplit(blank_tx,
- {pool[1] : zcsecretkey, pool[2] : zcsecretkey},
- {zcaddress:(39.99*2)-0.01},
- 0, 0.01)
-
- # Create joinsplit {C, D}->{*}
- joinsplit_CD = self.nodes[0].zcrawjoinsplit(blank_tx,
- {pool[2] : zcsecretkey, pool[3] : zcsecretkey},
- {zcaddress:(39.99*2)-0.01},
- 0, 0.01)
-
- # Create joinsplit {A, D}->{*}
- joinsplit_AD = self.nodes[0].zcrawjoinsplit(blank_tx,
- {pool[0] : zcsecretkey, pool[3] : zcsecretkey},
- {zcaddress:(39.99*2)-0.01},
- 0, 0.01)
-
- # (a) Node 0 will spend joinsplit AB, then attempt to
- # double-spend it with BC. It should fail before and
- # after Node 0 mines blocks.
- #
- # (b) Then, Node 2 will spend BC, and mine 5 blocks.
- # Node 1 connects, and AB will be reorg'd from the chain.
- # Any attempts to spend AB or CD should fail for
- # both nodes.
- #
- # (c) Then, Node 0 will spend AD, which should work
- # because the previous spend for A (AB) is considered
- # invalid due to the reorg.
-
- # (a)
-
- AB_txid = self.nodes[0].sendrawtransaction(joinsplit_AB["rawtxn"])
-
- self.expect_cannot_joinsplit(self.nodes[0], joinsplit_BC["rawtxn"])
-
- # Wait until node[1] receives AB before we attempt to double-spend
- # with BC.
- print "Waiting for AB_txid...\n"
- while True:
- if self.txid_in_mempool(self.nodes[1], AB_txid):
- break
- time.sleep(0.2)
- print "Done!\n"
-
- self.expect_cannot_joinsplit(self.nodes[1], joinsplit_BC["rawtxn"])
-
- # Generate a block
- self.nodes[0].generate(1)
- sync_blocks(self.nodes[0:2])
-
- self.expect_cannot_joinsplit(self.nodes[0], joinsplit_BC["rawtxn"])
- self.expect_cannot_joinsplit(self.nodes[1], joinsplit_BC["rawtxn"])
-
- # (b)
- self.nodes[2].sendrawtransaction(joinsplit_BC["rawtxn"])
- self.nodes[2].generate(5)
-
- # Connect the two nodes
-
- connect_nodes(self.nodes[1], 2)
- sync_blocks(self.nodes)
-
- # AB and CD should all be impossible to spend for each node.
- self.expect_cannot_joinsplit(self.nodes[0], joinsplit_AB["rawtxn"])
- self.expect_cannot_joinsplit(self.nodes[0], joinsplit_CD["rawtxn"])
-
- self.expect_cannot_joinsplit(self.nodes[1], joinsplit_AB["rawtxn"])
- self.expect_cannot_joinsplit(self.nodes[1], joinsplit_CD["rawtxn"])
-
- self.expect_cannot_joinsplit(self.nodes[2], joinsplit_AB["rawtxn"])
- self.expect_cannot_joinsplit(self.nodes[2], joinsplit_CD["rawtxn"])
-
- self.expect_cannot_joinsplit(self.nodes[3], joinsplit_AB["rawtxn"])
- self.expect_cannot_joinsplit(self.nodes[3], joinsplit_CD["rawtxn"])
-
- # (c)
- # AD should be possible to send due to the reorg that
- # tossed out AB.
-
- self.nodes[0].sendrawtransaction(joinsplit_AD["rawtxn"])
- self.nodes[0].generate(1)
-
- sync_blocks(self.nodes)
-
-if __name__ == '__main__':
- JoinSplitTest().main()
diff --git a/src/Makefile.am b/src/Makefile.am
index 6277e0f98..b44dd13c5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,3 +1,5 @@
+# Copyright 2019-2020 The Hush developers
+
DIST_SUBDIRS = secp256k1 univalue cryptoconditions
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(SAN_LDFLAGS) $(HARDENED_LDFLAGS)
@@ -181,14 +183,11 @@ BITCOIN_CORE_H = \
netbase.h \
notaries_staked.h \
noui.h \
- paymentdisclosure.h \
- paymentdisclosuredb.h \
policy/fees.h \
pow.h \
prevector.h \
primitives/block.h \
primitives/transaction.h \
- primitives/nonce.h \
protocol.h \
pubkey.h \
random.h \
@@ -303,8 +302,6 @@ libbitcoin_server_a_SOURCES = \
notaries_staked.cpp \
noui.cpp \
notarisationdb.cpp \
- paymentdisclosure.cpp \
- paymentdisclosuredb.cpp \
policy/fees.cpp \
pow.cpp \
rest.cpp \
@@ -343,12 +340,10 @@ libbitcoin_proton_a_SOURCES = \
amqp/amqppublishnotifier.cpp
endif
-# wallet: zcashd, but only linked when wallet enabled
+# wallet: komodod, but only linked when wallet enabled
libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_a_SOURCES = \
- utiltest.cpp \
- utiltest.h \
zcbenchmarks.cpp \
zcbenchmarks.h \
wallet/asyncrpcoperation_mergetoaddress.cpp \
@@ -357,10 +352,8 @@ libbitcoin_wallet_a_SOURCES = \
wallet/asyncrpcoperation_shieldcoinbase.cpp \
wallet/crypter.cpp \
wallet/db.cpp \
- paymentdisclosure.cpp \
- paymentdisclosuredb.cpp \
+ zcash/Note.cpp \
transaction_builder.cpp \
- wallet/rpcdisclosure.cpp \
wallet/rpcdump.cpp \
cc/CCtokens.cpp \
cc/CCassetsCore.cpp \
@@ -436,7 +429,6 @@ libbitcoin_common_a_SOURCES = \
metrics.cpp \
primitives/block.cpp \
primitives/transaction.cpp \
- primitives/nonce.cpp \
protocol.cpp \
pubkey.cpp \
scheduler.cpp \
@@ -496,7 +488,7 @@ libbitcoin_cli_a_SOURCES = \
nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
#
-# bitcoind binary #
+# komodod binary #
komodod_SOURCES = bitcoind.cpp
komodod_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
komodod_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
@@ -555,7 +547,7 @@ if TARGET_DARWIN
komodod_LDFLAGS += -static-libgcc
endif
-# bitcoin-cli binary #
+# komodo-cli binary #
komodo_cli_SOURCES = bitcoin-cli.cpp
komodo_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS)
komodo_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
@@ -603,7 +595,7 @@ wallet_utility_LDADD = \
$(LIBCRYPTOCONDITIONS)
endif
-# zcash-tx binary #
+# komodo-tx binary #
komodo_tx_SOURCES = komodo-tx.cpp
komodo_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
komodo_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
@@ -613,7 +605,6 @@ if TARGET_WINDOWS
komodo_tx_SOURCES += bitcoin-tx-res.rc
endif
-# FIXME: Is libzcash needed for hush-tx ?
komodo_tx_LDADD = \
$(LIBUNIVALUE) \
$(LIBBITCOIN_COMMON) \
@@ -625,7 +616,6 @@ komodo_tx_LDADD = \
$(LIBCRYPTOCONDITIONS)
komodo_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
-#
# zcash protocol primitives #
libzcash_a_SOURCES = \
@@ -661,7 +651,6 @@ libzcashconsensus_la_SOURCES = \
crypto/sha512.cpp \
hash.cpp \
primitives/transaction.cpp \
- primitives/nonce.cpp \
pubkey.cpp \
script/zcashconsensus.cpp \
script/interpreter.cpp \
diff --git a/src/amount.h b/src/amount.h
index be1c39a6e..c5f49593c 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index e9c0dd056..d7a5c0afe 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -193,9 +193,10 @@ unsigned int base_uint::bits() const
{
for (int pos = WIDTH - 1; pos >= 0; pos--) {
if (pn[pos]) {
- for (int bits = 31; bits > 0; bits--) {
- if (pn[pos] & 1 << bits)
+ for (size_t bits = 31; bits > 0; bits--) {
+ if (pn[pos] & (1U << bits)) {
return 32 * pos + bits + 1;
+ }
}
return 32 * pos + 1;
}
diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp
index 364953148..67440f3da 100644
--- a/src/cc/cclib.cpp
+++ b/src/cc/cclib.cpp
@@ -1,3 +1,4 @@
+// Copyright © 2019-2020 The Hush Developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
diff --git a/src/cc/dapps/Makefile b/src/cc/dapps/Makefile
index 6e7874788..1fea27084 100644
--- a/src/cc/dapps/Makefile
+++ b/src/cc/dapps/Makefile
@@ -1,6 +1,10 @@
+# Copyright 2020 The Hush Developers
# just type make to compile all dapps
all: zmigrate oraclefeed
+subatomic:
+ $(CC) subatomic.c -o subatomic -lm
+
zmigrate:
$(CC) zmigrate.c -o zmigrate -lm
@@ -9,3 +13,4 @@ oraclefeed:
clean:
rm zmigrate oraclefeed
+
diff --git a/src/cc/dapps/dappinc.h b/src/cc/dapps/dappinc.h
new file mode 100644
index 000000000..3c71dfdec
--- /dev/null
+++ b/src/cc/dapps/dappinc.h
@@ -0,0 +1,1599 @@
+/******************************************************************************
+ * Copyright © 2014-2020 The SuperNET Developers. *
+ * *
+ * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
+ * the top-level directory of this distribution for the individual copyright *
+ * holder information and the developer policies on copyright and licensing. *
+ * *
+ * Unless otherwise agreed in a custom licensing agreement, no part of the *
+ * SuperNET software, including this file may be copied, modified, propagated *
+ * or distributed except according to the terms contained in the LICENSE file *
+ * *
+ * Removal or modification of this copyright notice is prohibited. *
+ * *
+ ******************************************************************************/
+
+#include
+#include
+#include
+#include
+#include "cJSON.c"
+
+bits256 zeroid;
+
+int32_t unstringbits(char *buf,uint64_t bits)
+{
+ int32_t i;
+ for (i=0; i<8; i++,bits>>=8)
+ if ( (buf[i]= (char)(bits & 0xff)) == 0 )
+ break;
+ buf[i] = 0;
+ return(i);
+}
+
+uint64_t stringbits(char *str)
+{
+ uint64_t bits = 0;
+ if ( str == 0 )
+ return(0);
+ int32_t i,n = (int32_t)strlen(str);
+ if ( n > 8 )
+ n = 8;
+ for (i=n-1; i>=0; i--)
+ bits = (bits << 8) | (str[i] & 0xff);
+ //printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits);
+ return(bits);
+}
+
+char hexbyte(int32_t c)
+{
+ c &= 0xf;
+ if ( c < 10 )
+ return('0'+c);
+ else if ( c < 16 )
+ return('a'+c-10);
+ else return(0);
+}
+
+int32_t _unhex(char c)
+{
+ if ( c >= '0' && c <= '9' )
+ return(c - '0');
+ else if ( c >= 'a' && c <= 'f' )
+ return(c - 'a' + 10);
+ else if ( c >= 'A' && c <= 'F' )
+ return(c - 'A' + 10);
+ return(-1);
+}
+
+int32_t is_hexstr(char *str,int32_t n)
+{
+ int32_t i;
+ if ( str == 0 || str[0] == 0 )
+ return(0);
+ for (i=0; str[i]!=0; i++)
+ {
+ if ( n > 0 && i >= n )
+ break;
+ if ( _unhex(str[i]) < 0 )
+ break;
+ }
+ if ( n == 0 )
+ return(i);
+ return(i == n);
+}
+
+int32_t unhex(char c)
+{
+ int32_t hex;
+ if ( (hex= _unhex(c)) < 0 )
+ {
+ //printf("unhex: illegal hexchar.(%c)\n",c);
+ }
+ return(hex);
+}
+
+unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); }
+
+int32_t decode_hex(unsigned char *bytes,int32_t n,char *hex)
+{
+ int32_t adjust,i = 0;
+ //printf("decode.(%s)\n",hex);
+ if ( is_hexstr(hex,n) <= 0 )
+ {
+ memset(bytes,0,n);
+ return(n);
+ }
+ if ( hex[n-1] == '\n' || hex[n-1] == '\r' )
+ hex[--n] = 0;
+ if ( hex[n-1] == '\n' || hex[n-1] == '\r' )
+ hex[--n] = 0;
+ if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) )
+ {
+ if ( n > 0 )
+ {
+ bytes[0] = unhex(hex[0]);
+ printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex));
+ }
+ bytes++;
+ hex++;
+ adjust = 1;
+ } else adjust = 0;
+ if ( n > 0 )
+ {
+ for (i=0; i>4) & 0xf);
+ hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf);
+ //printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]);
+ }
+ hexbytes[len*2] = 0;
+ //printf("len.%ld\n",len*2+1);
+ return((int32_t)len*2+1);
+}
+
+long _stripwhite(char *buf,int accept)
+{
+ int32_t i,j,c;
+ if ( buf == 0 || buf[0] == 0 )
+ return(0);
+ for (i=j=0; buf[i]!=0; i++)
+ {
+ buf[j] = c = buf[i];
+ if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') )
+ j++;
+ }
+ buf[j] = 0;
+ return(j);
+}
+
+char *clonestr(char *str)
+{
+ char *clone;
+ if ( str == 0 || str[0]==0)
+ {
+ printf("warning cloning nullstr.%p\n",str);
+ //#ifdef __APPLE__
+ // while ( 1 ) sleep(1);
+ //#endif
+ str = (char *)"";
+ }
+ clone = (char *)malloc(strlen(str)+16);
+ strcpy(clone,str);
+ return(clone);
+}
+
+int32_t safecopy(char *dest,char *src,long len)
+{
+ int32_t i = -1;
+ if ( src != 0 && dest != 0 && src != dest )
+ {
+ if ( dest != 0 )
+ memset(dest,0,len);
+ for (i=0; i0; i--)
+ str[i] = str[i-1];
+ str[0] = '/';
+ str[n+1] = 0;
+ }*/
+#endif
+ return(str);
+#endif
+}
+
+void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep)
+{
+ FILE *fp;
+ long filesize,buflen = *allocsizep;
+ uint8_t *buf = *bufp;
+ *lenp = 0;
+ if ( (fp= fopen(portable_path(fname),"rb")) != 0 )
+ {
+ fseek(fp,0,SEEK_END);
+ filesize = ftell(fp);
+ if ( filesize == 0 )
+ {
+ fclose(fp);
+ *lenp = 0;
+ //printf("loadfile null size.(%s)\n",fname);
+ return(0);
+ }
+ if ( filesize > buflen )
+ {
+ *allocsizep = filesize;
+ *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64);
+ }
+ rewind(fp);
+ if ( buf == 0 )
+ printf("Null buf ???\n");
+ else
+ {
+ if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize )
+ printf("error reading filesize.%ld\n",(long)filesize);
+ buf[filesize] = 0;
+ }
+ fclose(fp);
+ *lenp = filesize;
+ //printf("loaded.(%s)\n",buf);
+ } //else printf("OS_loadfile couldnt load.(%s)\n",fname);
+ return(buf);
+}
+
+void *filestr(long *allocsizep,char *_fname)
+{
+ long filesize = 0; char *fname,*buf = 0; void *retptr;
+ *allocsizep = 0;
+ fname = malloc(strlen(_fname)+1);
+ strcpy(fname,_fname);
+ retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep);
+ free(fname);
+ return(retptr);
+}
+
+char *send_curl(char *url,char *fname)
+{
+ long fsize; char curlstr[1024];
+ sprintf(curlstr,"curl --url \"%s\" > %s",url,fname);
+ system(curlstr);
+ return(filestr(&fsize,fname));
+}
+
+cJSON *get_urljson(char *url,char *fname)
+{
+ char *jsonstr; cJSON *json = 0;
+ if ( (jsonstr= send_curl(url,fname)) != 0 )
+ {
+ //printf("(%s) -> (%s)\n",url,jsonstr);
+ json = cJSON_Parse(jsonstr);
+ free(jsonstr);
+ }
+ return(json);
+}
+
+//////////////////////////////////////////////
+// start of dapp
+//////////////////////////////////////////////
+int md_unlink(char *file)
+{
+#ifdef _WIN32
+ _chmod(file, 0600);
+ return( _unlink(file) );
+#else
+ return(unlink(file));
+#endif
+}
+
+char *REFCOIN_CLI,DPOW_pubkeystr[67],DPOW_secpkeystr[67],DPOW_handle[67],DPOW_recvaddr[64],DPOW_recvZaddr[128];
+
+cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
+{
+ long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[32768];
+ sprintf(fname,"/tmp/notarizer_%s_%d",method,(rand() >> 17) % 10000);
+ //if ( (acname == 0 || acname[0] == 0) && strcmp(refcoin,"KMD") != 0 )
+ // acname = refcoin;
+ if ( acname[0] != 0 )
+ {
+ if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 && strcmp(refcoin,acname) != 0 )
+ printf("unexpected: refcoin.(%s) acname.(%s)\n",refcoin,acname);
+ sprintf(cmdstr,"komodo-cli -ac_name=%s %s %s %s %s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname);
+ }
+ else if ( strcmp(refcoin,"KMD") == 0 )
+ sprintf(cmdstr,"komodo-cli %s %s %s %s %s %s %s %s > %s\n",method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname);
+ else if ( REFCOIN_CLI != 0 && REFCOIN_CLI[0] != 0 )
+ {
+ sprintf(cmdstr,"%s %s %s %s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname);
+ //printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr);
+ }
+//fprintf(stderr,"system(%s)\n",cmdstr);
+ system(cmdstr);
+ *retstrp = 0;
+ if ( (jsonstr= filestr(&fsize,fname)) != 0 )
+ {
+ jsonstr[strlen(jsonstr)-1]='\0';
+ //fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr);
+ if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 )
+ *retstrp = jsonstr;
+ else free(jsonstr);
+ md_unlink(fname);
+ } //else fprintf(stderr,"system(%s) -> NULL\n",cmdstr);
+ return(retjson);
+}
+
+cJSON *subatomic_cli(char *clistr,char **retstrp,char *method,char *arg0,char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
+{
+ long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[32768];
+ sprintf(fname,"/tmp/subatomic_%s_%d",method,(rand() >> 17) % 10000);
+ sprintf(cmdstr,"%s %s %s %s %s %s %s %s %s > %s\n",clistr,method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname);
+//fprintf(stderr,"system(%s)\n",cmdstr);
+ system(cmdstr);
+ *retstrp = 0;
+ if ( (jsonstr= filestr(&fsize,fname)) != 0 )
+ {
+ jsonstr[strlen(jsonstr)-1]='\0';
+ //fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr);
+ if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 )
+ *retstrp = jsonstr;
+ else free(jsonstr);
+ md_unlink(fname);
+ } //else fprintf(stderr,"system(%s) -> NULL\n",cmdstr);
+ return(retjson);
+}
+
+bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson)
+{
+ char *hexstr,*retstr,str[65]; cJSON *retjson; bits256 txid;
+ memset(txid.bytes,0,sizeof(txid));
+ if ( (hexstr= jstr(hexjson,"hex")) != 0 )
+ {
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","","","","")) != 0 )
+ {
+ //fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0));
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ if ( strlen(retstr) >= 64 )
+ {
+ retstr[64] = 0;
+ decode_hex(txid.bytes,32,retstr);
+ }
+ fprintf(stderr,"broadcast %s txid.(%s)\n",strlen(acname)>0?acname:refcoin,bits256_str(str,txid));
+ free(retstr);
+ }
+ }
+ return(txid);
+}
+
+bits256 sendtoaddress(char *refcoin,char *acname,char *destaddr,int64_t satoshis,char *oprethexstr)
+{
+ char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid;
+ memset(txid.bytes,0,sizeof(txid));
+ sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN);
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"false","","",oprethexstr,"")) != 0 )
+ {
+ fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0));
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ if ( strlen(retstr) >= 64 )
+ {
+ retstr[64] = 0;
+ decode_hex(txid.bytes,32,retstr);
+ }
+ fprintf(stderr,"sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid));
+ free(retstr);
+ }
+ return(txid);
+}
+
+bits256 tokentransfer(char *refcoin,char *acname,char *tokenid,char *destpub,int64_t units)
+{
+ char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid;
+ memset(txid.bytes,0,sizeof(txid));
+ sprintf(numstr,"%llu",(long long)units);
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"tokentransfer",tokenid,destpub,numstr,"","","","")) != 0 )
+ {
+ txid = komodobroadcast(refcoin,acname,retjson);
+ fprintf(stderr,"tokentransfer returned (%s)\n",jprint(retjson,0));
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"tokentransfer.(%s) error.(%s)\n",acname,retstr);
+ free(retstr);
+ }
+ return(txid);
+}
+
+char *get_tokenaddress(char *refcoin,char *acname,char *tokenaddr)
+{
+ char *retstr,*str; cJSON *retjson;
+ tokenaddr[0] = 0;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"tokenaddress","","","","","","","")) != 0 )
+ {
+ if ( (str= jstr(retjson,"myCCAddress(Tokens)")) != 0 )
+ {
+ strcpy(tokenaddr,str);
+ fprintf(stderr,"tokenaddress returned (%s)\n",tokenaddr);
+ free_json(retjson);
+ return(tokenaddr);
+ }
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ //fprintf(stderr,"tokentransfer.(%s) error.(%s)\n",acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+int64_t get_tokenbalance(char *refcoin,char *acname,char *tokenid)
+{
+ cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"tokenbalance",tokenid,"","","","","","")) != 0 )
+ {
+ amount = j64bits(retjson,"balance");
+ fprintf(stderr,"tokenbalance %llu\n",(long long)amount);
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ //printf("retstr %s -> %.8f\n",retstr,dstr(amount));
+ free(retstr);
+ }
+ return (amount);
+}
+
+cJSON *get_decodescript(char *refcoin,char *acname,char *script)
+{
+ cJSON *retjson; char *retstr;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"decodescript",script,"","","","","","")) != 0 )
+ {
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"get_decodescript.(%s) error.(%s)\n",acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+char *get_createmultisig2(char *refcoin,char *acname,char *msigaddr,char *redeemscript,char *pubkeyA,char *pubkeyB)
+{
+ //char para 2 '["02c3af47b51a506b08b4ededb156cb4c3f9db9e0ac7ad27b8623c08a056fdcc220", "038e61fbface549a850862f12ed99b7cbeef5c2bd2d8f1daddb34809416f0259e1"]'
+ cJSON *retjson; char *retstr,*str,params[256]; int32_t height=0;
+ msigaddr[0] = 0;
+ redeemscript[0] = 0;
+ sprintf(params,"'[\"%s\", \"%s\"]'",pubkeyA,pubkeyB);
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"createmultisig","2",params,"","","","","")) != 0 )
+ {
+ if ( (str= jstr(retjson,"address")) != 0 )
+ strcpy(msigaddr,str);
+ if ( (str= jstr(retjson,"redeemScript")) != 0 )
+ strcpy(redeemscript,str);
+ free_json(retjson);
+ if ( msigaddr[0] != 0 && redeemscript[0] != 0 )
+ return(msigaddr);
+ else return(0);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"%s get_createmultisig2.(%s) error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+int32_t get_coinheight(char *refcoin,char *acname,bits256 *blockhashp)
+{
+ cJSON *retjson; char *retstr; int32_t height=0;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockchaininfo","","","","","","","")) != 0 )
+ {
+ height = jint(retjson,"blocks");
+ *blockhashp = jbits256(retjson,"bestblockhash");
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"%s get_coinheight.(%s) error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(height);
+}
+
+bits256 get_coinblockhash(char *refcoin,char *acname,int32_t height)
+{
+ cJSON *retjson; char *retstr,heightstr[32]; bits256 hash;
+ memset(hash.bytes,0,sizeof(hash));
+ sprintf(heightstr,"%d",height);
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","","","","")) != 0 )
+ {
+ fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0));
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ if ( strlen(retstr) >= 64 )
+ {
+ retstr[64] = 0;
+ decode_hex(hash.bytes,32,retstr);
+ }
+ free(retstr);
+ }
+ return(hash);
+}
+
+bits256 get_coinmerkleroot(char *refcoin,char *acname,bits256 blockhash,uint32_t *blocktimep)
+{
+ cJSON *retjson; char *retstr,str[65]; bits256 merkleroot;
+ memset(merkleroot.bytes,0,sizeof(merkleroot));
+ *blocktimep = 0;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","","","","")) != 0 )
+ {
+ merkleroot = jbits256(retjson,"merkleroot");
+ *blocktimep = juint(retjson,"time");
+ //fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot));
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"%s %s get_coinmerkleroot error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(merkleroot);
+}
+
+uint32_t get_heighttime(char *refcoin,char *acname,int32_t height)
+{
+ bits256 blockhash; uint32_t blocktime;
+ blockhash = get_coinblockhash(refcoin,acname,height);
+ get_coinmerkleroot(refcoin,acname,blockhash,&blocktime);
+ return(blocktime);
+}
+
+int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *merklerootp,int32_t prevheight)
+{
+ int32_t height = 0; char str[65]; bits256 bhash; uint32_t blocktime;
+ if ( prevheight == 0 )
+ height = get_coinheight(refcoin,acname,&bhash) - 20;
+ else height = prevheight + 1;
+ if ( height > 0 )
+ {
+ *blockhashp = get_coinblockhash(refcoin,acname,height);
+ if ( bits256_nonz(*blockhashp) != 0 )
+ {
+ *merklerootp = get_coinmerkleroot(refcoin,acname,*blockhashp,&blocktime);
+ if ( bits256_nonz(*merklerootp) != 0 )
+ return(height);
+ }
+ }
+ memset(blockhashp,0,sizeof(*blockhashp));
+ memset(merklerootp,0,sizeof(*merklerootp));
+ return(0);
+}
+
+cJSON *get_rawmempool(char *refcoin,char *acname)
+{
+ cJSON *retjson; char *retstr;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawmempool","","","","","","","")) != 0 )
+ {
+ //printf("mempool.(%s)\n",jprint(retjson,0));
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"get_rawmempool.(%s) error.(%s)\n",acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
+{
+ cJSON *retjson; char *retstr,jsonbuf[256];
+ if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 )
+ printf("warning: assumes %s has addressindex enabled\n",refcoin);
+ sprintf(jsonbuf,"{\\\"addresses\\\":[\\\"%s\\\"]}",coinaddr);
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","","","","")) != 0 )
+ {
+ //printf("addressutxos.(%s)\n",jprint(retjson,0));
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid)
+{
+ cJSON *retjson; char *retstr,str[65];
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","","","","")) != 0 )
+ {
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"get_rawtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+cJSON *get_z_viewtransaction(char *refcoin,char *acname,bits256 txid)
+{
+ cJSON *retjson; char *retstr,str[65];
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_viewtransaction",bits256_str(str,txid),"","","","","","")) != 0 )
+ {
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"get_z_viewtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+cJSON *get_listunspent(char *refcoin,char *acname)
+{
+ cJSON *retjson; char *retstr,str[65];
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","","","","","","","")) != 0 )
+ {
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"get_listunspent.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+cJSON *get_getinfo(char *refcoin,char *acname)
+{
+ cJSON *retjson; char *retstr,str[65];
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getinfo","","","","","","","")) != 0 )
+ {
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"get_getinfo.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+cJSON *z_listunspent(char *refcoin,char *acname)
+{
+ cJSON *retjson; char *retstr,str[65];
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_listunspent","","","","","","","")) != 0 )
+ {
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"z_listunspent.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+cJSON *z_listoperationids(char *refcoin,char *acname)
+{
+ cJSON *retjson; char *retstr,str[65];
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_listoperationids","","","","","","","")) != 0 )
+ {
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"z_listoperationids.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+cJSON *z_getoperationstatus(char *refcoin,char *acname,char *opid)
+{
+ cJSON *retjson; char *retstr,str[65],params[512];
+ sprintf(params,"'[\"%s\"]'",opid);
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getoperationstatus",params,"","","","","","")) != 0 )
+ {
+ //printf("got status (%s)\n",jprint(retjson,0));
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"z_getoperationstatus.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+cJSON *z_getoperationresult(char *refcoin,char *acname,char *opid)
+{
+ cJSON *retjson; char *retstr,str[65],params[512];
+ sprintf(params,"'[\"%s\"]'",opid);
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getoperationresult",params,"","","","","","")) != 0 )
+ {
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"z_getoperationresult.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* compare)
+{
+ cJSON *retjson; char *retstr; int32_t res=0;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","","","","")) != 0 )
+ {
+ if (is_cJSON_True(jobj(retjson,compare)) != 0 ) res=1;
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return (res);
+}
+
+int32_t z_validateaddress(char *refcoin,char *acname,char *depositaddr, char *compare)
+{
+ cJSON *retjson; char *retstr; int32_t res=0;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_validateaddress",depositaddr,"","","","","","")) != 0 )
+ {
+ if (is_cJSON_True(jobj(retjson,compare)) != 0 )
+ res=1;
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"z_validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr);
+ free(retstr);
+ }
+ return (res);
+}
+
+int64_t get_getbalance(char *refcoin,char *acname)
+{
+ cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getbalance","","","","","","","")) != 0 )
+ {
+ fprintf(stderr,"get_getbalance.(%s) %s returned json!\n",refcoin,acname);
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ amount = atof(retstr) * SATOSHIDEN;
+ sprintf(cmpstr,"%.8f",dstr(amount));
+ if ( strcmp(retstr,cmpstr) != 0 )
+ amount++;
+ //printf("retstr %s -> %.8f\n",retstr,dstr(amount));
+ free(retstr);
+ }
+ return (amount);
+}
+
+int64_t z_getbalance(char *refcoin,char *acname,char *coinaddr)
+{
+ cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getbalance",coinaddr,"","","","","","")) != 0 )
+ {
+ fprintf(stderr,"z_getbalance.(%s) %s returned json!\n",refcoin,acname);
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ amount = atof(retstr) * SATOSHIDEN;
+ sprintf(cmpstr,"%.8f",dstr(amount));
+ if ( strcmp(retstr,cmpstr) != 0 )
+ amount++;
+ //printf("retstr %s -> %.8f\n",retstr,dstr(amount));
+ free(retstr);
+ }
+ return (amount);
+}
+
+int32_t z_exportkey(char *privkey,char *refcoin,char *acname,char *zaddr)
+{
+ cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
+ privkey[0] = 0;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_exportkey",zaddr,"","","","","","")) != 0 )
+ {
+ fprintf(stderr,"z_exportkey.(%s) %s returned json!\n",refcoin,acname);
+ free_json(retjson);
+ return(-1);
+ }
+ else if ( retstr != 0 )
+ {
+ //printf("retstr %s -> %.8f\n",retstr,dstr(amount));
+ strcpy(privkey,retstr);
+ free(retstr);
+ return(0);
+ }
+ return(-1);
+}
+
+int32_t getnewaddress(char *coinaddr,char *refcoin,char *acname)
+{
+ cJSON *retjson; char *retstr; int64_t amount=0; int32_t retval = -1;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getnewaddress","","","","","","","")) != 0 )
+ {
+ fprintf(stderr,"getnewaddress.(%s) %s returned json!\n",refcoin,acname);
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ strcpy(coinaddr,retstr);
+ free(retstr);
+ retval = 0;
+ }
+ return(retval);
+}
+
+int32_t z_getnewaddress(char *coinaddr,char *refcoin,char *acname,char *typestr)
+{
+ cJSON *retjson; char *retstr; int64_t amount=0; int32_t retval = -1;
+ if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getnewaddress",typestr,"","","","","","")) != 0 )
+ {
+ fprintf(stderr,"z_getnewaddress.(%s) %s returned json!\n",refcoin,acname);
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ strcpy(coinaddr,retstr);
+ free(retstr);
+ retval = 0;
+ }
+ return(retval);
+}
+
+int64_t find_onetime_amount(char *coinstr,char *coinaddr)
+{
+ cJSON *array,*item; int32_t i,n; char *addr; int64_t amount = 0;
+ 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 0 )
+ {
+ for (i=0; i %s\n",coinstr,acname,srcaddr,params);
+ if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_sendmany",addr,params,"","","","","")) != 0 )
+ {
+ printf("unexpected json z_sendmany.(%s)\n",jprint(retjson,0));
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"z_sendmany.(%s) -> opid.(%s)\n",coinstr,retstr);
+ strcpy(opidstr,retstr);
+ free(retstr);
+ retval = 0;
+ }
+ return(retval);
+}
+
+int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr)
+{
+ cJSON *retjson; char *retstr,addr[128],*opstr; int32_t retval = -1;
+ sprintf(addr,"[\\\"ANY_SPROUT\\\"]");
+ if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_mergetoaddress",addr,destaddr,"","","","","")) != 0 )
+ {
+ if ( (opstr= jstr(retjson,"opid")) != 0 )
+ strcpy(opidstr,opstr);
+ retval = jint(retjson,"remainingNotes");
+ fprintf(stderr,"%s\n",jprint(retjson,0));
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"z_mergetoaddress.(%s) -> opid.(%s)\n",coinstr,retstr);
+ strcpy(opidstr,retstr);
+ free(retstr);
+ }
+ return(retval);
+}
+
+int32_t empty_mempool(char *coinstr,char *acname)
+{
+ cJSON *array; int32_t n;
+ if ( (array= get_rawmempool(coinstr,acname)) != 0 )
+ {
+ if ( (n= cJSON_GetArraySize(array)) > 0 )
+ return(0);
+ free_json(array);
+ return(1);
+ }
+ return(-1);
+}
+
+cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required)
+{
+ cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid;
+ *totalp = 0;
+ if ( (n= cJSON_GetArraySize(unspents)) > 0 )
+ {
+ for (i=0; i= required )
+ break;
+ }
+ }
+ }
+ return(vins);
+}
+
+int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinaddr)
+{
+ cJSON *txobj,*vouts,*vout,*vins,*vin,*sobj,*addresses; char *addr,str[65]; int32_t i,j,n,numarray,retval = 0, hasvout=0;
+ if ( (txobj= get_rawtransaction(refcoin,acname,txid)) != 0 )
+ {
+ if ( (vouts= jarray(&numarray,txobj,"vout")) != 0 )
+ {
+ for (i=0; i 0 )
+ {
+ for (i=0; i 0 )
+ {
+ for (j=0; j 0 && strcmp(vinaddr,cmpaddr) == 0 )
+ return(0);
+ printf("mismatched vinaddr.(%s) vs %s\n",vinaddr,cmpaddr);
+ }
+ }
+ return(-1);
+}
+
+int32_t txid_in_vins(char *refcoin,bits256 txid,bits256 cmptxid)
+{
+ cJSON *txjson,*vins,*vin; int32_t numvins,v,vinvout; bits256 vintxid; char str[65];
+ if ( (txjson= get_rawtransaction(refcoin,"",txid)) != 0 )
+ {
+ if ( (vins= jarray(&numvins,txjson,"vin")) != 0 )
+ {
+ for (v=0; v n.%d retval.%d\n",tagA,tagB,pubkeystr,n,retval);
+ }
+ free_json(retjson);
+ }
+ return(retval);
+}
+
+int32_t dpow_hasmessage(char *payload,char *tagA,char *tagB,char *pubkeystr)
+{
+ cJSON *retjson,*item,*array; char *retstr,*pstr; int32_t i,n,retval = 0;
+ if ( (retjson= get_komodocli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list","0","0",tagA,tagB,pubkeystr,"","")) != 0 )
+ {
+ if ( (array= jarray(&n,retjson,"matches")) != 0 )
+ {
+ for (i=0; i 0 )
+ {
+ ptrs = calloc(n,sizeof(*ptrs));
+ for (i=0; ishorthash = juint(item,"id");
+ ptrs[m]->jsonstr = ptr;
+ strcpy(ptrs[m]->senderpub,senderpub);
+ m++;
+ }
+ }
+ }
+ *nump = m;
+ }
+ free_json(retjson);
+ }
+ return(ptrs);
+}
+
+
diff --git a/src/cc/dapps/subatomic.c b/src/cc/dapps/subatomic.c
new file mode 100644
index 000000000..2f6ebf824
--- /dev/null
+++ b/src/cc/dapps/subatomic.c
@@ -0,0 +1,1429 @@
+/******************************************************************************
+ * Copyright © 2014-2020 The SuperNET Developers. *
+ * *
+ * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
+ * the top-level directory of this distribution for the individual copyright *
+ * holder information and the developer policies on copyright and licensing. *
+ * *
+ * Unless otherwise agreed in a custom licensing agreement, no part of the *
+ * SuperNET software, including this file may be copied, modified, propagated *
+ * or distributed except according to the terms contained in the LICENSE file *
+ * *
+ * Removal or modification of this copyright notice is prohibited. *
+ * *
+ ******************************************************************************/
+
+// build subatomic and put in path: git pull; gcc cc/dapps/subatomic.c -lm -o subatomic; cp subatomic /usr/bin
+// alice sends relcoin and gets basecoin
+
+#define DEXP2P_CHAIN ((char *)"DEX")
+#define DEXP2P_PUBKEYS ((char *)"subatomic")
+#include "dappinc.h"
+
+// for OTC mode, the following 4 functions are the only ones that should be needed to support a new "coin"
+//int64_t subatomic_getbalance(char *coin);
+//bits256 subatomic_coinpayment(int32_t OTCmode,char *coin,char *destaddr,uint64_t paytoshis,char *memostr);
+//cJSON *subatomic_txidwait(char *coin,bits256 txid,char *hexstr,int32_t numseconds);
+//int64_t subatomic_verifypayment(char *coin,cJSON *rawtx,uint64_t destsatoshis,char *destaddr);
+
+// TODO:
+// address conversion
+// new inventory types:
+// anonsend
+
+// bob nodes:
+// mutex for bob instances
+// "deposits" messages and approved bobs
+// volume caps per coin and non-notarized exposure
+
+// later:
+// sharded storage
+
+#define SUBATOMIC_OTCDEFAULT 1
+#define SUBATOMIC_TIMEOUT 60
+#define SUBATOMIC_LOCKTIME 3600
+#define SUBATOMIC_TXFEE 10000
+
+#define SUBATOMIC_PRIORITY 5
+
+#define SUBATOMIC_OPENREQUEST 1
+#define SUBATOMIC_APPROVED 2
+#define SUBATOMIC_OPENED 3
+#define SUBATOMIC_PAYMENT 4
+#define SUBATOMIC_PAIDINFULL 5
+#define SUBATOMIC_CLOSED 6
+
+cJSON *SUBATOMIC_json;
+int32_t SUBATOMIC_retval = -1;
+
+struct abinfo
+{
+ char pubkey[67],recvaddr[64],recvZaddr[128],secp[67];
+};
+
+struct coininfo
+{
+ uint64_t satoshis,txfee,maxamount;
+ char istoken,iszaddr,isfile,isexternal,tokenid[65],coin[16],name[16],cli[256],acname[16],coinstr[16];
+};
+
+struct msginfo
+{
+ UT_hash_handle hh;
+ bits256 bobpayment,alicepayment;
+ double price;
+ uint64_t gotpayment;
+ uint32_t origid,openrequestid,approvalid,openedid,paymentids[100],paidid,closedid,locktime;
+ int32_t bobflag,status,OTCmode;
+ char payload[128],approval[128],senderpub[67],msigaddr[64],redeemscript[256];
+ struct coininfo base,rel;
+ struct abinfo alice,bob;
+} *Messages;
+
+uint64_t subatomic_txfee(char *coin)
+{
+ return(SUBATOMIC_TXFEE);
+}
+
+char *subatomic_checkname(char *tmpstr,struct msginfo *mp,int32_t baserel,char *coin)
+{
+ int32_t i,n; cJSON *external,*item; char *coinstr,*clistr; struct coininfo *ptr;
+ ptr = (baserel == 0) ? &mp->base : &mp->rel;
+ if ( coin[0] == 0 )
+ return(coin);
+ if ( (external= jarray(&n,SUBATOMIC_json,"externalcoins")) != 0 && n > 0 )
+ {
+ for (i=0; icli) )
+ {
+ ptr->isexternal = 1;
+ strcpy(ptr->cli,clistr);
+ //fprintf(stderr,"found external coin %s %s\n",coin,clistr);
+ }
+ }
+ }
+ if ( coin[0] == '#' )
+ {
+ strcpy(ptr->coinstr,coin);
+ strcpy(ptr->acname,"");
+ ptr->isfile = 1;
+ return(coin);
+ }
+ else if ( coin[0] != 'z' )
+ {
+ for (i=1; coin[i]!=0; i++)
+ if ( coin[i] == '.' )
+ {
+ dpow_tokenregister(ptr->tokenid,0,coin,0);
+ if ( ptr->tokenid[0] != 0 )
+ {
+ strcpy(tmpstr,coin);
+ tmpstr[i] = 0;
+ //fprintf(stderr,"found a tokenmap %s -> %s %s\n",coin,tmpstr,ptr->tokenid);
+ ptr->istoken = 1;
+ strcpy(ptr->acname,coin);
+ strcpy(ptr->coinstr,"");
+ return(tmpstr);
+ }
+ }
+ if ( ptr->isexternal == 0 )
+ {
+ if ( strcmp(coin,"KMD") != 0 )
+ {
+ strcpy(ptr->acname,coin);
+ strcpy(ptr->coinstr,"");
+ }
+ else
+ {
+ strcpy(ptr->coinstr,coin);
+ strcpy(ptr->acname,"");
+ }
+ }
+ else
+ {
+ strcpy(ptr->coinstr,coin);
+ strcpy(ptr->acname,"");
+ }
+ return(coin);
+ }
+ else
+ {
+ for (i=1; coin[i]!=0; i++)
+ if ( isupper(coin[i]) == 0 )
+ return(coin);
+ if ( strcmp(coin+1,"KMD") != 0 )
+ ptr->iszaddr = 1;
+ return(coin+1);
+ }
+}
+
+int32_t subatomic_zonly(struct coininfo *coin)
+{
+ if ( strcmp(coin->coin,"PIRATE") == 0 )
+ return(1);
+ else return(coin->iszaddr);
+}
+
+// //////////////////////////////// the four key functions needed to support a new item for subatomics
+
+int64_t _subatomic_getbalance(struct coininfo *coin)
+{
+ cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
+ if ( (retjson= subatomic_cli(coin->cli,&retstr,"getbalance","","","","","","","")) != 0 )
+ {
+ fprintf(stderr,"_subatomic_getbalance.(%s) %s returned json!\n",coin->coinstr,coin->cli);
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ amount = atof(retstr) * SATOSHIDEN;
+ sprintf(cmpstr,"%.8f",dstr(amount));
+ if ( strcmp(retstr,cmpstr) != 0 )
+ amount++;
+ //printf("retstr %s -> %.8f\n",retstr,dstr(amount));
+ free(retstr);
+ }
+ return (amount);
+}
+
+bits256 _subatomic_sendtoaddress(struct coininfo *coin,char *destaddr,int64_t satoshis)
+{
+ char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid;
+ memset(txid.bytes,0,sizeof(txid));
+ sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN);
+ if ( (retjson= subatomic_cli(coin->cli,&retstr,"sendtoaddress",destaddr,numstr,"false","","","","")) != 0 )
+ {
+ fprintf(stderr,"unexpected _subatomic_sendtoaddress json.(%s)\n",jprint(retjson,0));
+ free_json(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ if ( strlen(retstr) >= 64 )
+ {
+ retstr[64] = 0;
+ decode_hex(txid.bytes,32,retstr);
+ }
+ fprintf(stderr,"_subatomic_sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid));
+ free(retstr);
+ }
+ return(txid);
+}
+
+cJSON *_subatomic_rawtransaction(struct coininfo *coin,bits256 txid)
+{
+ cJSON *retjson; char *retstr,str[65];
+ if ( (retjson= subatomic_cli(coin->cli,&retstr,"getrawtransaction",bits256_str(str,txid),"1","","","","","")) != 0 )
+ {
+ return(retjson);
+ }
+ else if ( retstr != 0 )
+ {
+ fprintf(stderr,"_subatomic_rawtransaction.(%s) %s error.(%s)\n",coin->coin,coin->name,retstr);
+ free(retstr);
+ }
+ return(0);
+}
+
+int64_t subatomic_getbalance(struct coininfo *coin)
+{
+ char *coinstr,*acname=""; FILE *fp; int64_t retval = 0;
+ if ( strcmp(coin->coin,"KMD") != 0 )
+ {
+ acname = coin->coin;
+ coinstr = "";
+ } else coinstr = coin->coin;
+ if ( coin->isfile != 0 )
+ {
+ if ( (fp= fopen(coin->name+1,"rb")) != 0 ) // if alice, add bob pubkey to fname
+ {
+ fclose(fp);
+ retval = SATOSHIDEN;
+ }
+ return(retval);
+ }
+ else if ( subatomic_zonly(coin) != 0 )
+ return(z_getbalance(coinstr,acname,DPOW_recvZaddr));
+ else
+ {
+ if ( coin->istoken != 0 )
+ {
+ if ( get_getbalance(coinstr,acname) < SUBATOMIC_TXFEE )
+ {
+ fprintf(stderr,"not enough balance to send token\n");
+ return(0);
+ }
+ //fprintf(stderr,"token balance %s\n",coin->tokenid);
+ return(get_tokenbalance(coinstr,acname,coin->tokenid) * SATOSHIDEN);
+ }
+ else if ( coin->isexternal == 0 )
+ return(get_getbalance(coinstr,acname));
+ else return(_subatomic_getbalance(coin));
+ }
+}
+
+bits256 subatomic_coinpayment(uint32_t origid,int32_t OTCmode,struct coininfo *coin,char *destaddr,uint64_t paytoshis,char *memostr,char *destpub,char *senderpub)
+{
+ bits256 txid; char opidstr[128],opretstr[32],str[65],*status,*coinstr,*acname=""; cJSON *retjson,*retjson2,*item,*res; int32_t i,pending=0;
+ memset(&txid,0,sizeof(txid));
+ if ( OTCmode == 0 )
+ {
+ fprintf(stderr,"micropayment channels are not supported yet\n");
+ return(txid);
+ }
+ if ( coin->isfile != 0 )
+ {
+ fprintf(stderr,"start broadcast of (%s)\n",coin->coin+1);
+ if ( (retjson= dpow_publish(SUBATOMIC_PRIORITY,coin->coin+1)) != 0 ) // spawn thread
+ {
+ sprintf(opretstr,"%08x",juint(retjson,"id"));
+ sprintf(opidstr,"%u",origid);
+ if ( (retjson2= dpow_broadcast(SUBATOMIC_PRIORITY,opretstr,"inbox",opidstr,senderpub,"","")) != 0 )
+ free_json(retjson2);
+ fprintf(stderr,"broadcast file.(%s) and send id.%u to alice (%s)\n",coin->coin+1,juint(retjson,"id"),jprint(retjson,0));
+ txid = jbits256(retjson,"filehash");
+ free_json(retjson);
+ }
+ fprintf(stderr,"end broadcast of (%s) to %s\n",coin->coin+1,senderpub);
+ return(txid);
+ }
+ else if ( subatomic_zonly(coin) != 0 )
+ {
+ if ( memostr[0] == 0 )
+ memostr = "beef";
+ z_sendmany(opidstr,"",coin->coin,DPOW_recvZaddr,destaddr,paytoshis,memostr);
+ for (i=0; icoin,opidstr)) != 0 )
+ {
+ item = jitem(retjson,0);
+ if ( (status= jstr(item,"status")) != 0 )
+ {
+ if ( strcmp(status,"executing") == 0 )
+ pending++;
+ else
+ {
+ res = jobj(item,"result");
+ txid = jbits256(res,"txid");
+ //fprintf(stderr,"got Ztx txid.%s\n",bits256_str(str,txid));
+ free_json(retjson);
+ break;
+ }
+ /*else if ( clearresults != 0 )
+ {
+ if ( (result= z_getoperationresult(coinstr,"",jstri(array,i))) != 0 )
+ {
+ free_json(result);
+ }
+ }*/
+ }
+ free_json(retjson);
+ }
+ sleep(1);
+ }
+ if ( i == 60 )
+ printf("%u timed out waiting for opid to finish\n",origid);
+ }
+ else
+ {
+ if ( strcmp(coin->coin,"KMD") != 0 )
+ {
+ acname = coin->coin;
+ coinstr = "";
+ } else coinstr = coin->coin;
+ if ( coin->istoken != 0 )
+ txid = tokentransfer(coinstr,acname,coin->tokenid,destpub,paytoshis/SATOSHIDEN);
+ else if ( coin->isexternal == 0 )
+ {
+ sprintf(opretstr,"%08x",origid);
+ txid = sendtoaddress(coinstr,acname,destaddr,paytoshis,opretstr);
+ } else txid = _subatomic_sendtoaddress(coin,destaddr,paytoshis);
+ printf("%u got txid.%s\n",origid,bits256_str(str,txid));
+ }
+ return(txid);
+}
+
+cJSON *subatomic_txidwait(struct coininfo *coin,bits256 txid,char *hexstr,int32_t numseconds,char *senderpub)
+{
+ int32_t i,zflag; char *coinstr,str[65],*acname=""; cJSON *rawtx; bits256 z; bits256 filehash;
+ memset(&z,0,sizeof(z));
+ if ( memcmp(&z,&txid,sizeof(txid)) == 0 )
+ return(0);
+ if ( hexstr != 0 && hexstr[0] != 0 ) // probably not worth doing and zaddr is a problem to decode
+ {
+ // compare against txid
+ // if matches, sendrawtransaction if OTC mode, decoode and return if channels mode
+ }
+ zflag = (subatomic_zonly(coin) != 0);
+ if ( strcmp(coin->coin,"KMD") != 0 )
+ {
+ acname = coin->coin;
+ coinstr = "";
+ } else coinstr = coin->coin;
+ for (i=0; iisfile != 0 )
+ {
+ if ( (rawtx= dpow_subscribe(SUBATOMIC_PRIORITY,coin->coin+1,senderpub)) != 0 )
+ {
+ filehash = jbits256(rawtx,"filehash");
+ if ( memcmp(&filehash,&txid,sizeof(filehash)) != 0 )
+ {
+ fprintf(stderr,"waiting (%s) (%s)\n",coin->coin+1,jprint(rawtx,0));
+ free_json(rawtx);
+ rawtx = 0;
+ } else return(rawtx);
+ }
+ }
+ else if ( zflag != 0 )
+ rawtx = get_z_viewtransaction(coinstr,acname,txid);
+ else if ( coin->isexternal == 0 )
+ rawtx = get_rawtransaction(coinstr,acname,txid);
+ else rawtx = _subatomic_rawtransaction(coin,txid);
+ if ( rawtx != 0 )
+ return(rawtx);
+ sleep(1);
+ }
+ printf("%s/%s timeout waiting for %s\n",coin->name,coin->coin,bits256_str(str,txid));
+ return(0);
+}
+
+int64_t subatomic_verifypayment(struct coininfo *coin,cJSON *rawtx,uint64_t destsatoshis,char *destaddr,bits256 txid)
+{
+ int32_t i,n,m,valid=0; bits256 tokenid,filehash,checkhash; cJSON *array,*item,*sobj,*a; char *addr,*acname,*coinstr,tokenaddr[64],*hex; uint8_t hexbuf[512],pub33[33]; uint64_t netval,recvsatoshis = 0;
+ if ( coin->isfile != 0 )
+ {
+ filehash = jbits256(rawtx,"filehash");
+ checkhash = jbits256(rawtx,"checkhash");
+ if ( memcmp(&txid,&filehash,sizeof(txid)) == 0 && memcmp(&txid,&checkhash,sizeof(txid)) == 0 )
+ {
+ fprintf(stderr,"verified file is matching the filehash (%s)\n",jprint(rawtx,0));
+ return(SATOSHIDEN);
+ } else return(0);
+ }
+ else if ( subatomic_zonly(coin) != 0 )
+ {
+ if ( (array= jarray(&n,rawtx,"outputs")) != 0 && n > 0 )
+ {
+ for (i=0; iistoken != 0 )
+ {
+ if ( (array= jarray(&n,rawtx,"vout")) != 0 && n > 0 )
+ {
+ item = jitem(array,0);
+ if ( (sobj= jobj(item,"scriptPubKey")) != 0 && (a= jarray(&m,sobj,"addresses")) != 0 && m == 1 )
+ {
+ if ( strcmp(coin->coin,"KMD") != 0 )
+ {
+ acname = coin->coin;
+ coinstr = "";
+ } else coinstr = coin->coin;
+ if ( get_tokenaddress(coinstr,acname,tokenaddr) != 0 )
+ {
+ //fprintf(stderr,"tokenaddr.%s\n",tokenaddr);
+ if ( (addr= jstri(a,0)) != 0 && strcmp(addr,tokenaddr) == 0 )
+ recvsatoshis += SATOSHIDEN * (uint64_t)(jdouble(item,"value")*SATOSHIDEN + 0.000000004999);
+ else fprintf(stderr,"miscompare (%s) vs %s\n",jprint(sobj,0),addr);
+ }
+ }
+ item = jitem(array,n-1);
+ if ( (sobj= jobj(item,"scriptPubKey")) != 0 && (hex= jstr(sobj,"hex")) != 0 && (m= is_hexstr(hex,0)) > 1 && m/2 < sizeof(hexbuf) )
+ {
+ m >>= 1;
+ decode_hex(hexbuf,m,hex);
+ decode_hex(tokenid.bytes,32,coin->tokenid);
+ decode_hex(pub33,33,DPOW_secpkeystr);
+ // opret 69len EVAL_TOKENS 't' tokenid 1 33 pub33
+ if ( hexbuf[0] == 0x6a && hexbuf[1] == 0x45 && hexbuf[2] == 0xf2 && hexbuf[3] == 't' && memcmp(&hexbuf[4],&tokenid,sizeof(tokenid)) == 0 && hexbuf[4+32] == 1 && hexbuf[4+32+1] == 33 && memcmp(&hexbuf[4+32+2],pub33,33) == 0 )
+ {
+ valid = 1;
+ //fprintf(stderr,"validated it is a token transfer!\n");
+ } else fprintf(stderr,"need to validate tokentransfer.(%s) %s %d\n",hex,DPOW_secpkeystr,memcmp(&hexbuf[4+32+2],pub33,33) == 0);
+ //6a 45 f2 74 2b1feef719ecb526b07416dd432bce603ac6dc8bfe794cddf105cb52f6aae3cd 01 21 02b27de3ee5335518b06f69f4fbabb029cfc737613b100996841d5532b324a5a61
+
+ }
+ recvsatoshis *= valid;
+ }
+ }
+ else
+ {
+ if ( (array= jarray(&n,rawtx,"vout")) != 0 && n > 0 )
+ {
+ for (i=0; iorigid = origid;
+ HASH_ADD(hh,Messages,origid,sizeof(origid),mp);
+ return(mp);
+}
+
+int32_t subatomic_status(struct msginfo *mp,int32_t status)
+{
+ static FILE *fp;
+ if ( fp == 0 )
+ {
+ int32_t i,oid,s,n,num,count; struct msginfo *m; long fsize;
+ if ( (fp= fopen("SUBATOMIC.DB","rb+")) == 0 )
+ {
+ if ( (fp= fopen("SUBATOMIC.DB","wb")) == 0 )
+ {
+ fprintf(stderr,"cant create SUBATOMIC.DB\n");
+ exit(-1);
+ }
+ }
+ else
+ {
+ fseek(fp,0,SEEK_END);
+ fsize = ftell(fp);
+ if ( (fsize % (sizeof(uint32_t)*2)) != 0 )
+ {
+ fprintf(stderr,"SUBATOMIC.DB illegal filesize.%ld\n",fsize);
+ exit(-1);
+ }
+ n = (int32_t)(fsize / (sizeof(uint32_t)*2));
+ rewind(fp);
+ for (i=num=count=0; i SUBATOMIC_CLOSED )
+ {
+ fprintf(stderr,"SUBATOMIC.DB corrupted at filepos.%ld: illegal status.%d\n",ftell(fp),s);
+ exit(-1);
+ }
+ //fprintf(stderr,"%u <- %d\n",oid,s);
+ if ( (m= subatomic_find(oid)) == 0 )
+ {
+ m = subatomic_add(oid);
+ count++;
+ }
+ if ( s > m->status )
+ {
+ m->status = s;
+ num++;
+ }
+ }
+ fprintf(stderr,"initialized %d messages, updated %d out of total.%d\n",count,num,n);
+ }
+ }
+ if ( mp->status >= status )
+ return(-1);
+ if ( fwrite(&mp->origid,1,sizeof(mp->origid),fp) != sizeof(mp->origid) || fwrite(&status,1,sizeof(status),fp) != sizeof(status) )
+ fprintf(stderr,"error updating SUBATOMIC.DB, risk of double spends\n");
+ fflush(fp);
+ mp->status = status;
+ return(0);
+}
+
+struct msginfo *subatomic_tracker(uint32_t origid)
+{
+ struct msginfo *mp;
+ if ( (mp= subatomic_find(origid)) == 0 )
+ {
+ mp = subatomic_add(origid);
+ subatomic_status(mp,0);
+ }
+ return(mp);
+}
+
+char *subatomic_hexstr(char *jsonstr)
+{
+ char *hexstr; int32_t i,c,n = (int32_t)strlen(jsonstr);
+ hexstr = malloc(2*n + 3);
+ strcpy(hexstr,jsonstr);
+ for (i=0; iorigid);
+ jaddnum(item,"price",mp->price);
+ jaddnum(item,"openrequest",mp->openrequestid);
+ jaddstr(item,"base",mp->base.name);
+ jaddstr(item,"basecoin",mp->base.coin);
+ jadd64bits(item,"basesatoshis",mp->base.satoshis);
+ jadd64bits(item,"basetxfee",mp->base.txfee);
+ jadd64bits(item,"maxbaseamount",mp->base.maxamount);
+ jaddstr(item,"rel",mp->rel.name);
+ jaddstr(item,"relcoin",mp->rel.coin);
+ jadd64bits(item,"relsatoshis",mp->rel.satoshis);
+ jadd64bits(item,"reltxfee",mp->rel.txfee);
+ jadd64bits(item,"maxrelamount",mp->rel.maxamount);
+ jaddstr(item,"alice",mp->alice.pubkey);
+ jaddstr(item,"alicesecp",mp->alice.secp);
+ jaddstr(item,"bob",mp->bob.pubkey);
+ jaddstr(item,"bobsecp",mp->bob.secp);
+ if ( subatomic_zonly(&mp->rel) != 0 )
+ jaddstr(item,"bobZaddr",mp->bob.recvZaddr);
+ else jaddstr(item,"bobaddr",mp->bob.recvaddr);
+ if ( mp->rel.istoken != 0 )
+ jaddstr(item,"bobtoken",mp->rel.tokenid);
+ if ( subatomic_zonly(&mp->base) != 0 )
+ jaddstr(item,"aliceZaddr",mp->alice.recvZaddr);
+ else jaddstr(item,"aliceaddr",mp->alice.recvaddr);
+ if ( mp->base.istoken != 0 )
+ jaddstr(item,"alicetoken",mp->base.tokenid);
+ return(item);
+}
+
+uint64_t subatomic_orderbook_mpset(struct msginfo *mp,char *basecheck)
+{
+ cJSON *retjson; char *tagA,*tagB,*senderpub,*str,tmpstr[32]; int32_t matches=0; double volA,volB; int64_t txfee=0;
+ strcpy(mp->base.name,basecheck);
+ strcpy(mp->base.coin,subatomic_checkname(tmpstr,mp,0,basecheck));
+ mp->rel.txfee = subatomic_txfee(mp->rel.coin);
+ if ( (retjson= dpow_get(mp->origid)) != 0 )
+ {
+ //fprintf(stderr,"dpow_get.(%s) (%s/%s)\n",jprint(retjson,0),mp->base.coin,mp->rel.coin);
+ if ( (senderpub= jstr(retjson,"senderpub")) != 0 && is_hexstr(senderpub,0) == 66 && (tagA= jstr(retjson,"tagA")) != 0 && (tagB= jstr(retjson,"tagB")) != 0 && strncmp(tagB,mp->rel.name,strlen(mp->rel.name)) == 0 && strlen(tagA) < sizeof(mp->base.name) )
+ {
+ strcpy(mp->base.name,tagA);
+ strcpy(mp->base.coin,subatomic_checkname(tmpstr,mp,0,tagA));
+ if ( basecheck[0] == 0 || strncmp(basecheck,tagA,strlen(basecheck)) == 0 )
+ matches = 1;
+ else if ( strcmp(tagA,mp->base.name) == 0 )
+ matches = 1;
+ else if ( mp->bobflag != 0 && tagA[0] == '#' && strcmp(mp->base.name,"#allfiles") == 0 )
+ matches = 1;
+ if ( matches != 0 )
+ {
+ if ( (str= jstr(retjson,"decrypted")) != 0 && strlen(str) < 128 )
+ strcpy(mp->payload,str);
+ mp->locktime = juint(retjson,"timestamp") + SUBATOMIC_LOCKTIME;
+ mp->base.txfee = subatomic_txfee(mp->base.coin);
+ strcpy(mp->senderpub,senderpub);
+ volB = jdouble(retjson,"amountB");
+ volA = jdouble(retjson,"amountA");
+ mp->base.maxamount = volA*SATOSHIDEN + 0.0000000049999;
+ mp->rel.maxamount = volB*SATOSHIDEN + 0.0000000049999;
+ if ( 0 && mp->rel.istoken == 0 )
+ txfee = mp->rel.txfee;
+ if ( mp->base.maxamount != 0 && mp->rel.maxamount != 0 && volA > SMALLVAL && volB > SMALLVAL && mp->rel.satoshis <= mp->rel.maxamount )
+ {
+ mp->price = volA / volB;
+ mp->base.satoshis = (mp->rel.satoshis - txfee) * mp->price;
+ //fprintf(stderr,"base satoshis.%llu\n",(long long)mp->base.satoshis);
+ } else fprintf(stderr,"%u rel %llu vs (%llu %llu)\n",mp->origid,(long long)mp->rel.satoshis,(long long)mp->base.maxamount,(long long)mp->rel.maxamount);
+ } else printf("%u didnt match (%s) tagA.%s %s, tagB.%s %s %d %d\n",mp->origid,basecheck,tagA,mp->base.name,tagB,mp->rel.name,tagA[0] == '#', strcmp(mp->base.name,"#allfiles") == 0);
+ } else printf("%u didnt compare tagA.%s %s, tagB.%s %s\n",mp->origid,tagA,mp->base.name,tagB,mp->rel.name);
+ free_json(retjson);
+ }
+ return(mp->base.satoshis);
+}
+
+char *randhashstr(char *str)
+{
+ bits256 rands; int32_t i;
+ for (i=0; i<32; i++)
+ rands.bytes[i] = rand() >> 17;
+ bits256_str(str,rands);
+ return(str);
+}
+
+void subatomic_extrafields(cJSON *dest,cJSON *src)
+{
+ char *str;
+ if ( (str= jstr(src,"approval")) != 0 )
+ jaddstr(dest,"approval",str);
+ if ( (str= jstr(src,"opened")) != 0 )
+ jaddstr(dest,"opened",str);
+ if ( (str= jstr(src,"payamount")) != 0 )
+ jaddstr(dest,"payamount",str);
+ if ( (str= jstr(src,"destaddr")) != 0 )
+ jaddstr(dest,"destaddr",str);
+ if ( (str= jstr(src,"bobpayment")) != 0 )
+ jaddstr(dest,"bobpayment",str);
+ if ( (str= jstr(src,"alicepayment")) != 0 )
+ jaddstr(dest,"alicepayment",str);
+ if ( (str= jstr(src,"bobaddr")) != 0 )
+ jaddstr(dest,"bobaddr",str);
+ if ( (str= jstr(src,"bobZaddr")) != 0 )
+ jaddstr(dest,"bobZaddr",str);
+ if ( (str= jstr(src,"aliceaddr")) != 0 )
+ jaddstr(dest,"aliceaddr",str);
+ if ( (str= jstr(src,"aliceZaddr")) != 0 )
+ jaddstr(dest,"aliceZaddr",str);
+ if ( (str= jstr(src,"alicetoken")) != 0 )
+ jaddstr(dest,"alicetoken",str);
+ if ( (str= jstr(src,"bobtoken")) != 0 )
+ jaddstr(dest,"bobtoken",str);
+}
+
+char *subatomic_submit(cJSON *argjson,int32_t tobob)
+{
+ char *jsonstr,*hexstr;
+ jaddnum(argjson,"tobob",tobob != 0);
+ jsonstr = jprint(argjson,1);
+ hexstr = subatomic_hexstr(jsonstr);
+ free(jsonstr);
+ return(hexstr);
+}
+
+#define SCRIPT_OP_IF 0x63
+#define SCRIPT_OP_ELSE 0x67
+#define SCRIPT_OP_DUP 0x76
+#define SCRIPT_OP_ENDIF 0x68
+#define SCRIPT_OP_TRUE 0x51
+#define SCRIPT_OP_2 0x52
+#define SCRIPT_OP_3 0x53
+#define SCRIPT_OP_DROP 0x75
+#define SCRIPT_OP_EQUALVERIFY 0x88
+#define SCRIPT_OP_HASH160 0xa9
+#define SCRIPT_OP_EQUAL 0x87
+#define SCRIPT_OP_CHECKSIG 0xac
+#define SCRIPT_OP_CHECKMULTISIG 0xae
+#define SCRIPT_OP_CHECKMULTISIGVERIFY 0xaf
+#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1
+
+int32_t subatomic_redeemscript(char *redeemscript,uint32_t locktime,char *pubkeyA,char *pubkeyB) // not needed
+{
+ // if ( refund ) OP_HASH160 <2of2 multisig hash> OP_EQUAL // standard multisig
+ // else CLTV OP_DROP OP_CHECKSIG // standard spend
+ uint8_t pubkeyAbytes[33],pubkeyBbytes[33],hex[4096]; int32_t i,n = 0;
+ decode_hex(pubkeyAbytes,33,pubkeyA);
+ decode_hex(pubkeyBbytes,33,pubkeyB);
+ hex[n++] = SCRIPT_OP_IF;
+ hex[n++] = SCRIPT_OP_2;
+ hex[n++] = 33, memcpy(&hex[n],pubkeyAbytes,33), n += 33;
+ hex[n++] = 33, memcpy(&hex[n],pubkeyBbytes,33), n += 33;
+ hex[n++] = SCRIPT_OP_2;
+ hex[n++] = SCRIPT_OP_CHECKMULTISIG;
+ hex[n++] = SCRIPT_OP_ELSE;
+ hex[n++] = 4;
+ hex[n++] = locktime & 0xff, locktime >>= 8;
+ hex[n++] = locktime & 0xff, locktime >>= 8;
+ hex[n++] = locktime & 0xff, locktime >>= 8;
+ hex[n++] = locktime & 0xff;
+ hex[n++] = SCRIPT_OP_CHECKLOCKTIMEVERIFY;
+ hex[n++] = SCRIPT_OP_DROP;
+ hex[n++] = 33; memcpy(&hex[n],pubkeyAbytes,33); n += 33;
+ hex[n++] = SCRIPT_OP_CHECKSIG;
+ hex[n++] = SCRIPT_OP_ENDIF;
+ for (i=0; i>4) & 0xf);
+ redeemscript[i*2 + 1] = hexbyte(hex[i] & 0xf);
+ }
+ redeemscript[n*2] = 0;
+ /*tmpbuf[0] = SCRIPT_OP_HASH160;
+ tmpbuf[1] = 20;
+ calc_OP_HASH160(scriptPubKey,tmpbuf+2,redeemscript);
+ tmpbuf[22] = SCRIPT_OP_EQUAL;
+ init_hexbytes_noT(scriptPubKey,tmpbuf,23);
+ if ( p2shaddr != 0 )
+ {
+ p2shaddr[0] = 0;
+ if ( (btc_addr= base58_encode_check(addrtype,true,tmpbuf+2,20)) != 0 )
+ {
+ if ( strlen(btc_addr->str) < 36 )
+ strcpy(p2shaddr,btc_addr->str);
+ cstr_free(btc_addr,true);
+ }
+ }*/
+ return(n);
+}
+
+int32_t subatomic_approved(struct msginfo *mp,cJSON *approval,cJSON *msgjson,char *senderpub)
+{
+ char *hexstr,numstr[32],redeemscript[1024],*coin,*acname=""; cJSON *retjson,*decodejson; int32_t i,retval = 0;
+ subatomic_extrafields(approval,msgjson);
+ if ( mp->OTCmode == 0 )
+ {
+ coin = (mp->bobflag != 0) ? mp->base.coin : mp->rel.coin; // the other side gets this coin
+ if ( strcmp(coin,"KMD") != 0 )
+ {
+ acname = coin;
+ coin = "";
+ }
+ if ( get_createmultisig2(coin,acname,mp->msigaddr,mp->redeemscript,mp->alice.secp,mp->bob.secp) != 0 )
+ {
+ subatomic_redeemscript(redeemscript,mp->locktime,mp->alice.secp,mp->bob.secp);
+ if ( (decodejson= get_decodescript(coin,acname,redeemscript)) != 0 )
+ {
+ fprintf(stderr,"%s %s msigaddr.%s %s -> %s %s\n",mp->bobflag!=0?"bob":"alice",(mp->bobflag != 0) ? mp->base.coin : mp->rel.coin,mp->msigaddr,mp->redeemscript,redeemscript,jprint(decodejson,0));
+ free(decodejson);
+ }
+ }
+ }
+ sprintf(numstr,"%u",mp->origid);
+ for (i=0; numstr[i]!=0; i++)
+ sprintf(&mp->approval[i<<1],"%02x",numstr[i]);
+ sprintf(&mp->approval[i<<1],"%02x",' ');
+ i++;
+ mp->approval[i<<1] = 0;
+ jaddstr(approval,"approval",mp->approval);
+ hexstr = subatomic_submit(approval,!mp->bobflag);
+ if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"approved",senderpub,"","")) != 0 )
+ {
+ if ( (mp->approvalid= juint(retjson,"id")) != 0 )
+ retval = 1;
+ printf("%u approvalid.%u (%s)\n",mp->origid,mp->approvalid,senderpub);
+ subatomic_status(mp,SUBATOMIC_APPROVED);
+ free_json(retjson);
+ }
+ free(hexstr);
+ return(retval);
+}
+
+int32_t subatomic_opened(struct msginfo *mp,cJSON *opened,cJSON *msgjson,char *senderpub)
+{
+ char *hexstr,channelstr[65]; cJSON *retjson; int32_t retval = 0;
+ subatomic_extrafields(opened,msgjson);
+ jaddstr(opened,"opened",randhashstr(channelstr));
+ hexstr = subatomic_submit(opened,!mp->bobflag);
+ if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"opened",senderpub,"","")) != 0 )
+ {
+ if ( (mp->openedid= juint(retjson,"id")) != 0 )
+ retval = 1;
+ printf("%u openedid.%u\n",mp->origid,mp->openedid);
+ subatomic_status(mp,SUBATOMIC_OPENED);
+ free_json(retjson);
+ }
+ free(hexstr);
+ return(retval);
+}
+
+int32_t subatomic_payment(struct msginfo *mp,cJSON *payment,cJSON *msgjson,char *senderpub)
+{
+ bits256 txid; uint64_t paytoshis; cJSON *retjson; char numstr[32],*coin,*dest,*hexstr; int32_t retval = 0;
+ if ( mp->bobflag == 0 )
+ {
+ coin = mp->rel.name;
+ paytoshis = mp->rel.satoshis;
+ if ( subatomic_zonly(&mp->rel) != 0 )
+ dest = mp->bob.recvZaddr;
+ else dest = mp->bob.recvaddr;
+ sprintf(numstr,"%llu",(long long)paytoshis);
+ jaddstr(payment,"alicepays",numstr);
+ jaddstr(payment,"bobdestaddr",dest);
+ txid = subatomic_coinpayment(mp->origid,mp->OTCmode,&mp->rel,dest,paytoshis,mp->approval,mp->bob.secp,senderpub);
+ jaddbits256(payment,"alicepayment",txid);
+ mp->alicepayment = txid;
+ hexstr = 0; // get it from rawtransaction of txid
+ jaddstr(payment,"alicetx",hexstr);
+ }
+ else
+ {
+ coin = mp->base.name;
+ paytoshis = mp->base.satoshis;
+ if ( subatomic_zonly(&mp->base) != 0 )
+ dest = mp->alice.recvZaddr;
+ else dest = mp->alice.recvaddr;
+ sprintf(numstr,"%llu",(long long)paytoshis);
+ jaddstr(payment,"bobpays",numstr);
+ jaddstr(payment,"alicedestaddr",dest);
+ txid = subatomic_coinpayment(mp->origid,mp->OTCmode,&mp->base,dest,paytoshis,mp->approval,mp->alice.secp,senderpub);
+ jaddbits256(payment,"bobpayment",txid);
+ mp->bobpayment = txid;
+ hexstr = 0; // get it from rawtransaction of txid
+ jaddstr(payment,"bobtx",hexstr);
+ }
+ hexstr = subatomic_submit(payment,!mp->bobflag);
+ if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"payment",senderpub,"","")) != 0 )
+ {
+ if ( (mp->paymentids[0]= juint(retjson,"id")) != 0 )
+ retval = 1;
+ printf("%u: %.8f %s -> %s, paymentid[0] %u\n",mp->origid,dstr(paytoshis),coin,dest,mp->paymentids[0]);
+ subatomic_status(mp,SUBATOMIC_PAYMENT);
+ free_json(retjson);
+ }
+ free(hexstr);
+ return(retval);
+}
+
+int32_t subatomic_paidinfull(struct msginfo *mp,cJSON *paid,cJSON *msgjson,char *senderpub)
+{
+ char *hexstr; cJSON *retjson; int32_t retval = 0;
+ jaddstr(paid,"paid","in full");
+ subatomic_extrafields(paid,msgjson);
+ hexstr = subatomic_submit(paid,!mp->bobflag);
+ if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"paid",senderpub,"","")) != 0 )
+ {
+ if ( (mp->paidid= juint(retjson,"id")) != 0 )
+ retval = 1;
+ printf("%u paidid.%u\n",mp->origid,mp->paidid);
+ subatomic_status(mp,SUBATOMIC_PAIDINFULL);
+ free_json(retjson);
+ }
+ free(hexstr);
+ return(retval);
+}
+
+int32_t subatomic_closed(struct msginfo *mp,cJSON *closed,cJSON *msgjson,char *senderpub)
+{
+ char *hexstr; cJSON *retjson; int32_t retval = 0;
+ jaddnum(closed,"closed",mp->origid);
+ subatomic_extrafields(closed,msgjson);
+ hexstr = subatomic_submit(closed,!mp->bobflag);
+ if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"closed",senderpub,"","")) != 0 )
+ {
+ if ( (mp->closedid= juint(retjson,"id")) != 0 )
+ retval = 1;
+ subatomic_status(mp,SUBATOMIC_CLOSED);
+ printf("%u closedid.%u\n",mp->origid,mp->closedid);
+ free_json(retjson);
+ }
+ free(hexstr);
+ return(retval);
+}
+
+uint32_t subatomic_alice_openrequest(struct msginfo *origmp)
+{
+ struct msginfo *mp; cJSON *retjson,*openrequest; char *hexstr,*str,tmpstr[32];
+ mp = subatomic_tracker(origmp->origid);
+ mp->origid = origmp->origid;
+ mp->rel.satoshis = origmp->rel.satoshis;
+ mp->rel.istoken = origmp->rel.istoken;
+ strcpy(mp->rel.tokenid,origmp->rel.tokenid);
+ strcpy(mp->rel.name,origmp->rel.name);
+ strcpy(mp->rel.coin,subatomic_checkname(tmpstr,mp,1,origmp->rel.name));
+ strcpy(mp->alice.pubkey,DPOW_pubkeystr);
+ strcpy(mp->alice.secp,DPOW_secpkeystr);
+ strcpy(mp->alice.recvZaddr,DPOW_recvZaddr);
+ strcpy(mp->alice.recvaddr,DPOW_recvaddr);
+ printf("rel.%s/%s %s openrequest %u status.%d (%s/%s)\n",mp->rel.name,mp->rel.coin,mp->rel.tokenid,mp->origid,mp->status,mp->alice.recvaddr,mp->alice.recvZaddr);
+ if ( mp->status == 0 && subatomic_orderbook_mpset(mp,"") != 0 )
+ {
+ strcpy(mp->bob.pubkey,mp->senderpub);
+ if ( subatomic_zonly(&mp->base) != 0 || subatomic_zonly(&mp->rel) != 0 )
+ mp->OTCmode = 1;
+ else mp->OTCmode = SUBATOMIC_OTCDEFAULT;
+ strcpy(origmp->base.name,mp->base.name);
+ strcpy(origmp->base.coin,mp->base.coin);
+ origmp->base.istoken = mp->base.istoken;
+ strcpy(origmp->base.tokenid,mp->base.tokenid);
+ origmp->OTCmode = mp->OTCmode;
+ if ( mp->rel.istoken != 0 && ((mp->rel.satoshis % SATOSHIDEN) != 0 || mp->rel.iszaddr != 0) )
+ {
+ printf("%u cant do zaddr or fractional rel %s.%s tokens %.8f\n",mp->origid,mp->rel.coin,mp->rel.tokenid,dstr(mp->rel.satoshis));
+ return(0);
+ }
+ else if ( mp->base.istoken != 0 && ((mp->base.satoshis % SATOSHIDEN) != 0 || mp->base.iszaddr != 0 ) )
+ {
+ printf("%u cant do zaddr or fractional base %s.%s tokens %.8f\n",mp->origid,mp->base.coin,mp->base.tokenid,dstr(mp->base.satoshis));
+ return(0);
+ }
+ else if ( (openrequest= subatomic_mpjson(mp)) != 0 )
+ {
+ hexstr = subatomic_submit(openrequest,!mp->bobflag);
+ if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"openrequest",mp->bob.pubkey,"","")) != 0 )
+ {
+ mp->openrequestid = juint(retjson,"id");
+ printf("%u openrequest.%u -> (%s)\n",mp->origid,mp->openrequestid,mp->bob.pubkey);
+ subatomic_status(mp,SUBATOMIC_OPENREQUEST);
+ free_json(retjson);
+ }
+ free(hexstr);
+ }
+ }
+ return(mp->openrequestid);
+}
+
+void subatomic_bob_gotopenrequest(uint32_t inboxid,char *senderpub,cJSON *msgjson,char *basename,char *relname)
+{
+ struct msginfo *mp; cJSON *approval; int32_t origid; char *addr,tmpstr[32],*coin,*acname="";
+ origid = juint(msgjson,"origid");
+ mp = subatomic_tracker(origid);
+ strcpy(mp->base.name,basename);
+ strcpy(mp->base.coin,subatomic_checkname(tmpstr,mp,0,basename));
+ strcpy(mp->rel.name,relname);
+ strcpy(mp->rel.coin,subatomic_checkname(tmpstr,mp,1,relname));
+ mp->origid = origid;
+ mp->rel.satoshis = j64bits(msgjson,"relsatoshis");
+ mp->bobflag = 1;
+ strcpy(mp->bob.pubkey,DPOW_pubkeystr);
+ strcpy(mp->bob.secp,DPOW_secpkeystr);
+ strcpy(mp->bob.recvZaddr,DPOW_recvZaddr);
+ strcpy(mp->bob.recvaddr,DPOW_recvaddr);
+ if ( (addr= jstr(msgjson,"aliceaddr")) != 0 )
+ strcpy(mp->alice.recvaddr,addr);
+ if ( (addr= jstr(msgjson,"aliceZaddr")) != 0 )
+ strcpy(mp->alice.recvZaddr,addr);
+ if ( (addr= jstr(msgjson,"alicesecp")) != 0 )
+ strcpy(mp->alice.secp,addr);
+ if ( subatomic_zonly(&mp->base) != 0 || subatomic_zonly(&mp->rel) != 0 )
+ mp->OTCmode = 1;
+ else mp->OTCmode = SUBATOMIC_OTCDEFAULT;
+ printf("%u got open request\n",mp->origid);
+ if ( mp->status == 0 && subatomic_orderbook_mpset(mp,basename) != 0 && (approval= subatomic_mpjson(mp)) != 0 )
+ {
+ if ( mp->rel.istoken != 0 && ((mp->rel.satoshis % SATOSHIDEN) != 0 || mp->rel.iszaddr != 0) )
+ {
+ printf("%u cant do zaddr or fractional rel %s.%s tokens %.8f\n",mp->origid,mp->rel.coin,mp->rel.tokenid,dstr(mp->rel.satoshis));
+ subatomic_closed(mp,approval,msgjson,senderpub);
+ return;
+ }
+ else if ( mp->base.istoken != 0 && ((mp->base.satoshis % SATOSHIDEN) != 0 || mp->base.iszaddr != 0 ) )
+ {
+ printf("%u cant do zaddr or fractional base %s.%s tokens %.8f\n",mp->origid,mp->base.coin,mp->base.tokenid,dstr(mp->base.satoshis));
+ subatomic_closed(mp,approval,msgjson,senderpub);
+ return;
+ }
+ else if ( subatomic_getbalance(&mp->base) < mp->base.satoshis )
+ {
+ printf("%u bob node low on %s funds! %.8f not enough for %.8f\n",mp->origid,mp->base.coin,dstr(subatomic_getbalance(&mp->base)),dstr(mp->base.satoshis));
+ subatomic_closed(mp,approval,msgjson,senderpub);
+ }
+ else
+ {
+ printf("%u bob (%s/%s) gotopenrequest origid.%u status.%d (%s/%s) SENDERPUB.(%s)\n",mp->origid,mp->base.name,mp->rel.name,mp->origid,mp->status,mp->bob.recvaddr,mp->bob.recvZaddr,senderpub);
+ subatomic_approved(mp,approval,msgjson,senderpub);
+ }
+ }
+}
+
+int32_t subatomic_channelapproved(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp)
+{
+ struct msginfo *mp; cJSON *approval; char *addr,*coin,*acname; int32_t retval = 0;
+ mp = subatomic_tracker(juint(msgjson,"origid"));
+ if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (approval= subatomic_mpjson(mp)) != 0 )
+ {
+ printf("%u iambob.%d (%s/%s) channelapproved origid.%u status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->origid,mp->status);
+ if ( mp->bobflag == 0 && mp->status == SUBATOMIC_OPENREQUEST )
+ {
+ if ( (addr= jstr(msgjson,"bobaddr")) != 0 )
+ strcpy(mp->bob.recvaddr,addr);
+ if ( (addr= jstr(msgjson,"bobZaddr")) != 0 )
+ strcpy(mp->bob.recvZaddr,addr);
+ if ( (addr= jstr(msgjson,"bobsecp")) != 0 )
+ strcpy(mp->bob.secp,addr);
+ retval = subatomic_approved(mp,approval,msgjson,senderpub);
+ }
+ else if ( mp->bobflag != 0 && mp->status == SUBATOMIC_APPROVED )
+ retval = subatomic_opened(mp,approval,msgjson,senderpub);
+ }
+ return(retval);
+}
+
+int32_t subatomic_incomingopened(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp)
+{
+ struct msginfo *mp; cJSON *payment; int32_t retval = 0;
+ mp = subatomic_tracker(juint(msgjson,"origid"));
+ if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (payment= subatomic_mpjson(mp)) != 0 )
+ {
+ printf("%u iambob.%d (%s/%s) incomingchannel status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status);
+ if ( mp->bobflag == 0 && mp->status == SUBATOMIC_APPROVED )
+ retval = subatomic_payment(mp,payment,msgjson,senderpub);
+ else if ( mp->bobflag != 0 && mp->status == SUBATOMIC_OPENED )
+ retval = 1; // nothing to do
+ }
+ return(retval);
+}
+
+int32_t subatomic_incomingpayment(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp)
+{
+ static FILE *fp;
+ struct msginfo *mp; cJSON *pay,*rawtx,*retjson; bits256 txid; char str[65],*hexstr; int32_t retval = 0;
+ mp = subatomic_tracker(juint(msgjson,"origid"));
+ if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (pay= subatomic_mpjson(mp)) != 0 )
+ {
+ printf("%u iambob.%d (%s/%s) incomingpayment status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status);
+ if ( mp->bobflag == 0 )
+ {
+ txid = jbits256(msgjson,"bobpayment");
+ jaddbits256(msgjson,"alicepayment",mp->alicepayment);
+ printf("%u alice waits for %s.%s to be in mempool (%.8f -> %s)\n",mp->origid,mp->base.name,bits256_str(str,txid),dstr(mp->base.satoshis),subatomic_zonly(&mp->base) == 0 ? mp->alice.recvaddr : mp->alice.recvZaddr);
+ hexstr = jstr(msgjson,"bobtx");
+ if ( (rawtx= subatomic_txidwait(&mp->base,txid,hexstr,SUBATOMIC_TIMEOUT,senderpub)) != 0 )
+ {
+ if ( subatomic_verifypayment(&mp->base,rawtx,mp->base.satoshis,subatomic_zonly(&mp->base) == 0 ? mp->alice.recvaddr : mp->alice.recvZaddr,txid) >= 0 )
+ mp->gotpayment = 1;
+ free_json(rawtx);
+ }
+ if ( mp->gotpayment != 0 )
+ {
+ printf("%u SWAP COMPLETE <<<<<<<<<<<<<<<<\n",mp->origid);
+ SUBATOMIC_retval = 0;
+ if ( mp->base.iszaddr == 0 )
+ {
+ sprintf(str,"%u",mp->origid);
+ if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,bits256_str(str,mp->alicepayment),(char *)"completed",str,DPOW_pubkeystr,"","")) != 0 )
+ free_json(retjson);
+ }
+ }
+ else
+ {
+ printf("%u SWAP INCOMPLETE, waiting on %s.%s\n",mp->origid,mp->base.name,bits256_str(str,txid));
+ if ( (fp= fopen("SUBATOMIC.incomplete","a+")) != 0 )
+ {
+ char *jsonstr = jprint(msgjson,0);
+ fwrite(jsonstr,1,strlen(jsonstr),fp);
+ fputc('\n',fp);
+ fclose(fp);
+ free(jsonstr);
+ }
+ if ( mp->base.iszaddr == 0 )
+ {
+ sprintf(str,"%u",mp->origid);
+ if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,bits256_str(str,mp->alicepayment),(char *)"incomplete",str,DPOW_pubkeystr,"","")) != 0 )
+ free_json(retjson);
+ }
+ subatomic_closed(mp,pay,msgjson,senderpub);
+ exit(-1);
+ }
+ }
+ if ( mp->gotpayment != 0 )
+ retval = subatomic_paidinfull(mp,pay,msgjson,senderpub);
+ else
+ {
+ if ( mp->bobflag != 0 && mp->status == SUBATOMIC_OPENED )
+ {
+ txid = jbits256(msgjson,"alicepayment");
+ printf("%u bob waits for %s.%s to be in mempool (%.8f -> %s)\n",mp->origid,mp->rel.name,bits256_str(str,txid),dstr(mp->rel.satoshis),subatomic_zonly(&mp->rel) == 0 ? mp->bob.recvaddr : mp->bob.recvZaddr);
+ hexstr = jstr(msgjson,"alicetx");
+ if ( (rawtx= subatomic_txidwait(&mp->rel,txid,hexstr,SUBATOMIC_TIMEOUT,senderpub)) != 0 )
+ {
+ if ( subatomic_verifypayment(&mp->rel,rawtx,mp->rel.satoshis,subatomic_zonly(&mp->rel) == 0 ? mp->bob.recvaddr : mp->bob.recvZaddr,txid) >= 0 )
+ mp->gotpayment = 1;
+ free_json(rawtx);
+ }
+ if ( mp->gotpayment != 0 )
+ {
+ retval = subatomic_payment(mp,pay,msgjson,senderpub);
+ jaddbits256(msgjson,"bobpayment",mp->bobpayment);
+ if ( mp->rel.iszaddr == 0 )
+ {
+ sprintf(str,"%u",mp->origid);
+ if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,bits256_str(str,mp->bobpayment),(char *)"completed",str,DPOW_pubkeystr,"","")) != 0 )
+ free_json(retjson);
+ }
+ printf("%u SWAP COMPLETE <<<<<<<<<<<<<<<<\n",mp->origid);
+ if ( (fp= fopen("SUBATOMIC.proof","rb+")) == 0 )
+ fp = fopen("SUBATOMIC.proof","wb");
+ if ( fp != 0 )
+ {
+ char *jsonstr = jprint(msgjson,0);
+ fseek(fp,0,SEEK_END);
+ fwrite(jsonstr,1,strlen(jsonstr),fp);
+ fputc('\n',fp);
+ fflush(fp);
+ free(jsonstr);
+ }
+ } else printf("%u SWAP INCOMPLETE: %s\n",mp->origid,jprint(msgjson,0));
+ }
+ }
+ }
+ return(retval);
+}
+
+int32_t subatomic_incomingfullypaid(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp)
+{
+ struct msginfo *mp; cJSON *closed; int32_t retval = 0;
+ mp = subatomic_tracker(juint(msgjson,"origid"));
+ if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (closed= subatomic_mpjson(mp)) != 0 )
+ {
+ printf("%u iambob.%d (%s/%s) incomingfullypaid status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status);
+ // error check msgjson vs M
+ if ( mp->bobflag == 0 && mp->status == SUBATOMIC_PAIDINFULL )
+ retval = subatomic_closed(mp,closed,msgjson,senderpub);
+ else if ( mp->bobflag != 0 && mp->status == SUBATOMIC_PAYMENT )
+ retval = subatomic_paidinfull(mp,closed,msgjson,senderpub);
+ }
+ return(retval);
+}
+
+int32_t subatomic_incomingclosed(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp)
+{
+ struct msginfo *mp; cJSON *closed; int32_t retval = 0;
+ mp = subatomic_tracker(juint(msgjson,"origid"));
+ if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (closed= subatomic_mpjson(mp)) != 0 )
+ {
+ printf("%u iambob.%d (%s/%s) incomingclose status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status);
+ if ( mp->bobflag != 0 )
+ dpow_cancel(mp->origid);
+ if ( mp->status < SUBATOMIC_CLOSED )
+ {
+ retval = subatomic_closed(mp,closed,msgjson,senderpub);
+ subatomic_status(mp,SUBATOMIC_CLOSED);
+ }
+ retval = 1;
+ }
+ return(retval);
+}
+
+int32_t subatomic_ismine(int32_t bobflag,cJSON *json,char *basename,char *relname)
+{
+ char *base,*rel;
+ if ( (base= jstr(json,"base")) != 0 && (rel= jstr(json,"rel")) != 0 )
+ {
+ if ( strcmp(base,basename) == 0 && strcmp(rel,relname) == 0 )
+ return(1);
+ if ( bobflag != 0 )
+ {
+ if ( strcmp(basename,"#allfiles") == 0 && base[0] == '#' )
+ return(1);
+ fprintf(stderr,"skip ismine (%s/%s) vs (%s/%s)\n",basename,relname,base,rel);
+ }
+ }
+ return(0);
+}
+
+void subatomic_tokensregister(int32_t priority)
+{
+ char *token_name,*tokenid,existing[65]; cJSON *tokens,*token; int32_t i,numtokens;
+ if ( SUBATOMIC_json != 0 && (tokens= jarray(&numtokens,SUBATOMIC_json,"tokens")) != 0 )
+ {
+ for (i=0; i 0 )
+ {
+ for (j=0; j %s, %u %llu %u\n",mp->bobflag,mp->base.name,mp->rel.name,mp->origid,(long long)mp->rel.satoshis,mp->openrequestid);
+ while ( 1 )
+ {
+ if ( msgs == 0 )
+ {
+ sleep(1);
+ fflush(stdout);
+ if ( mp->bobflag != 0 )
+ {
+ dpow_pubkeyregister(SUBATOMIC_PRIORITY);
+ subatomic_tokensregister(SUBATOMIC_PRIORITY);
+ subatomic_filesregister(SUBATOMIC_PRIORITY);
+ }
+ }
+ msgs = 0;
+ for (iter=0; iter<(int32_t)(sizeof(tagBs)/sizeof(*tagBs)); iter++)
+ {
+ tagB = tagBs[iter];
+ if ( (ptrs= dpow_inboxcheck(&n,&stopats[iter],tagB)) != 0 )
+ {
+ for (i=0; ijsonstr)) != 0 )
+ {
+ if ( jint(inboxjson,"tobob") != mp->bobflag )
+ continue;
+ if ( subatomic_ismine(mp->bobflag,inboxjson,mp->base.name,mp->rel.name) != 0 )
+ {
+ if ( strcmp(tagB,"openrequest") == 0 && mp->bobflag != 0 )
+ subatomic_bob_gotopenrequest(ptr->shorthash,ptr->senderpub,inboxjson,mp->base.name,mp->rel.name);
+ else if ( strcmp(tagB,"approved") == 0 )
+ mask |= subatomic_channelapproved(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 0;
+ else if ( strcmp(tagB,"opened") == 0 )
+ mask |= subatomic_incomingopened(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 1;
+ else if ( strcmp(tagB,"payment") == 0 )
+ mask |= subatomic_incomingpayment(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 2;
+ else if ( strcmp(tagB,"paid") == 0 )
+ mask |= subatomic_incomingfullypaid(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 3;
+ else if ( strcmp(tagB,"closed") == 0 )
+ mask |= subatomic_incomingclosed(ptr->shorthash,ptr->senderpub,inboxjson,mp) * 0x1f;
+ else fprintf(stderr,"iambob.%d unknown unexpected tagB.(%s)\n",mp->bobflag,tagB);
+ }
+ free_json(inboxjson);
+ } else fprintf(stderr,"subatomic iambob.%d loop got unparseable(%s)\n",mp->bobflag,ptr->jsonstr);
+ free(ptr);
+ ptrs[i] = 0;
+ }
+ }
+ free(ptrs);
+ }
+ }
+ if ( mp->bobflag == 0 && (mask & 0x1f) == 0x1f )
+ {
+ printf("alice %u %llu %u finished\n",mp->origid,(long long)mp->rel.satoshis,mp->openrequestid);
+ break;
+ }
+ }
+}
+
+int32_t main(int32_t argc,char **argv)
+{
+ char *fname = "subatomic.json";
+ int32_t i,height; char *coin,*kcli,*subatomic,*hashstr,*acname=(char *)""; cJSON *retjson; bits256 blockhash; char checkstr[65],str[65],str2[65],tmpstr[32]; long fsize; struct msginfo M;
+ memset(&M,0,sizeof(M));
+ srand((int32_t)time(NULL));
+ if ( (subatomic= filestr(&fsize,fname)) == 0 )
+ {
+ fprintf(stderr,"cant load %s file\n",fname);
+ exit(-1);
+ }
+ if ( (SUBATOMIC_json= cJSON_Parse(subatomic)) == 0 )
+ {
+ fprintf(stderr,"cant parse subatomic.json file (%s)\n",subatomic);
+ exit(-1);
+ }
+ free(subatomic);
+ if ( argc >= 4 )
+ {
+ if ( dpow_pubkey() < 0 )
+ {
+ fprintf(stderr,"couldnt set pubkey for DEX\n");
+ return(-1);
+ }
+ coin = (char *)argv[1];
+ if ( argv[2][0] != 0 )
+ REFCOIN_CLI = (char *)argv[2];
+ else
+ {
+ if ( strcmp(coin,"KMD") != 0 )
+ {
+ acname = coin;
+ }
+ }
+ hashstr = (char *)argv[3];
+ strcpy(M.rel.coin,subatomic_checkname(tmpstr,&M,1,coin));
+ strcpy(M.rel.name,coin);
+ if ( argc == 4 && strlen(hashstr) == 64 ) // for blocknotify usage, seems not needed
+ {
+ height = get_coinheight(coin,acname,&blockhash);
+ bits256_str(checkstr,blockhash);
+ if ( strcmp(checkstr,hashstr) == 0 )
+ {
+ fprintf(stderr,"%s: (%s) %s height.%d\n",coin,REFCOIN_CLI!=0?REFCOIN_CLI:"",checkstr,height);
+ if ( (retjson= dpow_ntzdata(coin,SUBATOMIC_PRIORITY,height,blockhash)) != 0 )
+ free_json(retjson);
+ } else fprintf(stderr,"coin.%s (%s) %s vs %s, height.%d\n",coin,REFCOIN_CLI!=0?REFCOIN_CLI:"",checkstr,hashstr,height);
+ if ( strcmp("BTC",coin) != 0 )
+ {
+ bits256 prevntzhash,ntzhash; int32_t prevntzheight,ntzheight; uint32_t ntztime,prevntztime; char hexstr[81]; cJSON *retjson2;
+ prevntzhash = dpow_ntzhash(coin,&prevntzheight,&prevntztime);
+ if ( (retjson= get_getinfo(coin,acname)) != 0 )
+ {
+ ntzheight = juint(retjson,"notarized");
+ ntzhash = jbits256(retjson,"notarizedhash");
+ if ( ntzheight > prevntzheight )
+ {
+ get_coinmerkleroot(coin,acname,ntzhash,&ntztime);
+ fprintf(stderr,"NOTARIZATION %s.%d %s t.%u\n",coin,ntzheight,bits256_str(str,ntzhash),ntztime);
+ bits256_str(hexstr,ntzhash);
+ sprintf(&hexstr[64],"%08x",ntzheight);
+ sprintf(&hexstr[72],"%08x",ntztime);
+ hexstr[80] = 0;
+ if ( (retjson2= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,coin,"notarizations",DPOW_pubkeystr,"","")) != 0 )
+ free_json(retjson2);
+ }
+ else if ( ntzheight == prevntzheight && memcmp(&prevntzhash,&ntzhash,32) != 0 )
+ fprintf(stderr,"NTZ ERROR %s.%d %s != %s\n",coin,ntzheight,bits256_str(str,ntzhash),bits256_str(str2,prevntzhash));
+ free_json(retjson);
+ }
+ }
+ }
+ else if ( argc == 5 && atol(hashstr) > 10000 )
+ {
+ char checkstr[32]; uint64_t mult = 1;
+ M.origid = (uint32_t)atol(hashstr);
+ sprintf(checkstr,"%u",M.origid);
+ if ( strcmp(checkstr,hashstr) == 0 ) // alice
+ {
+ M.rel.satoshis = (uint64_t)(atof(argv[4])*SATOSHIDEN+0.0000000049999);
+ for (i=0; M.rel.name[i]!=0; i++)
+ if ( M.rel.name[i] == '.' )
+ {
+ mult = SATOSHIDEN;
+ break;
+ }
+ if ( subatomic_getbalance(&M.rel) < M.rel.satoshis/mult )
+ {
+ fprintf(stderr,"not enough balance %s %.8f for %.8f\n",M.rel.coin,dstr(subatomic_getbalance(&M.rel)),dstr(M.rel.satoshis/mult));
+ return(-1);
+ }
+ fprintf(stderr,"subatomic_channel_alice (%s/%s) %s %u with %.8f %llu\n",M.rel.name,M.rel.coin,hashstr,M.origid,atof(argv[4]),(long long)M.rel.satoshis);
+ dpow_pubkeyregister(SUBATOMIC_PRIORITY);
+ M.openrequestid = subatomic_alice_openrequest(&M);
+ if ( M.openrequestid != 0 )
+ subatomic_loop(&M);
+ } else fprintf(stderr,"checkstr mismatch %s %s != %s\n",coin,hashstr,checkstr);
+ }
+ else
+ {
+ M.bobflag = 1;
+ strcpy(M.base.name,hashstr);
+ strcpy(M.base.coin,subatomic_checkname(tmpstr,&M,0,hashstr));
+ subatomic_loop(&M); // while ( 1 ) loop for each relcoin -> basecoin
+ }
+ }
+ return(SUBATOMIC_retval);
+}
+
diff --git a/src/cc/dapps/subatomic.json b/src/cc/dapps/subatomic.json
new file mode 100644
index 000000000..7832fdb9e
--- /dev/null
+++ b/src/cc/dapps/subatomic.json
@@ -0,0 +1,27 @@
+{
+"authorized": [
+ {"chmex":"030754bffcf6dfcb34a20c486ff5a5be5546b9cc16fba9692165272b3f8e98c4af" },
+ {"SHossain":"03c8657bd57b6ceb14514a10e99fe8a0cec5a9bc24592df7f66f050e670e4f6bac" },
+ {"satinder":"03732f8ef851ff234c74d0df575c2c5b159e2bab3faca4ec52b3f217d5cda5361d" },
+ {"ml777":"02453d028c74cb9551e1aaf35113383b6ecbd9f06ff23a4ab1a953429b9763e345" },
+ {"tonylhub":"0218e0f435d4544404c25a7759b7f7174d821215085ef936218c5569d975af468b" },
+ {"gthub":"036c7de9a5090fbad78b9eea41549ccacc07bd0e9e7f8d290c88f470f3569e1a35" },
+ {"zkTrader":"026c6b0b35ec0adc2f8a5c648da1fce634f798c69d5e9fe518400447e88398b830" },
+ {"nutellalicka":"03aee08860e0340f0f490a3ef3718d6676882f2d63d4f536dfebb1d348b82c79ee" },
+ {"gcharang":"02d3431950c2f0f9654217b6ce3d44468d3a9ca7255741767fdeee7c5ec6b47567" },
+ {"jl777":"02b27de3ee5335518b06f69f4fbabb029cfc737613b100996841d5532b324a5a61" }
+],
+"tokens":[
+ {"RICK.demo":"2b1feef719ecb526b07416dd432bce603ac6dc8bfe794cddf105cb52f6aae3cd"}
+],
+"files":[
+ {"filename":"hushd","prices":[{"HUSH":0.1}, {"PIRATE":1}]}
+],
+"externalcoins":[
+ { "BTC":"bitcoin-cli" },
+ { "KMD":"komodod-cli" },
+ { "CHIPS":"chips-cli" },
+ { "PIRATE":"pirate-cli" }
+]
+}
+
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 7fd94e4e7..026475f88 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -74,7 +74,7 @@ namespace Checkpoints {
fWorkAfter = nExpensiveAfter*fSigcheckVerificationFactor;
}
- return fWorkBefore / (fWorkBefore + fWorkAfter);
+ return std::min(fWorkBefore / (fWorkBefore + fWorkAfter), 1.0);
}
int GetTotalBlocksEstimate(const CChainParams::CCheckpointData& data)
diff --git a/src/clientversion.h b/src/clientversion.h
index 71fcee16f..c62e6d3e0 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -33,8 +33,8 @@
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
// Must be kept in sync with configure.ac !
#define CLIENT_VERSION_MAJOR 3
-#define CLIENT_VERSION_MINOR 3
-#define CLIENT_VERSION_REVISION 2
+#define CLIENT_VERSION_MINOR 4
+#define CLIENT_VERSION_REVISION 0
#define CLIENT_VERSION_BUILD 50
//! Set to true for release, false for prerelease or test build
diff --git a/src/coins.cpp b/src/coins.cpp
index 38fac8252..03b046a70 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2012-2014 The Bitcoin Core developers
-// Copyright (c) 2019 The Hush developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -65,7 +65,6 @@ bool CCoins::Spend(uint32_t nPos)
Cleanup();
return true;
}
-bool CCoinsView::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return false; }
bool CCoinsView::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return false; }
bool CCoinsView::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return false; }
bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
@@ -85,7 +84,6 @@ bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
-bool CCoinsViewBacked::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return base->GetSproutAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return base->GetNullifier(nullifier, type); }
bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
@@ -139,30 +137,6 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const
return ret;
}
-
-bool CCoinsViewCache::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const {
- CAnchorsSproutMap::const_iterator it = cacheSproutAnchors.find(rt);
- if (it != cacheSproutAnchors.end()) {
- if (it->second.entered) {
- tree = it->second.tree;
- return true;
- } else {
- return false;
- }
- }
-
- if (!base->GetSproutAnchorAt(rt, tree)) {
- return false;
- }
-
- CAnchorsSproutMap::iterator ret = cacheSproutAnchors.insert(std::make_pair(rt, CAnchorsSproutCacheEntry())).first;
- ret->second.entered = true;
- ret->second.tree = tree;
- cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
-
- return true;
-}
-
bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt);
if (it != cacheSaplingAnchors.end()) {
@@ -271,7 +245,6 @@ void CCoinsViewCache::BringBestAnchorIntoCache(
SproutMerkleTree &tree
)
{
- assert(GetSproutAnchorAt(currentRoot, tree));
}
template<>
@@ -550,9 +523,9 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
bool CCoinsViewCache::Flush() {
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, cacheSproutAnchors, cacheSaplingAnchors, cacheSproutNullifiers, cacheSaplingNullifiers);
cacheCoins.clear();
- cacheSproutAnchors.clear();
+ //cacheSproutAnchors.clear();
cacheSaplingAnchors.clear();
- cacheSproutNullifiers.clear();
+ //cacheSproutNullifiers.clear();
cacheSaplingNullifiers.clear();
cachedCoinsUsage = 0;
return fOk;
@@ -624,37 +597,8 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr
}
-bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
+bool CCoinsViewCache::HaveShieldedRequirements(const CTransaction& tx) const
{
- boost::unordered_map intermediates;
-
- BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit)
- {
- BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers)
- {
- if (GetNullifier(nullifier, SPROUT)) {
- // If the nullifier is set, this transaction
- // double-spends!
- return false;
- }
- }
-
- SproutMerkleTree tree;
- auto it = intermediates.find(joinsplit.anchor);
- if (it != intermediates.end()) {
- tree = it->second;
- } else if (!GetSproutAnchorAt(joinsplit.anchor, tree)) {
- return false;
- }
-
- BOOST_FOREACH(const uint256& commitment, joinsplit.commitments)
- {
- tree.append(commitment);
- }
-
- intermediates.insert(std::make_pair(tree.root(), tree));
- }
-
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
if (GetNullifier(spendDescription.nullifier, SAPLING)) { // Prevent double spends
LogPrintf("%s: sapling nullifier %s exists, preventing double spend\n", __FUNCTION__, spendDescription.nullifier.GetHex().c_str());
diff --git a/src/coins.h b/src/coins.h
index cc8b19f68..2d08be42c 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -372,9 +372,6 @@ struct CCoinsStats
class CCoinsView
{
public:
- //! Retrieve the tree (Sprout) at a particular anchored root in the chain
- virtual bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const;
-
//! Retrieve the tree (Sapling) at a particular anchored root in the chain
virtual bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const;
@@ -421,7 +418,6 @@ protected:
public:
CCoinsViewBacked(CCoinsView *viewIn);
- bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const;
bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier, ShieldedType type) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
@@ -493,7 +489,6 @@ public:
CNullifiersMap getNullifiers();
// Standard CCoinsView methods
- bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const;
bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier, ShieldedType type) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
@@ -550,7 +545,7 @@ public:
size_t DynamicMemoryUsage() const;
/**
- * Amount of bitcoins coming in to a transaction
+ * Amount of HUSH 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.
*
@@ -562,8 +557,8 @@ public:
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
bool HaveInputs(const CTransaction& tx) const;
- //! Check whether all joinsplit requirements (anchors/nullifiers) are satisfied
- bool HaveJoinSplitRequirements(const CTransaction& tx) const;
+ //! Check whether all shielded requirements (anchors/nullifiers) are satisfied
+ bool HaveShieldedRequirements(const CTransaction& tx) const;
//! Return priority of tx at height nHeight
double GetPriority(const CTransaction &tx, int nHeight) const;
diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp
index b75e0c002..984ca377e 100644
--- a/src/consensus/upgrades.cpp
+++ b/src/consensus/upgrades.cpp
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
// Copyright (c) 2018 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c
index 55d7a3b7f..a1bd6b4a3 100644
--- a/src/cryptoconditions/src/anon.c
+++ b/src/cryptoconditions/src/anon.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -53,11 +54,8 @@ static void anonToJSON(const CC *cond, cJSON *params) {
}
-static unsigned char *anonFingerprint(const CC *cond) {
- unsigned char *out = calloc(1, 32);
- //fprintf(stderr,"anon fingerprint %p %p\n",out,cond->fingerprint);
+static void anonFingerprint(const CC *cond, uint8_t *out) {
memcpy(out, cond->fingerprint, 32);
- return out;
}
diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c
index 74949affc..6642b0345 100644
--- a/src/cryptoconditions/src/cryptoconditions.c
+++ b/src/cryptoconditions/src/cryptoconditions.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -65,8 +66,8 @@ void appendUriSubtypes(uint32_t mask, unsigned char *buf) {
char *cc_conditionUri(const CC *cond) {
- unsigned char *fp = cond->type->fingerprint(cond);
- if (!fp) return NULL;
+ unsigned char *fp = calloc(1, 32);
+ cond->type->fingerprint(cond, fp);
unsigned char *encoded = base64_encode(fp, 32);
@@ -118,13 +119,13 @@ uint32_t fromAsnSubtypes(const ConditionTypes_t types) {
size_t cc_conditionBinary(const CC *cond, unsigned char *buf) {
Condition_t *asn = calloc(1, sizeof(Condition_t));
asnCondition(cond, asn);
+ size_t out = 0;
asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Condition, asn, buf, 1000);
- if (rc.encoded == -1) {
- fprintf(stderr, "CONDITION NOT ENCODED\n");
- return 0;
- }
+ if (rc.encoded == -1) goto end;
+ out = rc.encoded;
+end:
ASN_STRUCT_FREE(asn_DEF_Condition, asn);
- return rc.encoded;
+ return out;
}
@@ -146,10 +147,12 @@ void asnCondition(const CC *cond, Condition_t *asn) {
// This may look a little weird - we dont have a reference here to the correct
// union choice for the condition type, so we just assign everything to the threshold
// type. This works out nicely since the union choices have the same binary interface.
+
CompoundSha256Condition_t *choice = &asn->choice.thresholdSha256;
choice->cost = cc_getCost(cond);
- choice->fingerprint.buf = cond->type->fingerprint(cond);
choice->fingerprint.size = 32;
+ choice->fingerprint.buf = calloc(1, 32);
+ cond->type->fingerprint(cond, choice->fingerprint.buf);
choice->subtypes = asnSubtypes(cond->type->getSubtypes(cond));
}
diff --git a/src/cryptoconditions/src/ed25519.c b/src/cryptoconditions/src/ed25519.c
index 8d73d3cf1..33b332071 100644
--- a/src/cryptoconditions/src/ed25519.c
+++ b/src/cryptoconditions/src/ed25519.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -25,11 +26,10 @@
struct CCType CC_Ed25519Type;
-static unsigned char *ed25519Fingerprint(const CC *cond) {
+static void ed25519Fingerprint(const CC *cond, uint8_t *out) {
Ed25519FingerprintContents_t *fp = calloc(1, sizeof(Ed25519FingerprintContents_t));
- //fprintf(stderr,"ed25519 fingerprint %p %p\n",fp,cond->publicKey);
OCTET_STRING_fromBuf(&fp->publicKey, cond->publicKey, 32);
- return hashFingerprintContents(&asn_DEF_Ed25519FingerprintContents, fp);
+ hashFingerprintContents(&asn_DEF_Ed25519FingerprintContents, fp, out);
}
diff --git a/src/cryptoconditions/src/eval.c b/src/cryptoconditions/src/eval.c
index 99ff1ebf5..a017d181d 100644
--- a/src/cryptoconditions/src/eval.c
+++ b/src/cryptoconditions/src/eval.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -25,11 +26,8 @@
struct CCType CC_EvalType;
-static unsigned char *evalFingerprint(const CC *cond) {
- unsigned char *hash = calloc(1, 32);
- //fprintf(stderr,"evalfingerprint %p %p\n",hash,cond->code);
- sha256(cond->code, cond->codeLength, hash);
- return hash;
+static void evalFingerprint(const CC *cond, uint8_t *out) {
+ sha256(cond->code, cond->codeLength, out);
}
@@ -105,7 +103,7 @@ static uint32_t evalSubtypes(const CC *cond) {
*/
int jsonVerifyEval(CC *cond, void *context) {
if (cond->codeLength == 5 && 0 == memcmp(cond->code, "TEST", 4)) {
- return cond->code[5];
+ return cond->code[4];
}
fprintf(stderr, "Cannot verify eval; user function unknown\n");
return 0;
diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h
index bdb9ae43a..5a36ba40b 100644
--- a/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h
+++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h
@@ -36,4 +36,4 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
#endif
-
+#endif
diff --git a/src/cryptoconditions/src/internal.h b/src/cryptoconditions/src/internal.h
index 790e28962..3d24214ce 100644
--- a/src/cryptoconditions/src/internal.h
+++ b/src/cryptoconditions/src/internal.h
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -41,7 +42,7 @@ typedef struct CCType {
char name[100];
Condition_PR asnType;
int (*visitChildren)(CC *cond, CCVisitor visitor);
- unsigned char *(*fingerprint)(const CC *cond);
+ void (*fingerprint)(const CC *cond, uint8_t *fp);
unsigned long (*getCost)(const CC *cond);
uint32_t (*getSubtypes)(const CC *cond);
CC *(*fromJSON)(const cJSON *params, char *err);
@@ -77,7 +78,7 @@ struct CCType *getTypeByAsnEnum(Condition_PR present);
*/
unsigned char *base64_encode(const unsigned char *data, size_t input_length);
unsigned char *base64_decode(const unsigned char *data_, size_t *output_length);
-unsigned char *hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp);
+void hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp, uint8_t* out);
void dumpStr(unsigned char *str, size_t len);
int checkString(const cJSON *value, char *key, char *err);
int checkDecodeBase64(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size);
diff --git a/src/cryptoconditions/src/json_rpc.c b/src/cryptoconditions/src/json_rpc.c
index 150bcb12b..c4fde8080 100644
--- a/src/cryptoconditions/src/json_rpc.c
+++ b/src/cryptoconditions/src/json_rpc.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
diff --git a/src/cryptoconditions/src/prefix.c b/src/cryptoconditions/src/prefix.c
index 45c6d8033..ea339df35 100644
--- a/src/cryptoconditions/src/prefix.c
+++ b/src/cryptoconditions/src/prefix.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -37,13 +38,12 @@ static int prefixVisitChildren(CC *cond, CCVisitor visitor) {
}
-static unsigned char *prefixFingerprint(const CC *cond) {
+static void prefixFingerprint(const CC *cond, uint8_t *out) {
PrefixFingerprintContents_t *fp = calloc(1, sizeof(PrefixFingerprintContents_t));
- //fprintf(stderr,"prefixfinger %p %p\n",fp,cond->prefix);
- asnCondition(cond->subcondition, &fp->subcondition); // TODO: check asnCondition for safety
+ asnCondition(cond->subcondition, &fp->subcondition);
fp->maxMessageLength = cond->maxMessageLength;
OCTET_STRING_fromBuf(&fp->prefix, cond->prefix, cond->prefixLength);
- return hashFingerprintContents(&asn_DEF_PrefixFingerprintContents, fp);
+ hashFingerprintContents(&asn_DEF_PrefixFingerprintContents, fp, out);
}
diff --git a/src/cryptoconditions/src/preimage.c b/src/cryptoconditions/src/preimage.c
index 9e7fe12f4..2fee86b88 100644
--- a/src/cryptoconditions/src/preimage.c
+++ b/src/cryptoconditions/src/preimage.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -44,11 +45,8 @@ static unsigned long preimageCost(const CC *cond) {
}
-static unsigned char *preimageFingerprint(const CC *cond) {
- unsigned char *hash = calloc(1, 32);
- //fprintf(stderr,"preimage %p %p\n",hash,cond->preimage);
- sha256(cond->preimage, cond->preimageLength, hash);
- return hash;
+static void preimageFingerprint(const CC *cond, uint8_t *out) {
+ sha256(cond->preimage, cond->preimageLength, out);
}
diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c
index a16115bb8..d5319d32b 100644
--- a/src/cryptoconditions/src/secp256k1.c
+++ b/src/cryptoconditions/src/secp256k1.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -88,11 +89,10 @@ void initVerify() {
}
-static unsigned char *secp256k1Fingerprint(const CC *cond) {
+static void secp256k1Fingerprint(const CC *cond, uint8_t *out) {
Secp256k1FingerprintContents_t *fp = calloc(1, sizeof(Secp256k1FingerprintContents_t));
- //fprintf(stderr,"secpfinger %p %p size %d vs %d\n",fp,cond->publicKey,(int32_t)sizeof(Secp256k1FingerprintContents_t),(int32_t)SECP256K1_PK_SIZE);
OCTET_STRING_fromBuf(&fp->publicKey, cond->publicKey, SECP256K1_PK_SIZE);
- return hashFingerprintContents(&asn_DEF_Secp256k1FingerprintContents, fp);
+ hashFingerprintContents(&asn_DEF_Secp256k1FingerprintContents, fp, out);
}
diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c
index 9547f4f8c..e8e12435e 100644
--- a/src/cryptoconditions/src/threshold.c
+++ b/src/cryptoconditions/src/threshold.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -94,17 +95,15 @@ static int cmpConditionBin(const void *a, const void *b) {
}
-static unsigned char *thresholdFingerprint(const CC *cond) {
- /* Create fingerprint */
+static void thresholdFingerprint(const CC *cond, uint8_t *out) {
ThresholdFingerprintContents_t *fp = calloc(1, sizeof(ThresholdFingerprintContents_t));
- //fprintf(stderr,"thresholdfinger %p\n",fp);
fp->threshold = cond->threshold;
for (int i=0; isize; i++) {
Condition_t *asnCond = asnConditionNew(cond->subconditions[i]);
asn_set_add(&fp->subconditions2, asnCond);
}
qsort(fp->subconditions2.list.array, cond->size, sizeof(Condition_t*), cmpConditionBin);
- return hashFingerprintContents(&asn_DEF_ThresholdFingerprintContents, fp);
+ hashFingerprintContents(&asn_DEF_ThresholdFingerprintContents, fp, out);
}
diff --git a/src/cryptoconditions/src/utils.c b/src/cryptoconditions/src/utils.c
index 6a2167119..ac2256f18 100644
--- a/src/cryptoconditions/src/utils.c
+++ b/src/cryptoconditions/src/utils.c
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -210,17 +211,15 @@ void jsonAddBase64(cJSON *params, char *key, unsigned char *bin, size_t size) {
}
-unsigned char *hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp) {
+void hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp, uint8_t *out) {
unsigned char buf[BUF_SIZE];
asn_enc_rval_t rc = der_encode_to_buffer(asnType, fp, buf, BUF_SIZE);
ASN_STRUCT_FREE(*asnType, fp);
if (rc.encoded < 1) {
fprintf(stderr, "Encoding fingerprint failed\n");
- return 0;
+ return;
}
- unsigned char *hash = calloc(1,32);
- sha256(buf, rc.encoded, hash);
- return hash;
+ sha256(buf, rc.encoded, out);
}
@@ -301,5 +300,3 @@ int jsonGetHexOptional(const cJSON *params, char *key, char *err, unsigned char
}
return checkDecodeHex(item, key, err, data, size);
}
-
-
diff --git a/src/cryptoconditions/tests/test_failure_modes.py b/src/cryptoconditions/tests/test_failure_modes.py
index 59b0b3f24..435e20c88 100644
--- a/src/cryptoconditions/tests/test_failure_modes.py
+++ b/src/cryptoconditions/tests/test_failure_modes.py
@@ -82,4 +82,25 @@ def test_malleability_checked():
assert not cc_rfb(b'\xa2\x13\xa0\x0f\xa0\x06\x80\x04abcd\xa0\x05\x80\x03abc\xa1\x00')
+def test_large_threshold():
+ conds = [{
+ 'type': "secp256k1-sha-256",
+ "publicKey": "02D5D969305535AC29A77079C11D4F0DD40661CF96E04E974A5E8D7E374EE225AA"
+ }]
+
+ for i in range(250):
+ conds.append({
+ "type": "eval-sha-256",
+ "code": "VEVTVAE"
+ })
+
+ r = jsonRPC("encodeCondition", {
+ "type": "threshold-sha-256",
+ "subfulfillments": conds,
+ "threshold": 251
+ })
+ assert 'error' not in r, r
+
+
+
so.cc_conditionUri.restype = ctypes.c_char_p
diff --git a/src/gtest/test_joinsplit.cpp b/src/gtest/test_joinsplit.cpp
deleted file mode 100644
index 8032fc972..000000000
--- a/src/gtest/test_joinsplit.cpp
+++ /dev/null
@@ -1,585 +0,0 @@
-#include
-
-#include "utilstrencodings.h"
-
-#include
-#include
-
-#include "zcash/prf.h"
-#include "util.h"
-#include "streams.h"
-#include "version.h"
-#include "serialize.h"
-#include "primitives/transaction.h"
-#include "zcash/JoinSplit.hpp"
-#include "zcash/Note.hpp"
-#include "zcash/NoteEncryption.hpp"
-#include "zcash/IncrementalMerkleTree.hpp"
-
-#include
-
-using namespace libzcash;
-
-extern ZCJoinSplit* params;
-
-// Make the Groth proof for a Sprout statement,
-// and store the result in a JSDescription object.
-JSDescription makeSproutProof(
- ZCJoinSplit& js,
- const std::array& inputs,
- const std::array& outputs,
- const uint256& joinSplitPubKey,
- uint64_t vpub_old,
- uint64_t vpub_new,
- const uint256& rt
-){
- return JSDescription(js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
-}
-
-bool verifySproutProof(
- ZCJoinSplit& js,
- const JSDescription& jsdesc,
- const uint256& joinSplitPubKey
-)
-{
- auto verifier = libzcash::ProofVerifier::Strict();
- return jsdesc.Verify(js, verifier, joinSplitPubKey);
-}
-
-
-void test_full_api(ZCJoinSplit* js)
-{
- // Create verification context.
- auto verifier = libzcash::ProofVerifier::Strict();
-
- // The recipient's information.
- SproutSpendingKey recipient_key = SproutSpendingKey::random();
- SproutPaymentAddress recipient_addr = recipient_key.address();
-
- // Create the commitment tree
- SproutMerkleTree tree;
-
- // Set up a JoinSplit description
- uint64_t vpub_old = 10;
- uint64_t vpub_new = 0;
- uint256 joinSplitPubKey = random_uint256();
- uint256 rt = tree.root();
- JSDescription jsdesc;
-
- {
- std::array inputs = {
- JSInput(), // dummy input
- JSInput() // dummy input
- };
-
- std::array outputs = {
- JSOutput(recipient_addr, 10),
- JSOutput() // dummy output
- };
-
- std::array output_notes;
-
- // Perform the proofs
- jsdesc = makeSproutProof(
- *js,
- inputs,
- outputs,
- joinSplitPubKey,
- vpub_old,
- vpub_new,
- rt
- );
- }
-
- // Verify both PHGR and Groth Proof:
- ASSERT_TRUE(verifySproutProof(*js, jsdesc, joinSplitPubKey));
-
- {
- SproutMerkleTree tree;
- JSDescription jsdesc2;
- // Recipient should decrypt
- // Now the recipient should spend the money again
- auto h_sig = js->h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey);
- ZCNoteDecryption decryptor(recipient_key.receiving_key());
-
- auto note_pt = SproutNotePlaintext::decrypt(
- decryptor,
- jsdesc.ciphertexts[0],
- jsdesc.ephemeralKey,
- h_sig,
- 0
- );
-
- auto decrypted_note = note_pt.note(recipient_addr);
-
- ASSERT_TRUE(decrypted_note.value() == 10);
-
- // Insert the commitments from the last tx into the tree
- tree.append(jsdesc.commitments[0]);
- auto witness_recipient = tree.witness();
- tree.append(jsdesc.commitments[1]);
- witness_recipient.append(jsdesc.commitments[1]);
- vpub_old = 0;
- vpub_new = 1;
- rt = tree.root();
- auto joinSplitPubKey2 = random_uint256();
-
- {
- std::array inputs = {
- JSInput(), // dummy input
- JSInput(witness_recipient, decrypted_note, recipient_key)
- };
-
- SproutSpendingKey second_recipient = SproutSpendingKey::random();
- SproutPaymentAddress second_addr = second_recipient.address();
-
- std::array outputs = {
- JSOutput(second_addr, 9),
- JSOutput() // dummy output
- };
-
- std::array output_notes;
-
-
- // Perform the proofs
- jsdesc2 = makeSproutProof(
- *js,
- inputs,
- outputs,
- joinSplitPubKey2,
- vpub_old,
- vpub_new,
- rt
- );
-
- }
-
-
- // Verify Groth Proof:
- ASSERT_TRUE(verifySproutProof(*js, jsdesc2, joinSplitPubKey2));
- }
-}
-
-// Invokes the API (but does not compute a proof)
-// to test exceptions
-void invokeAPI(
- ZCJoinSplit* js,
- const std::array& inputs,
- const std::array& outputs,
- uint64_t vpub_old,
- uint64_t vpub_new,
- const uint256& rt
-) {
- uint256 ephemeralKey;
- uint256 randomSeed;
- uint256 joinSplitPubKey = random_uint256();
- std::array macs;
- std::array nullifiers;
- std::array commitments;
- std::array ciphertexts;
-
- std::array output_notes;
-
- // Groth
- SproutProof proof = js->prove(
- inputs,
- outputs,
- output_notes,
- ciphertexts,
- ephemeralKey,
- joinSplitPubKey,
- randomSeed,
- macs,
- nullifiers,
- commitments,
- vpub_old,
- vpub_new,
- rt,
- false
- );
-}
-
-void invokeAPIFailure(
- ZCJoinSplit* js,
- const std::array& inputs,
- const std::array& outputs,
- uint64_t vpub_old,
- uint64_t vpub_new,
- const uint256& rt,
- std::string reason
-)
-{
- try {
- invokeAPI(js, inputs, outputs, vpub_old, vpub_new, rt);
- FAIL() << "It worked, when it shouldn't have!";
- } catch(std::invalid_argument const & err) {
- EXPECT_EQ(err.what(), reason);
- } catch(...) {
- FAIL() << "Expected invalid_argument exception.";
- }
-}
-
-TEST(joinsplit, h_sig)
-{
-/*
-// by Taylor Hornby
-
-import pyblake2
-import binascii
-
-def hSig(randomSeed, nf1, nf2, joinSplitPubKey):
- return pyblake2.blake2b(
- data=(randomSeed + nf1 + nf2 + joinSplitPubKey),
- digest_size=32,
- person=b"ZcashComputehSig"
- ).digest()
-
-INCREASING = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
-
-TEST_VECTORS = [
- [b"a" * 32, b"b" * 32, b"c" * 32, b"d" * 32],
- [b"\x00" * 32, b"\x00" * 32, b"\x00" * 32, b"\x00" * 32],
- [b"\xFF" * 32, b"\xFF" * 32, b"\xFF" * 32, b"\xFF" * 32],
- [INCREASING, INCREASING, INCREASING, INCREASING]
-]
-
-for test_input in TEST_VECTORS:
- print "---"
- print "\"" + binascii.hexlify(test_input[0][::-1]) + "\""
- print "\"" + binascii.hexlify(test_input[1][::-1]) + "\""
- print "\"" + binascii.hexlify(test_input[2][::-1]) + "\""
- print "\"" + binascii.hexlify(test_input[3][::-1]) + "\""
- print "\"" + binascii.hexlify(hSig(test_input[0], test_input[1], test_input[2], test_input[3])[::-1]) + "\""
-*/
-
- std::vector> tests = {
- {
- "6161616161616161616161616161616161616161616161616161616161616161",
- "6262626262626262626262626262626262626262626262626262626262626262",
- "6363636363636363636363636363636363636363636363636363636363636363",
- "6464646464646464646464646464646464646464646464646464646464646464",
- "a8cba69f1fa329c055756b4af900f8a00b61e44f4cb8a1824ceb58b90a5b8113"
- },
- {
- "0000000000000000000000000000000000000000000000000000000000000000",
- "0000000000000000000000000000000000000000000000000000000000000000",
- "0000000000000000000000000000000000000000000000000000000000000000",
- "0000000000000000000000000000000000000000000000000000000000000000",
- "697322276b5dd93b12fb1fcbd2144b2960f24c73aac6c6a0811447be1e7f1e19"
- },
- {
- "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "4961048919f0ca79d49c9378c36a91a8767060001f4212fe6f7d426f3ccf9f32"
- },
- {
- "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100",
- "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100",
- "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100",
- "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100",
- "b61110ec162693bc3d9ca7fb0eec3afd2e278e2f41394b3ff11d7cb761ad4b27"
- }
- };
-
- BOOST_FOREACH(std::vector& v, tests) {
- auto expected = ZCJoinSplit::h_sig(
- uint256S(v[0]),
- {uint256S(v[1]), uint256S(v[2])},
- uint256S(v[3])
- );
-
- EXPECT_EQ(expected, uint256S(v[4]));
- }
-}
-
-void increment_note_witnesses(
- const uint256& element,
- std::vector& witnesses,
- SproutMerkleTree& tree
-)
-{
- tree.append(element);
- for (SproutWitness& w : witnesses) {
- w.append(element);
- }
- witnesses.push_back(tree.witness());
-}
-
-TEST(joinsplit, full_api_test)
-{
- {
- std::vector witnesses;
- SproutMerkleTree tree;
- increment_note_witnesses(uint256(), witnesses, tree);
- SproutSpendingKey sk = SproutSpendingKey::random();
- SproutPaymentAddress addr = sk.address();
- SproutNote note1(addr.a_pk, 100, random_uint256(), random_uint256());
- increment_note_witnesses(note1.cm(), witnesses, tree);
- SproutNote note2(addr.a_pk, 100, random_uint256(), random_uint256());
- increment_note_witnesses(note2.cm(), witnesses, tree);
- SproutNote note3(addr.a_pk, 2100000000000001, random_uint256(), random_uint256());
- increment_note_witnesses(note3.cm(), witnesses, tree);
- SproutNote note4(addr.a_pk, 1900000000000000, random_uint256(), random_uint256());
- increment_note_witnesses(note4.cm(), witnesses, tree);
- SproutNote note5(addr.a_pk, 1900000000000000, random_uint256(), random_uint256());
- increment_note_witnesses(note5.cm(), witnesses, tree);
-
- // Should work
- invokeAPI(params,
- {
- JSInput(),
- JSInput()
- },
- {
- JSOutput(),
- JSOutput()
- },
- 0,
- 0,
- tree.root());
-
- // lhs > MAX_MONEY
- invokeAPIFailure(params,
- {
- JSInput(),
- JSInput()
- },
- {
- JSOutput(),
- JSOutput()
- },
- 2100000000000001,
- 0,
- tree.root(),
- "nonsensical vpub_old value");
-
- // rhs > MAX_MONEY
- invokeAPIFailure(params,
- {
- JSInput(),
- JSInput()
- },
- {
- JSOutput(),
- JSOutput()
- },
- 0,
- 2100000000000001,
- tree.root(),
- "nonsensical vpub_new value");
-
- // input witness for the wrong element
- invokeAPIFailure(params,
- {
- JSInput(witnesses[0], note1, sk),
- JSInput()
- },
- {
- JSOutput(),
- JSOutput()
- },
- 0,
- 100,
- tree.root(),
- "witness of wrong element for joinsplit input");
-
- // input witness doesn't match up with
- // real root
- invokeAPIFailure(params,
- {
- JSInput(witnesses[1], note1, sk),
- JSInput()
- },
- {
- JSOutput(),
- JSOutput()
- },
- 0,
- 100,
- uint256(),
- "joinsplit not anchored to the correct root");
-
- // input is in the tree now! this should work
- invokeAPI(params,
- {
- JSInput(witnesses[1], note1, sk),
- JSInput()
- },
- {
- JSOutput(),
- JSOutput()
- },
- 0,
- 100,
- tree.root());
-
- // Wrong secret key
- invokeAPIFailure(params,
- {
- JSInput(witnesses[1], note1, SproutSpendingKey::random()),
- JSInput()
- },
- {
- JSOutput(),
- JSOutput()
- },
- 0,
- 0,
- tree.root(),
- "input note not authorized to spend with given key");
-
- // Absurd input value
- invokeAPIFailure(params,
- {
- JSInput(witnesses[3], note3, sk),
- JSInput()
- },
- {
- JSOutput(),
- JSOutput()
- },
- 0,
- 0,
- tree.root(),
- "nonsensical input note value");
-
- // Absurd total input value
- invokeAPIFailure(params,
- {
- JSInput(witnesses[4], note4, sk),
- JSInput(witnesses[5], note5, sk)
- },
- {
- JSOutput(),
- JSOutput()
- },
- 0,
- 0,
- tree.root(),
- "nonsensical left hand size of joinsplit balance");
-
- // Absurd output value
- invokeAPIFailure(params,
- {
- JSInput(),
- JSInput()
- },
- {
- JSOutput(addr, 2100000000000001),
- JSOutput()
- },
- 0,
- 0,
- tree.root(),
- "nonsensical output value");
-
- // Absurd total output value
- invokeAPIFailure(params,
- {
- JSInput(),
- JSInput()
- },
- {
- JSOutput(addr, 1900000000000000),
- JSOutput(addr, 1900000000000000)
- },
- 0,
- 0,
- tree.root(),
- "nonsensical right hand side of joinsplit balance");
-
- // Absurd total output value
- invokeAPIFailure(params,
- {
- JSInput(),
- JSInput()
- },
- {
- JSOutput(addr, 1900000000000000),
- JSOutput()
- },
- 0,
- 0,
- tree.root(),
- "invalid joinsplit balance");
- }
-
- test_full_api(params);
-}
-
-TEST(joinsplit, note_plaintexts)
-{
- uint252 a_sk = uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516840e"));
- uint256 a_pk = PRF_addr_a_pk(a_sk);
- uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk);
- uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
- SproutPaymentAddress addr_pk(a_pk, pk_enc);
-
- uint256 h_sig;
-
- ZCNoteEncryption encryptor(h_sig);
- uint256 epk = encryptor.get_epk();
-
- SproutNote note(a_pk,
- 1945813,
- random_uint256(),
- random_uint256()
- );
-
- std::array memo;
-
- SproutNotePlaintext note_pt(note, memo);
-
- ZCNoteEncryption::Ciphertext ct = note_pt.encrypt(encryptor, pk_enc);
-
- ZCNoteDecryption decryptor(sk_enc);
-
- auto decrypted = SproutNotePlaintext::decrypt(decryptor, ct, epk, h_sig, 0);
- auto decrypted_note = decrypted.note(addr_pk);
-
- ASSERT_TRUE(decrypted_note.a_pk == note.a_pk);
- ASSERT_TRUE(decrypted_note.rho == note.rho);
- ASSERT_TRUE(decrypted_note.r == note.r);
- ASSERT_TRUE(decrypted_note.value() == note.value());
-
- ASSERT_TRUE(decrypted.memo() == note_pt.memo());
-
- // Check memo() returns by reference, not return by value, for use cases such as:
- // std::string data(plaintext.memo().begin(), plaintext.memo().end());
- ASSERT_TRUE(decrypted.memo().data() == decrypted.memo().data());
-
- // Check serialization of note plaintext
- CDataStream ss(SER_DISK, PROTOCOL_VERSION);
- ss << note_pt;
- SproutNotePlaintext note_pt2;
- ss >> note_pt2;
- ASSERT_EQ(note_pt.value(), note.value());
- ASSERT_EQ(note_pt.value(), note_pt2.value());
- ASSERT_EQ(note_pt.memo(), note_pt2.memo());
- ASSERT_EQ(note_pt.rho, note_pt2.rho);
- ASSERT_EQ(note_pt.r, note_pt2.r);
-}
-
-TEST(joinsplit, note_class)
-{
- uint252 a_sk = uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516840e"));
- uint256 a_pk = PRF_addr_a_pk(a_sk);
- uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk);
- uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
- SproutPaymentAddress addr_pk(a_pk, pk_enc);
-
- SproutNote note(a_pk,
- 1945813,
- random_uint256(),
- random_uint256());
-
- SproutNote clone = note;
- ASSERT_NE(¬e, &clone);
- ASSERT_EQ(note.value(), clone.value());
- ASSERT_EQ(note.cm(), clone.cm());
- ASSERT_EQ(note.rho, clone.rho);
- ASSERT_EQ(note.r, clone.r);
- ASSERT_EQ(note.a_pk, clone.a_pk);
-}
diff --git a/src/gtest/test_keystore.cpp b/src/gtest/test_keystore.cpp
index ccf9cb9ba..a8c984984 100644
--- a/src/gtest/test_keystore.cpp
+++ b/src/gtest/test_keystore.cpp
@@ -95,101 +95,6 @@ TEST(keystore_tests, sapling_keys) {
}
}
-TEST(keystore_tests, store_and_retrieve_spending_key) {
- CBasicKeyStore keyStore;
- libzcash::SproutSpendingKey skOut;
-
- std::set addrs;
- keyStore.GetSproutPaymentAddresses(addrs);
- EXPECT_EQ(0, addrs.size());
-
- auto sk = libzcash::SproutSpendingKey::random();
- auto addr = sk.address();
-
- // Sanity-check: we can't get a key we haven't added
- EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr));
- EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut));
-
- keyStore.AddSproutSpendingKey(sk);
- EXPECT_TRUE(keyStore.HaveSproutSpendingKey(addr));
- EXPECT_TRUE(keyStore.GetSproutSpendingKey(addr, skOut));
- EXPECT_EQ(sk, skOut);
-
- keyStore.GetSproutPaymentAddresses(addrs);
- EXPECT_EQ(1, addrs.size());
- EXPECT_EQ(1, addrs.count(addr));
-}
-
-TEST(keystore_tests, store_and_retrieve_note_decryptor) {
- CBasicKeyStore keyStore;
- ZCNoteDecryption decOut;
-
- auto sk = libzcash::SproutSpendingKey::random();
- auto addr = sk.address();
-
- EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
-
- keyStore.AddSproutSpendingKey(sk);
- EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
- EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
-}
-
-TEST(keystore_tests, StoreAndRetrieveViewingKey) {
- CBasicKeyStore keyStore;
- libzcash::SproutViewingKey vkOut;
- libzcash::SproutSpendingKey skOut;
- ZCNoteDecryption decOut;
-
- auto sk = libzcash::SproutSpendingKey::random();
- auto vk = sk.viewing_key();
- auto addr = sk.address();
-
- // Sanity-check: we can't get a viewing key we haven't added
- EXPECT_FALSE(keyStore.HaveSproutViewingKey(addr));
- EXPECT_FALSE(keyStore.GetSproutViewingKey(addr, vkOut));
-
- // and we shouldn't have a spending key or decryptor either
- EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr));
- EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut));
- EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
-
- // and we can't find it in our list of addresses
- std::set addresses;
- keyStore.GetSproutPaymentAddresses(addresses);
- EXPECT_FALSE(addresses.count(addr));
-
- keyStore.AddSproutViewingKey(vk);
- EXPECT_TRUE(keyStore.HaveSproutViewingKey(addr));
- EXPECT_TRUE(keyStore.GetSproutViewingKey(addr, vkOut));
- EXPECT_EQ(vk, vkOut);
-
- // We should still not have the spending key...
- EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr));
- EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut));
-
- // ... but we should have a decryptor
- EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
- EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
-
- // ... and we should find it in our list of addresses
- addresses.clear();
- keyStore.GetSproutPaymentAddresses(addresses);
- EXPECT_TRUE(addresses.count(addr));
-
- keyStore.RemoveSproutViewingKey(vk);
- EXPECT_FALSE(keyStore.HaveSproutViewingKey(addr));
- EXPECT_FALSE(keyStore.GetSproutViewingKey(addr, vkOut));
- EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr));
- EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut));
- addresses.clear();
- keyStore.GetSproutPaymentAddresses(addresses);
- EXPECT_FALSE(addresses.count(addr));
-
- // We still have a decryptor because those are cached in memory
- // (and also we only remove viewing keys when adding a spending key)
- EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
- EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
-}
// Sapling
TEST(keystore_tests, StoreAndRetrieveSaplingSpendingKey) {
@@ -280,9 +185,6 @@ TEST(keystore_tests, StoreAndRetrieveHDSeedInEncryptedStore) {
// 3) Test adding a new seed to an already-encrypted key store
TestCCryptoKeyStore keyStore2;
- // Add a Sprout address so the wallet has something to test when decrypting
- ASSERT_TRUE(keyStore2.AddSproutSpendingKey(libzcash::SproutSpendingKey::random()));
-
ASSERT_TRUE(keyStore2.EncryptKeys(vMasterKey));
ASSERT_TRUE(keyStore2.Unlock(vMasterKey));
@@ -296,78 +198,4 @@ TEST(keystore_tests, StoreAndRetrieveHDSeedInEncryptedStore) {
EXPECT_EQ(seed3, seedOut);
}
-TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
- TestCCryptoKeyStore keyStore;
- uint256 r {GetRandHash()};
- CKeyingMaterial vMasterKey (r.begin(), r.end());
- libzcash::SproutSpendingKey keyOut;
- ZCNoteDecryption decOut;
- std::set addrs;
-
- // 1) Test adding a key to an unencrypted key store, then encrypting it
- auto sk = libzcash::SproutSpendingKey::random();
- auto addr = sk.address();
- EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
-
- keyStore.AddSproutSpendingKey(sk);
- ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr));
- ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr, keyOut));
- ASSERT_EQ(sk, keyOut);
- EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
- EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
-
- ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey));
- ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr));
- ASSERT_FALSE(keyStore.GetSproutSpendingKey(addr, keyOut));
- EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
- EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
-
- // Unlocking with a random key should fail
- uint256 r2 {GetRandHash()};
- CKeyingMaterial vRandomKey (r2.begin(), r2.end());
- EXPECT_FALSE(keyStore.Unlock(vRandomKey));
-
- // Unlocking with a slightly-modified vMasterKey should fail
- CKeyingMaterial vModifiedKey (r.begin(), r.end());
- vModifiedKey[0] += 1;
- EXPECT_FALSE(keyStore.Unlock(vModifiedKey));
-
- // Unlocking with vMasterKey should succeed
- ASSERT_TRUE(keyStore.Unlock(vMasterKey));
- ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr, keyOut));
- ASSERT_EQ(sk, keyOut);
-
- keyStore.GetSproutPaymentAddresses(addrs);
- ASSERT_EQ(1, addrs.size());
- ASSERT_EQ(1, addrs.count(addr));
-
- // 2) Test adding a spending key to an already-encrypted key store
- auto sk2 = libzcash::SproutSpendingKey::random();
- auto addr2 = sk2.address();
- EXPECT_FALSE(keyStore.GetNoteDecryptor(addr2, decOut));
-
- keyStore.AddSproutSpendingKey(sk2);
- ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr2));
- ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr2, keyOut));
- ASSERT_EQ(sk2, keyOut);
- EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
- EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
-
- ASSERT_TRUE(keyStore.Lock());
- ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr2));
- ASSERT_FALSE(keyStore.GetSproutSpendingKey(addr2, keyOut));
- EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
- EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
-
- ASSERT_TRUE(keyStore.Unlock(vMasterKey));
- ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr2, keyOut));
- ASSERT_EQ(sk2, keyOut);
- EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
- EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
-
- keyStore.GetSproutPaymentAddresses(addrs);
- ASSERT_EQ(2, addrs.size());
- ASSERT_EQ(1, addrs.count(addr));
- ASSERT_EQ(1, addrs.count(addr2));
-}
#endif
diff --git a/src/gtest/test_paymentdisclosure.cpp b/src/gtest/test_paymentdisclosure.cpp
deleted file mode 100644
index c166cdbe1..000000000
--- a/src/gtest/test_paymentdisclosure.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-#include
-
-#include "main.h"
-#include "utilmoneystr.h"
-#include "chainparams.h"
-#include "utilstrencodings.h"
-#include "zcash/Address.hpp"
-#include "wallet/wallet.h"
-#include "amount.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "util.h"
-
-#include "paymentdisclosure.h"
-#include "paymentdisclosuredb.h"
-
-#include "sodium.h"
-
-#include
-#include
-#include
-
-using namespace std;
-
-/*
- To run tests:
- ./zcash-gtest --gtest_filter="paymentdisclosure.*"
-
- Note: As an experimental feature, writing your own tests may require option flags to be set.
- mapArgs["-experimentalfeatures"] = true;
- mapArgs["-paymentdisclosure"] = true;
-*/
-
-#define NUM_TRIES 10000
-
-#define DUMP_DATABASE_TO_STDOUT false
-
-static boost::uuids::random_generator uuidgen;
-
-static uint256 random_uint256()
-{
- uint256 ret;
- randombytes_buf(ret.begin(), 32);
- return ret;
-}
-
-// Subclass of PaymentDisclosureDB to add debugging methods
-class PaymentDisclosureDBTest : public PaymentDisclosureDB {
-public:
- PaymentDisclosureDBTest(const boost::filesystem::path& dbPath) : PaymentDisclosureDB(dbPath) {}
-
- void DebugDumpAllStdout() {
- ASSERT_NE(db, nullptr);
- std::lock_guard guard(lock_);
-
- // Iterate over each item in the database and print them
- leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
-
- for (it->SeekToFirst(); it->Valid(); it->Next()) {
- cout << it->key().ToString() << " : ";
- // << it->value().ToString() << endl;
- try {
- std::string strValue = it->value().ToString();
- PaymentDisclosureInfo info;
- CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
- ssValue >> info;
- cout << info.ToString() << std::endl;
- } catch (const std::exception& e) {
- cout << e.what() << std::endl;
- }
- }
-
- if (false == it->status().ok()) {
- cerr << "An error was found iterating over the database" << endl;
- cerr << it->status().ToString() << endl;
- }
-
- delete it;
- }
-};
-
-
-
-// This test creates random payment disclosure blobs and checks that they can be
-// 1. inserted and retrieved from a database
-// 2. serialized and deserialized without corruption
-// Note that the zpd: prefix is not part of the payment disclosure blob itself. It is only
-// used as convention to improve the user experience when sharing payment disclosure blobs.
-TEST(paymentdisclosure, mainnet) {
- SelectParams(CBaseChainParams::MAIN);
-
- boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
- boost::filesystem::create_directories(pathTemp);
- mapArgs["-datadir"] = pathTemp.string();
-
- std::cout << "Test payment disclosure database created in folder: " << pathTemp.string() << std::endl;
-
- PaymentDisclosureDBTest mydb(pathTemp);
-
- for (int i=0; i vch(&buffer[0], &buffer[0] + 32);
- uint256 joinSplitPrivKey = uint256(vch);
-
- // Create payment disclosure key and info data to store in test database
- size_t js = random_uint256().GetCheapHash() % std::numeric_limits::max();
- uint8_t n = random_uint256().GetCheapHash() % std::numeric_limits::max();
- PaymentDisclosureKey key { random_uint256(), js, n};
- PaymentDisclosureInfo info;
- info.esk = random_uint256();
- info.joinSplitPrivKey = joinSplitPrivKey;
- info.zaddr = libzcash::SproutSpendingKey::random().address();
- ASSERT_TRUE(mydb.Put(key, info));
-
- // Retrieve info from test database into new local variable and test it matches
- PaymentDisclosureInfo info2;
- ASSERT_TRUE(mydb.Get(key, info2));
- ASSERT_EQ(info, info2);
-
- // Modify this local variable and confirm it no longer matches
- info2.esk = random_uint256();
- info2.joinSplitPrivKey = random_uint256();
- info2.zaddr = libzcash::SproutSpendingKey::random().address();
- ASSERT_NE(info, info2);
-
- // Using the payment info object, let's create a dummy payload
- PaymentDisclosurePayload payload;
- payload.version = PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL;
- payload.esk = info.esk;
- payload.txid = key.hash;
- payload.js = key.js;
- payload.n = key.n;
- payload.message = "random-" + boost::uuids::to_string(uuidgen()); // random message
- payload.zaddr = info.zaddr;
-
- // Serialize and hash the payload to generate a signature
- uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0);
-
- // Compute the payload signature
- unsigned char payloadSig[64];
- if (!(crypto_sign_detached(&payloadSig[0], NULL,
- dataToBeSigned.begin(), 32,
- &buffer[0] // buffer containing both private and public key required
- ) == 0))
- {
- throw std::runtime_error("crypto_sign_detached failed");
- }
-
- // Sanity check
- if (!(crypto_sign_verify_detached(&payloadSig[0],
- dataToBeSigned.begin(), 32,
- joinSplitPubKey.begin()
- ) == 0))
- {
- throw std::runtime_error("crypto_sign_verify_detached failed");
- }
-
- // Convert signature buffer to boost array
- std::array arrayPayloadSig;
- memcpy(arrayPayloadSig.data(), &payloadSig[0], 64);
-
- // Payment disclosure blob to pass around
- PaymentDisclosure pd = {payload, arrayPayloadSig};
-
- // Test payment disclosure constructors
- PaymentDisclosure pd2(payload, arrayPayloadSig);
- ASSERT_EQ(pd, pd2);
- PaymentDisclosure pd3(joinSplitPubKey, key, info, payload.message);
- ASSERT_EQ(pd, pd3);
-
- // Verify serialization and deserialization works
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
- ss << pd;
- std::string ssHexString = HexStr(ss.begin(), ss.end());
-
- PaymentDisclosure pdTmp;
- CDataStream ssTmp(ParseHex(ssHexString), SER_NETWORK, PROTOCOL_VERSION);
- ssTmp >> pdTmp;
- ASSERT_EQ(pd, pdTmp);
-
- CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
- ss2 << pdTmp;
- std::string ss2HexString = HexStr(ss2.begin(), ss2.end());
- ASSERT_EQ(ssHexString, ss2HexString);
-
- // Verify marker
- ASSERT_EQ(pd.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES);
- ASSERT_EQ(pdTmp.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES);
- ASSERT_EQ(0, ssHexString.find("706462ff")); // Little endian encoding of PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES value
-
- // Sanity check
- PaymentDisclosure pdDummy;
- ASSERT_NE(pd, pdDummy);
- }
-
-#if DUMP_DATABASE_TO_STDOUT == true
- mydb.DebugDumpAllStdout();
-#endif
-}
diff --git a/src/gtest/test_transaction.cpp b/src/gtest/test_transaction.cpp
deleted file mode 100644
index 1350768ff..000000000
--- a/src/gtest/test_transaction.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#include
-
-#include "primitives/transaction.h"
-#include "zcash/Note.hpp"
-#include "zcash/Address.hpp"
-
-#include
-
-extern ZCJoinSplit* params;
-extern int GenZero(int n);
-extern int GenMax(int n);
-
-TEST(Transaction, JSDescriptionRandomized) {
- // construct a merkle tree
- SproutMerkleTree merkleTree;
-
- libzcash::SproutSpendingKey k = libzcash::SproutSpendingKey::random();
- libzcash::SproutPaymentAddress addr = k.address();
-
- libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256());
-
- // commitment from coin
- uint256 commitment = note.cm();
-
- // insert commitment into the merkle tree
- merkleTree.append(commitment);
-
- // compute the merkle root we will be working with
- uint256 rt = merkleTree.root();
-
- auto witness = merkleTree.witness();
-
- // create JSDescription
- uint256 joinSplitPubKey;
- std::array inputs = {
- libzcash::JSInput(witness, note, k),
- libzcash::JSInput() // dummy input of zero value
- };
- std::array outputs = {
- libzcash::JSOutput(addr, 50),
- libzcash::JSOutput(addr, 50)
- };
- std::array inputMap;
- std::array outputMap;
-
- {
- auto jsdesc = JSDescription::Randomized(
- false,
- *params, joinSplitPubKey, rt,
- inputs, outputs,
- inputMap, outputMap,
- 0, 0, false);
-
- std::set inputSet(inputMap.begin(), inputMap.end());
- std::set expectedInputSet {0, 1};
- EXPECT_EQ(expectedInputSet, inputSet);
-
- std::set outputSet(outputMap.begin(), outputMap.end());
- std::set expectedOutputSet {0, 1};
- EXPECT_EQ(expectedOutputSet, outputSet);
- }
-
- {
- auto jsdesc = JSDescription::Randomized(
- false,
- *params, joinSplitPubKey, rt,
- inputs, outputs,
- inputMap, outputMap,
- 0, 0, false, nullptr, GenZero);
-
- std::array expectedInputMap {1, 0};
- std::array expectedOutputMap {1, 0};
- EXPECT_EQ(expectedInputMap, inputMap);
- EXPECT_EQ(expectedOutputMap, outputMap);
- }
-
- {
- auto jsdesc = JSDescription::Randomized(
- false,
- *params, joinSplitPubKey, rt,
- inputs, outputs,
- inputMap, outputMap,
- 0, 0, false, nullptr, GenMax);
-
- std::array expectedInputMap {0, 1};
- std::array expectedOutputMap {0, 1};
- EXPECT_EQ(expectedInputMap, inputMap);
- EXPECT_EQ(expectedOutputMap, outputMap);
- }
-}
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index e1d235665..603e1e6ae 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -11,6 +11,7 @@
#include "rpc/protocol.h" // For HTTP status codes
#include "sync.h"
#include "ui_interface.h"
+#include "utilstrencodings.h"
#include
#include
@@ -251,21 +252,25 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
{
std::unique_ptr hreq(new HTTPRequest(req));
- LogPrint("http", "Received a %s request for %s from %s\n",
- RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
-
// Early address-based allow check
if (!ClientAllowed(hreq->GetPeer())) {
+ LogPrint("http", "HTTP request from %s rejected: Client network is not allowed RPC access\n",
+ hreq->GetPeer().ToString());
hreq->WriteReply(HTTP_FORBIDDEN);
return;
}
// Early reject unknown HTTP methods
if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
+ LogPrint("http", "HTTP request from %s rejected: Unknown HTTP request method\n",
+ hreq->GetPeer().ToString());
hreq->WriteReply(HTTP_BADMETHOD);
return;
}
+ LogPrint("http", "Received a %s request for %s from %s\n",
+ RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToString());
+
// Find registered handler for prefix
std::string strURI = hreq->GetURI();
std::string path;
diff --git a/src/init.cpp b/src/init.cpp
index ac15db192..c43c5b0b4 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -101,7 +101,7 @@ extern int32_t KOMODO_SNAPSHOT_INTERVAL;
extern void komodo_init(int32_t height);
-ZCJoinSplit* pzcashParams = NULL;
+//ZCJoinSplit* pzcashParams = NULL;
#ifdef ENABLE_WALLET
CWallet* pwalletMain = NULL;
@@ -305,8 +305,8 @@ void Shutdown()
delete pwalletMain;
pwalletMain = NULL;
#endif
- delete pzcashParams;
- pzcashParams = NULL;
+ //delete pzcashParams;
+ //pzcashParams = NULL;
globalVerifyHandle.reset();
ECC_Stop();
LogPrintf("%s: done\n", __func__);
@@ -399,6 +399,7 @@ std::string HelpMessage(HelpMessageMode mode)
#ifndef _WIN32
strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), "komodod.pid"));
#endif
+ strUsage += HelpMessageOpt("-txexpirynotify=", _("Execute command when transaction expires (%s in cmd is replaced by transaction id)"));
strUsage += HelpMessageOpt("-prune=", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. "
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
"(default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
@@ -581,7 +582,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-metricsui", _("Set to 1 for a persistent metrics screen, 0 for sequential metrics output (default: 1 if running in a console, 0 otherwise)"));
strUsage += HelpMessageOpt("-metricsrefreshtime", strprintf(_("Number of seconds between metrics refreshes (default: %u if running in a console, %u otherwise)"), 1, 600));
}
- strUsage += HelpMessageGroup(_("Komodo Asset Chain options:"));
+ strUsage += HelpMessageGroup(_("Hush Smart Chain options:"));
strUsage += HelpMessageOpt("-ac_algo", _("Choose PoW mining algorithm, default is Equihash"));
strUsage += HelpMessageOpt("-ac_blocktime", _("Block time in seconds, default is 60"));
strUsage += HelpMessageOpt("-ac_cc", _("Cryptoconditions, default 0"));
@@ -618,6 +619,14 @@ static void BlockNotifyCallback(const uint256& hashNewTip)
boost::thread t(runCommand, strCmd); // thread runs free
}
+static void TxExpiryNotifyCallback(const uint256& txid)
+{
+ std::string strCmd = GetArg("-txexpirynotify", "");
+
+ boost::replace_all(strCmd, "%s", txid.GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+}
+
struct CImportingNow
{
CImportingNow() {
@@ -1033,10 +1042,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (mapArgs.count("-developerencryptwallet")) {
fprintf(stderr,"%s wallet encryption error\n", __FUNCTION__);
return InitError(_("Wallet encryption requires -experimentalfeatures."));
- }
- else if (mapArgs.count("-paymentdisclosure")) {
- fprintf(stderr,"%s payment disclosure error\n", __FUNCTION__);
- return InitError(_("Payment disclosure requires -experimentalfeatures."));
+ //TODO: make this non experimental
} else if (mapArgs.count("-zmergetoaddress")) {
fprintf(stderr,"%s zmerge error\n", __FUNCTION__);
return InitError(_("RPC method z_mergetoaddress requires -experimentalfeatures."));
@@ -2114,6 +2120,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (mapArgs.count("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
+ if (mapArgs.count("-txexpirynotify"))
+ uiInterface.NotifyTxExpiration.connect(TxExpiryNotifyCallback);
if ( KOMODO_REWIND >= 0 )
{
uiInterface.InitMessage(_("Activating best chain..."));
diff --git a/src/init.h b/src/init.h
index 108339865..c68d59419 100644
--- a/src/init.h
+++ b/src/init.h
@@ -23,7 +23,7 @@
#include
-#include "zcash/JoinSplit.hpp"
+//#include "zcash/JoinSplit.hpp"
class CScheduler;
class CWallet;
@@ -34,7 +34,7 @@ class thread_group;
} // namespace boost
extern CWallet* pwalletMain;
-extern ZCJoinSplit* pzcashParams;
+//extern ZCJoinSplit* pzcashParams;
void StartShutdown();
bool ShutdownRequested();
diff --git a/src/key.h b/src/key.h
index 857e8a8ae..16492b151 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,6 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/key_io.cpp b/src/key_io.cpp
index dd4176fee..2e0dfeb9a 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -1,5 +1,6 @@
// Copyright (c) 2014-2016 The Bitcoin Core developers
// Copyright (c) 2016-2018 The Zcash developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -84,15 +85,6 @@ private:
public:
PaymentAddressEncoder(const CChainParams& params) : m_params(params) {}
- std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const
- {
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
- ss << zaddr;
- std::vector data = m_params.Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
- data.insert(data.end(), ss.begin(), ss.end());
- return EncodeBase58Check(data);
- }
-
std::string operator()(const libzcash::SaplingPaymentAddress& zaddr) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
@@ -107,6 +99,7 @@ public:
}
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
+ std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const { return {}; }
};
class ViewingKeyEncoder : public boost::static_visitor
@@ -117,17 +110,6 @@ private:
public:
ViewingKeyEncoder(const CChainParams& params) : m_params(params) {}
- std::string operator()(const libzcash::SproutViewingKey& vk) const
- {
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
- ss << vk;
- std::vector data = m_params.Base58Prefix(CChainParams::ZCVIEWING_KEY);
- data.insert(data.end(), ss.begin(), ss.end());
- std::string ret = EncodeBase58Check(data);
- memory_cleanse(data.data(), data.size());
- return ret;
- }
-
std::string operator()(const libzcash::SaplingIncomingViewingKey& vk) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
@@ -152,17 +134,6 @@ private:
public:
SpendingKeyEncoder(const CChainParams& params) : m_params(params) {}
- std::string operator()(const libzcash::SproutSpendingKey& zkey) const
- {
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
- ss << zkey;
- std::vector data = m_params.Base58Prefix(CChainParams::ZCSPENDING_KEY);
- data.insert(data.end(), ss.begin(), ss.end());
- std::string ret = EncodeBase58Check(data);
- memory_cleanse(data.data(), data.size());
- return ret;
- }
-
std::string operator()(const libzcash::SaplingExtendedSpendingKey& zkey) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
@@ -324,18 +295,6 @@ std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
{
std::vector data;
- if (DecodeBase58Check(str, data)) {
- const std::vector& zaddr_prefix = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
- if ((data.size() == libzcash::SerializedSproutPaymentAddressSize + zaddr_prefix.size()) &&
- std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) {
- CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end());
- CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
- libzcash::SproutPaymentAddress ret;
- ss >> ret;
- return ret;
- }
- }
- data.clear();
auto bech = bech32::Decode(str);
if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS) &&
bech.second.size() == ConvertedSaplingPaymentAddressSize) {
@@ -363,20 +322,6 @@ std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
libzcash::ViewingKey DecodeViewingKey(const std::string& str)
{
std::vector data;
- if (DecodeBase58Check(str, data)) {
- const std::vector& vk_prefix = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY);
- if ((data.size() == libzcash::SerializedSproutViewingKeySize + vk_prefix.size()) &&
- std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) {
- CSerializeData serialized(data.begin() + vk_prefix.size(), data.end());
- CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
- libzcash::SproutViewingKey ret;
- ss >> ret;
- memory_cleanse(serialized.data(), serialized.size());
- memory_cleanse(data.data(), data.size());
- return ret;
- }
- }
- data.clear();
auto bech = bech32::Decode(str);
if(bech.first == Params().Bech32HRP(CChainParams::SAPLING_INCOMING_VIEWING_KEY) &&
bech.second.size() == ConvertedSaplingIncomingViewingKeySize) {
@@ -400,20 +345,6 @@ std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
{
std::vector data;
- if (DecodeBase58Check(str, data)) {
- const std::vector& zkey_prefix = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY);
- if ((data.size() == libzcash::SerializedSproutSpendingKeySize + zkey_prefix.size()) &&
- std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) {
- CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end());
- CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
- libzcash::SproutSpendingKey ret;
- ss >> ret;
- memory_cleanse(serialized.data(), serialized.size());
- memory_cleanse(data.data(), data.size());
- return ret;
- }
- }
- data.clear();
auto bech = bech32::Decode(str);
if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY) &&
bech.second.size() == ConvertedSaplingExtendedSpendingKeySize) {
diff --git a/src/key_io.h b/src/key_io.h
index 013469ab6..567c9a2f2 100644
--- a/src/key_io.h
+++ b/src/key_io.h
@@ -1,6 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2016-2018 The Zcash developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 34bab456c..ca4fa3712 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -128,15 +129,6 @@ bool CBasicKeyStore::HaveWatchOnly() const
return (!setWatchOnly.empty());
}
-bool CBasicKeyStore::AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk)
-{
- LOCK(cs_SpendingKeyStore);
- auto address = sk.address();
- mapSproutSpendingKeys[address] = sk;
- mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(sk.receiving_key())));
- return true;
-}
-
//! Sapling
bool CBasicKeyStore::AddSaplingSpendingKey(
const libzcash::SaplingExtendedSpendingKey &sk,
@@ -155,14 +147,6 @@ bool CBasicKeyStore::AddSaplingSpendingKey(
return true;
}
-bool CBasicKeyStore::AddSproutViewingKey(const libzcash::SproutViewingKey &vk)
-{
- LOCK(cs_SpendingKeyStore);
- auto address = vk.address();
- mapSproutViewingKeys[address] = vk;
- mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(vk.sk_enc)));
- return true;
-}
bool CBasicKeyStore::AddSaplingFullViewingKey(
const libzcash::SaplingFullViewingKey &fvk,
@@ -190,18 +174,7 @@ bool CBasicKeyStore::AddSaplingIncomingViewingKey(
return true;
}
-bool CBasicKeyStore::RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk)
-{
- LOCK(cs_SpendingKeyStore);
- mapSproutViewingKeys.erase(vk.address());
- return true;
-}
-bool CBasicKeyStore::HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const
-{
- LOCK(cs_SpendingKeyStore);
- return mapSproutViewingKeys.count(address) > 0;
-}
bool CBasicKeyStore::HaveSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk) const
{
@@ -215,19 +188,6 @@ bool CBasicKeyStore::HaveSaplingIncomingViewingKey(const libzcash::SaplingPaymen
return mapSaplingIncomingViewingKeys.count(addr) > 0;
}
-bool CBasicKeyStore::GetSproutViewingKey(
- const libzcash::SproutPaymentAddress &address,
- libzcash::SproutViewingKey &vkOut) const
-{
- LOCK(cs_SpendingKeyStore);
- SproutViewingKeyMap::const_iterator mi = mapSproutViewingKeys.find(address);
- if (mi != mapSproutViewingKeys.end()) {
- vkOut = mi->second;
- return true;
- }
- return false;
-}
-
bool CBasicKeyStore::GetSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk,
libzcash::SaplingFullViewingKey &fvkOut) const
{
diff --git a/src/keystore.h b/src/keystore.h
index c2e1f25d9..6f34d9bc4 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -70,14 +71,6 @@ public:
virtual bool HaveWatchOnly(const CScript &dest) const =0;
virtual bool HaveWatchOnly() const =0;
- //! Add a spending key to the store.
- virtual bool AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk) =0;
-
- //! Check whether a spending key corresponding to a given payment address is present in the store.
- virtual bool HaveSproutSpendingKey(const libzcash::SproutPaymentAddress &address) const =0;
- virtual bool GetSproutSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey& skOut) const =0;
- virtual void GetSproutPaymentAddresses(std::set &setAddress) const =0;
-
//! Add a Sapling spending key to the store.
virtual bool AddSaplingSpendingKey(
const libzcash::SaplingExtendedSpendingKey &sk,
@@ -106,21 +99,11 @@ public:
libzcash::SaplingIncomingViewingKey& ivkOut) const =0;
virtual void GetSaplingPaymentAddresses(std::set &setAddress) const =0;
- //! Support for Sprout viewing keys
- virtual bool AddSproutViewingKey(const libzcash::SproutViewingKey &vk) =0;
- virtual bool RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk) =0;
- virtual bool HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const =0;
- virtual bool GetSproutViewingKey(
- const libzcash::SproutPaymentAddress &address,
- libzcash::SproutViewingKey& vkOut) const =0;
};
typedef std::map KeyMap;
typedef std::map ScriptMap;
typedef std::set WatchOnlySet;
-typedef std::map SproutSpendingKeyMap;
-typedef std::map SproutViewingKeyMap;
-typedef std::map NoteDecryptorMap;
// Full viewing key has equivalent functionality to a transparent address
// When encrypting wallet, encrypt SaplingSpendingKeyMap, while leaving SaplingFullViewingKeyMap unencrypted
@@ -137,10 +120,7 @@ protected:
KeyMap mapKeys;
ScriptMap mapScripts;
WatchOnlySet setWatchOnly;
- SproutSpendingKeyMap mapSproutSpendingKeys;
- SproutViewingKeyMap mapSproutViewingKeys;
- NoteDecryptorMap mapNoteDecryptors;
-
+
SaplingSpendingKeyMap mapSaplingSpendingKeys;
SaplingFullViewingKeyMap mapSaplingFullViewingKeys;
SaplingIncomingViewingKeyMap mapSaplingIncomingViewingKeys;
@@ -195,62 +175,6 @@ public:
virtual bool HaveWatchOnly(const CScript &dest) const;
virtual bool HaveWatchOnly() const;
- bool AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk);
- bool HaveSproutSpendingKey(const libzcash::SproutPaymentAddress &address) const
- {
- bool result;
- {
- LOCK(cs_SpendingKeyStore);
- result = (mapSproutSpendingKeys.count(address) > 0);
- }
- return result;
- }
- bool GetSproutSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const
- {
- {
- LOCK(cs_SpendingKeyStore);
- SproutSpendingKeyMap::const_iterator mi = mapSproutSpendingKeys.find(address);
- if (mi != mapSproutSpendingKeys.end())
- {
- skOut = mi->second;
- return true;
- }
- }
- return false;
- }
- bool GetNoteDecryptor(const libzcash::SproutPaymentAddress &address, ZCNoteDecryption &decOut) const
- {
- {
- LOCK(cs_SpendingKeyStore);
- NoteDecryptorMap::const_iterator mi = mapNoteDecryptors.find(address);
- if (mi != mapNoteDecryptors.end())
- {
- decOut = mi->second;
- return true;
- }
- }
- return false;
- }
- void GetSproutPaymentAddresses(std::set &setAddress) const
- {
- setAddress.clear();
- {
- LOCK(cs_SpendingKeyStore);
- SproutSpendingKeyMap::const_iterator mi = mapSproutSpendingKeys.begin();
- while (mi != mapSproutSpendingKeys.end())
- {
- setAddress.insert((*mi).first);
- mi++;
- }
- SproutViewingKeyMap::const_iterator mvi = mapSproutViewingKeys.begin();
- while (mvi != mapSproutViewingKeys.end())
- {
- setAddress.insert((*mvi).first);
- mvi++;
- }
- }
- }
-
//! Sapling
bool AddSaplingSpendingKey(
const libzcash::SaplingExtendedSpendingKey &sk,
@@ -313,17 +237,10 @@ public:
}
}
- virtual bool AddSproutViewingKey(const libzcash::SproutViewingKey &vk);
- virtual bool RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk);
- virtual bool HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const;
- virtual bool GetSproutViewingKey(
- const libzcash::SproutPaymentAddress &address,
- libzcash::SproutViewingKey& vkOut) const;
};
typedef std::vector > CKeyingMaterial;
typedef std::map > > CryptedKeyMap;
-typedef std::map > CryptedSproutSpendingKeyMap;
//! Sapling
typedef std::map > CryptedSaplingSpendingKeyMap;
diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h
index 39cf5da63..e1748c191 100644
--- a/src/komodo_bitcoind.h
+++ b/src/komodo_bitcoind.h
@@ -20,7 +20,7 @@
#include
#include
#include "consensus/params.h"
-#include "primitives/nonce.h"
+//#include "primitives/nonce.h"
#include "komodo_defs.h"
#include "script/standard.h"
#include "cc/CCinclude.h"
diff --git a/src/komodo_defs.h b/src/komodo_defs.h
index 34b1cc364..e482390bb 100644
--- a/src/komodo_defs.h
+++ b/src/komodo_defs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Hush developers
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@@ -34,33 +34,34 @@
#define KOMODO_FIRSTFUNGIBLEID 100
#define KOMODO_SAPLING_ACTIVATION 1544832000 // Dec 15th, 2018
#define KOMODO_SAPLING_DEADLINE 1550188800 // Feb 15th, 2019
-#define ASSETCHAINS_STAKED_BLOCK_FUTURE_MAX 57
-#define ASSETCHAINS_STAKED_BLOCK_FUTURE_HALF 27
-#define ASSETCHAINS_STAKED_MIN_POW_DIFF 536900000 // 537000000 537300000
#define _COINBASE_MATURITY 100
// KMD Notary Seasons
// 1: May 1st 2018 1530921600
// 2: July 15th 2019 1563148800 -> estimated height 1444000
-// 3: 3rd season ending isnt known, so use very far times in future.
+// 3: 3rd season
// 1751328000 = dummy timestamp, 1 July 2025!
// 7113400 = 5x current KMD blockheight.
-// to add 4th season, change NUM_KMD_SEASONS to 4, and add timestamp and height of activation to these arrays.
+// to add seasons, change NUM_KMD_SEASONS, and add timestamp and height of activation to these arrays.
-#define NUM_KMD_SEASONS 4
+#define NUM_KMD_SEASONS 6
#define NUM_KMD_NOTARIES 64
// $ ./contrib/block_time.pl 166250
// Hush Block 166250 will happen at roughly:
// Wed Jan 29 08:14:12 2020 Eastern # 1580303652
// Wed Jan 29 13:14:12 2020 GMT # 1580303652
-const uint32_t nHushHardforkHeight = 166250;
+const uint32_t nHushHardforkHeight = 166250;
+// $ ./contrib/block_time.pl 245555
+// Hush Block 245555 will happen at roughly... now
+const uint32_t nHushHardforkHeight2 = 245055;
// No coins/code are currently using timestamp activated fork
-const uint32_t nHushHardforkTimestamp = 1580303652; // Jan 29nd 1pm GMT
+const uint32_t nHushHardforkTimestamp = 1580303652; // Jan 29nd 1pm GMT
+const uint32_t nHushHardforkTimestamp2 = 1594425600; // Jul 11th 12a GMT
-static const uint32_t KMD_SEASON_TIMESTAMPS[NUM_KMD_SEASONS] = {1525132800, 1563148800, nHushHardforkTimestamp, 1751328000};
-static const int32_t KMD_SEASON_HEIGHTS[NUM_KMD_SEASONS] = {1,2,nHushHardforkHeight, 5*nHushHardforkHeight};
+static const uint32_t KMD_SEASON_TIMESTAMPS[NUM_KMD_SEASONS] = {1525132800, 1563148800, nHushHardforkTimestamp, nHushHardforkTimestamp2, nHushHardforkTimestamp2*5, nHushHardforkTimestamp2*6};
+static const int32_t KMD_SEASON_HEIGHTS[NUM_KMD_SEASONS] = {1,2,nHushHardforkHeight, nHushHardforkHeight2, (int)340000, 5*nHushHardforkHeight2};
// Era array of pubkeys. Add extra seasons to bottom as requried, after adding appropriate info above.
static const char *notaries_elected[NUM_KMD_SEASONS][NUM_KMD_NOTARIES][2] =
@@ -329,7 +330,74 @@ static const char *notaries_elected[NUM_KMD_SEASONS][NUM_KMD_NOTARIES][2] =
{"gt_AR", "0307c1cf89bd8ed4db1b09a0a98cf5f746fc77df3803ecc8611cf9455ec0ce6960" },
{"patchkez_SH", "03d7c187689bf829ca076a30bbf36d2e67bb74e16a3290d8a55df21d6cb15c80c1" },
{"decker_AR", "02a85540db8d41c7e60bf0d33d1364b4151cad883dd032878ea4c037f67b769635" }
- }
+ },
+ {
+ // Season 4 https://github.com/KomodoPlatform/dPoW/blob/s4/iguana/3rd_party
+ {"alien_AR", "024f20c096b085308e21893383f44b4faf1cdedea9ad53cc7d7e7fbfa0c30c1e71" },
+ {"alien_EU", "022b85908191788f409506ebcf96a892f3274f352864c3ed566c5a16de63953236" },
+ {"alien_NA", "022f62b56ddfd07c9860921c701285ac39bb3ac8f6f083d1b59c8f4943be3de162" },
+ {"alright_DEV", "03b6f9493658bdd102503585a08ae642b49d6a68fb69ac3626f9737cd7581abdfa" },
+ {"artemii235_DEV", "037a20916d2e9ea575300ac9d729507c23a606b9a200c8e913d7c9832f912a1fa7" },
+ {"chainmakers_NA", "028803e07bcc521fde264b7191a944f9b3612e8ee4e24a99bcd903f6976240839a" },
+ {"chainzilla_SH", "0311dde03c2dd654ce78323b718ed3ad73a464d1bde97820f3395f54788b5420dd" },
+ {"chmex_AR", "030cd487e10fbf142e0e8d582e702ecb775f378569c3cb5acd0ff97b6b12803588" },
+ {"chmex_EU", "030bf7bd7ad0515c33b5d5d9a91e0729baf801b9002f80495ae535ea1cebb352cb" },
+ {"cipi_EU", "026f4f66385daaf8313ef30ffe4988e7db497132682dca185a70763d93e1417d9d" },
+ {"cipi_NA", "03f4e69edcb4fa3b2095cb8cb1ca010f4ec4972eac5d8822397e5c8d87aa21a739" },
+ {"daemonfox_NA", "023c7584b1006d4a62a4b4c9c1ede390a3789316547897d5ed49ff9385a3acb411" },
+ {"dappvader_SH", "025199bc04bcb8a17976d9fe8bc87763a6150c2727321aa59bf34a2b49f2f3a0ce" },
+ {"decker_AR", "02a85540db8d41c7e60bf0d33d1364b4151cad883dd032878ea4c037f67b769635" },
+ {"decker_DEV", "02fca8ee50e49f480de275745618db7b0b3680b0bdcce7dcae7d2e0fd5c3345744" },
+ {"decker_EU", "027777775b89ff548c3be54fb0c9455437d87f38bfce83bdef113899881b219c9e" },
+ {"dragonhound_NA", "029912212d370ee0fb4d38eefd8bfcd8ab04e2c3b0354020789c29ddf2a35c72d6" },
+ {"dudezmobi_AR", "033c121d3f8d450174674a73f3b7f140b2717a7d51ea19ee597e2e8e8f9d5ed87f" },
+ {"etszombi_AR", "03bfcbca83f11e622fa4eed9a1fa25dba377981ea3b22e3d0a4015f9a932af9272" },
+ {"etszombi_EU", "03a5c083c78ba397970f20b544a01c13e7ed36ca8a5ae26d5fe7bd38b92b6a0c94" },
+ {"fullmoon_AR", "03639bc56d3fecf856f17759a441c5893668e7c2d460f3d216798a413cd6766bb2" },
+ {"fullmoon_NA", "03e388bcc579ac2675f8fadfa921eec186dcea8d2b43de1eed6caba23d5a962b74" },
+ {"fullmoon_SH", "03a5cfda2b097c808834ccdd805828c811b519611feabdfe6b3644312e53f6748f" },
+ {"gcharang_SH", "02a654037d12cdd609f4fad48e15ec54538e03f61fdae1acb855f16ebacac6bd73" },
+ {"greer_NA", "0262da6aaa0b295b8e2f120035924758a4a630f899316dc63ee15ef03e9b7b2b23" },
+ {"indenodes_AR", "0242778789986d614f75bcf629081651b851a12ab1cc10c73995b27b90febb75a2" },
+ {"indenodes_EU", "03a416533cace0814455a1bb1cd7861ce825a543c6f6284a432c4c8d8875b7ace9" },
+ {"indenodes_NA", "02b3908eda4078f0e9b6704451cdc24d418e899c0f515fab338d7494da6f0a647b" },
+ {"indenodes_SH", "031d1584cf0eb4a2d314465e49e2677226b1615c3718013b8d6b4854c15676a58c" },
+ {"karasugoi_NA", "02f803e6f159824a181cc5d709f3d1e7ff65f19e1899920724aeb4e3d2d869f911" },
+ {"madmax_AR", "027afddbcf690230dd8d435ec16a7bfb0083e6b77030f763437f291dfc40a579d0" },
+ {"madmax_EU", "0397ec3a4ad84b3009566d260c89f1c4404e86e5d044964747c9371277e38f5995" },
+ {"madmax_NA", "036d3afebe1eab09f4c38c3ee6a4659ad390f3df92787c11437a58c59a29e408e6" },
+ {"marmarachain_AR", "028690ca1e3afdf8a38b421f6a41f5ff407afc96d5a7a6a488330aae26c8b086bb" },
+ {"mcrypt_SH", "027a4ca7b11d3456ff558c08bb04483a89c7f383448461fd0b6b3b07424aabe9a4" },
+ {"metaphilibert_AR", "0239e34ad22957bbf4c8df824401f237b2afe8d40f7a645ecd43e8f27dde1ab0da" },
+ {"metaphilibert_SH", "03b21ff042bf1730b28bde43f44c064578b41996117ac7634b567c3773089e3be3" },
+ {"mihailo_EU", "036494e7c9467c8c7ff3bf29e841907fb0fa24241866569944ea422479ec0e6252" },
+ {"mrlynch_AR", "03e67440141f53a08684c329ebc852b018e41f905da88e52aa4a6dc5aa4b12447a" },
+ {"mylo_SH", "026d5f29d09ff3f33e14db4811606249b2438c6bcf964876714f81d1f2d952acde" },
+ {"node9_EU", "0392e4c9400e69f28c6b9e89d586da69d5a6af7702f1045eaa6ebc1996f0496e1f" },
+ {"nodeone_NA", "0310a249c6c2dcc29f2135715138a9ddb8e01c0eab701cbd0b96d9cec660dbdc58" },
+ {"nutellalicka_SH", "0284c4d3cb97dd8a32d10fb32b1855ae18cf845dad542e3b8937ca0e998fb54ecc" },
+ {"oszy_EU", "03c53bd421de4a29ce68c8cc83f802e1181e77c08f8f16684490d61452ea8d023a" },
+ {"patchkez_SH", "028c08db6e7242681f50db6c234fe3d6e12fb1a915350311be26373bac0d457d49" },
+ {"pbca26_NA", "03c18431bb6bc95672f640f19998a196becd2851d5dcba4795fe8d85b7d77eab81" },
+ {"peer2cloud_AR", "0243958faf9ae4d43b598b859ddc595c170c4cf50f8e4517d660ae5bc72aeb821b" },
+ {"phba2061_EU", "03369187ce134bd7793ee34af7756fe1ab27202e09306491cdd5d8ad2c71697937" },
+ {"phm87_SH", "03889a10f9df2caef57220628515693cf25316fe1b0693b0241419e75d0d0e66ed" },
+ {"pirate_EU", "0240011b95cde819f298fe0f507b2260c9fecdab784924076d4d1e54c522103cb1" },
+ {"pirate_NA", "02ad7ef25d2dd461e361120cd3efe7cbce5e9512c361e9185aac33dd303d758613" },
+ {"pungocloud_SH", "02641c36ae6747b88150a463a1fe65cf7a9d1c00a64387c73f296f0b64e77c7d3f" },
+ {"smdmitry_AR", "0397b7584cb29717b721c0c587d4462477efc1f36a56921f133c9d17b0cd7f278a" },
+ {"starfleet_EU", "03c6e047218f34644ccba67e317b9da5d28e68bbbb6b9973aef1281d2bafa46496" },
+ {"strob_NA", "02285bf2f9e96068ecac14bc6f770e394927b4da9f5ba833eaa9468b5d47f203a3" },
+ {"strob_SH", "0213751a1c59d3489ca85b3d62a3d606dcef7f0428aa021c1978ea16fb38a2fad6" },
+ {"swisscertifiers_EU", "02e7722ebba9f8b5ebfb4e87d4fa58cc75aef677535b9cfc060c7d9471aacd9c9e" },
+ {"titomane_AR", "03958bd8d13fe6946b8d0d0fbbc3861c72542560d0276e80a4c6b5fe55bc758b81" },
+ {"titomane_EU", "02276090e483db1a01a802456b10831b3b6e0a6ad3ece9b2a01f4aad0e480c8edc" },
+ {"titomane_SH", "02abf206bafc8048dbdc042b8eb6b1e356ea5dbe149eae3532b4811d4905e5cf01" },
+ {"tonyl_AR", "0229e499e3f2e065ced402ceb8aaf3d5ab8bd3793aa074305e9fa30772ce604908" },
+ {"tonyl_DEV", "0258b77d7dcfc6c2628b0b6b438951a6e74201fb2cd180a795e4c37fcf8e78a678" },
+ {"webworker01_NA", "02de90c720c007229374772505a43917a84ed129d5fbcfa4949cc2e9b563351124" },
+ {"zatjum_SH", "0241c5660ca540780be66603b1791127a1261d56abbcb7562c297eec8e4fc078fb" }
+ }
};
#define SETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] |= (1 << ((bitoffset) & 7)))
diff --git a/src/komodo_notary.h b/src/komodo_notary.h
index 8114a86af..d5591aa29 100644
--- a/src/komodo_notary.h
+++ b/src/komodo_notary.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Hush developers
+// Copyright (c) 2019-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
diff --git a/src/main.cpp b/src/main.cpp
index 17b89a76b..fb53e2c28 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -114,6 +114,7 @@ bool fAlerts = DEFAULT_ALERTS;
/* If the tip is older than this (in seconds), the node is considered to be in initial block download.
*/
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
+bool ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false;
unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA;
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
@@ -1224,9 +1225,9 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde
if (IsExpiredTx(tx, nHeight)) {
// Don't increase banscore if the transaction only just expired
int expiredDosLevel = IsExpiredTx(tx, nHeight - 1) ? (dosLevel > 10 ? dosLevel : 10) : 0;
- string strHex = EncodeHexTx(tx);
+ //string strHex = EncodeHexTx(tx);
//fprintf(stderr, "transaction exipred.%s\n",strHex.c_str());
- return state.DoS(expiredDosLevel, error("ContextualCheckTransaction(): transaction %s is expired, expiry block %i vs current block %i\n txhex.%s",tx.GetHash().ToString(),tx.nExpiryHeight,nHeight,strHex), REJECT_INVALID, "tx-overwinter-expired");
+ return state.DoS(expiredDosLevel, error("ContextualCheckTransaction(): transaction %s is expired, expiry block %i vs current block %i\n",tx.GetHash().ToString(),tx.nExpiryHeight,nHeight), REJECT_INVALID, "tx-overwinter-expired");
}
}
@@ -1327,7 +1328,7 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde
))
{
librustzcash_sapling_verification_ctx_free(ctx);
- fprintf(stderr,"%s: Invalid sapling binding sig! tx=%s valueBalance=%li, bindingSig.size=%d\n", __func__, tx.GetHash().ToString().c_str(), tx.valueBalance, tx.bindingSig.size() );
+ fprintf(stderr,"%s: Invalid sapling binding sig! tx=%s valueBalance=%li, bindingSig.size=%li\n", __func__, tx.GetHash().ToString().c_str(), tx.valueBalance, tx.bindingSig.size() );
return state.DoS(100, error("ContextualCheckTransaction(): Sapling binding signature invalid"),
REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid");
}
@@ -1367,16 +1368,8 @@ bool CheckTransaction(uint32_t tiptime,const CTransaction& tx, CValidationState
if (!CheckTransactionWithoutProofVerification(tiptime,tx, state)) {
return false;
- } else {
- // Ensure that zk-SNARKs v|| y
- BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
- if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) {
- return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"),
- REJECT_INVALID, "bad-txns-joinsplit-verification-failed");
- }
- }
- return true;
}
+ return true;
}
int32_t komodo_isnotaryvout(char *coinaddr,uint32_t tiptime) // from ac_private chains only
@@ -1585,17 +1578,18 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio
else if ( joinsplit.vpub_new != 0 && joinsplit.vpub_old == 0 )
z_t++;
}
+
if ( ASSETCHAINS_PRIVATE != 0 && invalid_private_taddr != 0 )
{
static uint32_t counter;
if ( counter++ < 10 )
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");
+ return state.DoS(100, error("CheckTransaction(): this is a private chain, sending to taddrs not allowed"),REJECT_INVALID, "bad-txns-acprivacy-chain");
}
if ( ASSETCHAINS_TXPOW != 0 )
{
- // genesis coinbase 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
+ // BTC genesis coinbase 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
uint256 txid = tx.GetHash();
if ( ((ASSETCHAINS_TXPOW & 2) != 0 && iscoinbase != 0) || ((ASSETCHAINS_TXPOW & 1) != 0 && iscoinbase == 0) )
{
@@ -1741,6 +1735,23 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee, int dosLevel)
{
AssertLockHeld(cs_main);
+ const uint32_t z2zTransitionWindow = 10;
+ const uint32_t z2zTransitionStart = 340000 - z2zTransitionWindow;
+ const uint32_t nHeight = chainActive.Height();
+
+ // This only applies to HUSH3, other chains can start off z2z via ac_private=1
+ if(ishush3) {
+ if((nHeight >= z2zTransitionStart) || (nHeight <= 340000)) {
+ // During the z2z transition window, only coinbase tx's as part of blocks are allowed
+ // Theory: We want an empty mempool at our fork block height, and the only way to assure that
+ // is to have an empty mempool for a few previous blocks, to take care of potential re-orgs
+ // and edge cases. This empty mempool assures there will be no transactions involving taddrs
+ // stuck in the mempool, when the z2z rule takes effect.
+ // Thanks to jl777 for helping design this
+ fprintf(stderr,"%s: rejecting all tx's during z2z transition window at height=%d\n", __func__,nHeight);
+ return false;
+ }
+ }
if (pfMissingInputs)
*pfMissingInputs = false;
uint32_t tiptime;
@@ -1894,10 +1905,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
}
// are the joinsplit's requirements met?
- if (!view.HaveJoinSplitRequirements(tx))
+ if (!view.HaveShieldedRequirements(tx))
{
//fprintf(stderr,"accept failure.2\n");
- return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met");
+ return state.Invalid(error("AcceptToMemoryPool: shielded requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met");
}
// Bring the best block into scope
@@ -2718,9 +2729,9 @@ namespace Consensus {
if (!inputs.HaveInputs(tx))
return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString()));
- // are the JoinSplit's requirements met?
- if (!inputs.HaveJoinSplitRequirements(tx))
- return state.Invalid(error("CheckInputs(): %s JoinSplit requirements not met", tx.GetHash().ToString()));
+ // are the shielded requirements met?
+ if (!inputs.HaveShieldedRequirements(tx))
+ return state.Invalid(error("CheckInputs(): %s shielded requirements not met", tx.GetHash().ToString()));
CAmount nValueIn = 0;
CAmount nFees = 0;
@@ -3349,6 +3360,18 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return(false);
//fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->GetHeight());
AssertLockHeld(cs_main);
+
+ bool ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false;
+ if(!ASSETCHAINS_PRIVATE && ishush3) {
+ unsigned int nHeight = pindex->GetHeight();
+ if(nHeight >= 340000) {
+ // At startup, HUSH3 doesn't know a block height yet and so we must wait until
+ // connecting a block
+ fprintf(stderr, "%s: Going full z2z at height %d!\n",__func__,nHeight);
+ ASSETCHAINS_PRIVATE = 1;
+ }
+ }
+
bool fExpensiveChecks = true;
if (fCheckpointsEnabled) {
CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
@@ -3442,7 +3465,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// Before the genesis block, there was an empty tree
SproutMerkleTree tree;
pindex->hashSproutAnchor = tree.root();
- // The genesis block contained no JoinSplits
+ // The genesis block contained no JoinSplits, lulz
pindex->hashFinalSproutRoot = pindex->hashSproutAnchor;
}
return true;
@@ -3501,13 +3524,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// This should never fail: we should always be able to get the root
// that is on the tip of our chain
- assert(view.GetSproutAnchorAt(old_sprout_tree_root, sprout_tree));
+ //assert(view.GetSproutAnchorAt(old_sprout_tree_root, sprout_tree));
- {
+ //{
// Consistency check: the root of the tree we're given should
// match what we asked for.
- assert(sprout_tree.root() == old_sprout_tree_root);
- }
+ //assert(sprout_tree.root() == old_sprout_tree_root);
+ //}
SaplingMerkleTree sapling_tree;
assert(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree));
@@ -3535,10 +3558,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
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");
+ // are the shielded requirements met?
+ if (!view.HaveShieldedRequirements(tx))
+ return state.DoS(100, error("ConnectBlock(): shielded requirements not met"), REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met");
if (fAddressIndex || fSpentIndex)
{
@@ -3636,21 +3658,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
}
}
- //if ( ASSETCHAINS_SYMBOL[0] == 0 )
- // komodo_earned_interest(pindex->GetHeight(),sum);
CTxUndo undoDummy;
if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo());
}
UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->GetHeight());
- BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
- BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) {
- // Insert the note commitments into our temporary tree.
-
- sprout_tree.append(note_commitment);
- }
- }
BOOST_FOREACH(const OutputDescription &outputDescription, tx.vShieldedOutput) {
sapling_tree.append(outputDescription.cm);
@@ -3660,7 +3673,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
- view.PushAnchor(sprout_tree);
+ //view.PushAnchor(sprout_tree);
view.PushAnchor(sapling_tree);
if (!fJustCheck) {
pindex->hashFinalSproutRoot = sprout_tree.root();
@@ -4210,7 +4223,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
mempool.removeForBlock(pblock->vtx, pindexNew->GetHeight(), txConflicted, !IsInitialBlockDownload());
// Remove transactions that expire at new block height from mempool
- mempool.removeExpired(pindexNew->GetHeight());
+ auto ids = mempool.removeExpired(pindexNew->GetHeight());
+
+ for (auto id : ids) {
+ uiInterface.NotifyTxExpiration(id);
+ }
// Update chainActive & related variables.
UpdateTip(pindexNew);
@@ -6089,7 +6106,7 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
if (!pindexNew)
- throw runtime_error("LoadBlockIndex(): new CBlockIndex failed");
+ throw runtime_error("InsertBlockIndex(): new CBlockIndex failed");
mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
//fprintf(stderr,"inserted to block index %s\n",hash.ToString().c_str());
@@ -6306,6 +6323,13 @@ bool static LoadBlockIndexDB()
chainActive.SetTip(it->second);
+ // Try to detect if we are z2z based on height of blocks on disk
+ // This helps to set it correctly on startup before a new block is connected
+ if(ishush3 && chainActive.Height() >= 340000) {
+ LogPrintf("%s: enabled ac_private=1 at height=%d\n", __func__, chainActive.Height());
+ ASSETCHAINS_PRIVATE = 1;
+ }
+
// Set hashFinalSproutRoot for the end of best chain
it->second->hashFinalSproutRoot = pcoinsTip->GetBestAnchor(SPROUT);
@@ -6368,7 +6392,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
CValidationState state;
- // No need to verify JoinSplits twice
+ // No need to verify shielded req's twice
auto verifier = libzcash::ProofVerifier::Disabled();
//fprintf(stderr,"start VerifyDB %u\n",(uint32_t)time(NULL));
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
diff --git a/src/metrics.cpp b/src/metrics.cpp
index ff0863a19..adbef02f2 100644
--- a/src/metrics.cpp
+++ b/src/metrics.cpp
@@ -288,7 +288,7 @@ int printMiningStatus(bool mining)
} else if (IsInitialBlockDownload()) {
std::cout << _("Mining is paused while downloading blocks.") << std::endl;
} else {
- std::cout << _("Mining is paused (a JoinSplit may be in progress).") << std::endl;
+ std::cout << _("Mining is paused, enhance your calm") << std::endl;
}
}
lines++;
diff --git a/src/miner.cpp b/src/miner.cpp
index 8d3c5d4c4..a91fa9527 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -340,7 +340,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
if (!mempool.mapTx.count(txin.prevout.hash))
{
LogPrintf("ERROR: mempool transaction missing input\n");
- if (fDebug) assert("mempool transaction missing input" == 0);
+ // if (fDebug) assert("mempool transaction missing input" == 0);
fMissingInputs = true;
if (porphan)
vOrphan.pop_back();
diff --git a/src/paymentdisclosure.cpp b/src/paymentdisclosure.cpp
deleted file mode 100644
index eb55a0536..000000000
--- a/src/paymentdisclosure.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2017 The Zcash developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "paymentdisclosure.h"
-
-#include "key_io.h"
-#include "util.h"
-
-std::string PaymentDisclosureInfo::ToString() const {
- return strprintf("PaymentDisclosureInfo(version=%d, esk=%s, joinSplitPrivKey=, address=%s)",
- version, esk.ToString(), EncodePaymentAddress(zaddr));
-}
-
-std::string PaymentDisclosure::ToString() const {
- std::string s = HexStr(payloadSig.begin(), payloadSig.end());
- return strprintf("PaymentDisclosure(payload=%s, payloadSig=%s)", payload.ToString(), s);
-}
-
-std::string PaymentDisclosurePayload::ToString() const {
- return strprintf("PaymentDisclosurePayload(version=%d, esk=%s, txid=%s, js=%d, n=%d, address=%s, message=%s)",
- version, esk.ToString(), txid.ToString(), js, n, EncodePaymentAddress(zaddr), message);
-}
-
-PaymentDisclosure::PaymentDisclosure(const uint256 &joinSplitPubKey, const PaymentDisclosureKey &key, const PaymentDisclosureInfo &info, const std::string &message)
-{
- // Populate payload member variable
- payload.version = info.version; // experimental = 0, production = 1 etc.
- payload.esk = info.esk;
- payload.txid = key.hash;
- payload.js = key.js;
- payload.n = key.n;
- payload.zaddr = info.zaddr;
- payload.message = message;
-
- // Serialize and hash the payload to generate a signature
- uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0);
-
- LogPrint("paymentdisclosure", "Payment Disclosure: signing raw payload = %s\n", dataToBeSigned.ToString());
-
- // Prepare buffer to store ed25519 key pair in libsodium-compatible format
- unsigned char bufferKeyPair[64];
- memcpy(&bufferKeyPair[0], info.joinSplitPrivKey.begin(), 32);
- memcpy(&bufferKeyPair[32], joinSplitPubKey.begin(), 32);
-
- // Compute payload signature member variable
- if (!(crypto_sign_detached(payloadSig.data(), NULL,
- dataToBeSigned.begin(), 32,
- &bufferKeyPair[0]
- ) == 0))
- {
- throw std::runtime_error("crypto_sign_detached failed");
- }
-
- // Sanity check
- if (!(crypto_sign_verify_detached(payloadSig.data(),
- dataToBeSigned.begin(), 32,
- joinSplitPubKey.begin()) == 0))
- {
- throw std::runtime_error("crypto_sign_verify_detached failed");
- }
-
- std::string sigString = HexStr(payloadSig.data(), payloadSig.data() + payloadSig.size());
- LogPrint("paymentdisclosure", "Payment Disclosure: signature = %s\n", sigString);
-}
diff --git a/src/paymentdisclosure.h b/src/paymentdisclosure.h
deleted file mode 100644
index 28a1d4cdc..000000000
--- a/src/paymentdisclosure.h
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright (c) 2017 The Zcash developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef ZCASH_PAYMENTDISCLOSURE_H
-#define ZCASH_PAYMENTDISCLOSURE_H
-
-#include "uint256.h"
-#include "clientversion.h"
-#include "serialize.h"
-#include "streams.h"
-#include "version.h"
-
-// For JSOutPoint
-#include "wallet/wallet.h"
-
-#include
-#include
-#include
-
-
-// Ensure that the two different protocol messages, payment disclosure blobs and transactions,
-// which are signed with the same key, joinSplitPrivKey, have disjoint encodings such that an
-// encoding from one context will be rejected in the other. We know that the set of valid
-// transaction versions is currently ({1..INT32_MAX}) so we will use a negative value for
-// payment disclosure of -10328976 which in hex is 0xFF626470. Serialization is in little endian
-// format, so a payment disclosure hex string begins 706462FF, which in ISO-8859-1 is "pdbÿ".
-#define PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES -10328976
-
-#define PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL 0
-
-#define PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX "zpd:"
-
-typedef JSOutPoint PaymentDisclosureKey;
-
-struct PaymentDisclosureInfo {
- uint8_t version; // 0 = experimental, 1 = first production version, etc.
- uint256 esk; // zcash/NoteEncryption.cpp
- uint256 joinSplitPrivKey; // primitives/transaction.h
- // ed25519 - not tied to implementation e.g. libsodium, see ed25519 rfc
-
- libzcash::SproutPaymentAddress zaddr;
-
- PaymentDisclosureInfo() : version(PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL) {
- }
-
- PaymentDisclosureInfo(uint8_t v, uint256 esk, uint256 key, libzcash::SproutPaymentAddress zaddr) : version(v), esk(esk), joinSplitPrivKey(key), zaddr(zaddr) { }
-
- ADD_SERIALIZE_METHODS;
-
- template
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(version);
- READWRITE(esk);
- READWRITE(joinSplitPrivKey);
- READWRITE(zaddr);
- }
-
- std::string ToString() const;
-
- friend bool operator==(const PaymentDisclosureInfo& a, const PaymentDisclosureInfo& b) {
- return (a.version == b.version && a.esk == b.esk && a.joinSplitPrivKey == b.joinSplitPrivKey && a.zaddr == b.zaddr);
- }
-
- friend bool operator!=(const PaymentDisclosureInfo& a, const PaymentDisclosureInfo& b) {
- return !(a == b);
- }
-
-};
-
-
-struct PaymentDisclosurePayload {
- int32_t marker = PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES; // to be disjoint from transaction encoding
- uint8_t version; // 0 = experimental, 1 = first production version, etc.
- uint256 esk; // zcash/NoteEncryption.cpp
- uint256 txid; // primitives/transaction.h
- uint64_t js; // Index into CTransaction.vjoinsplit
- uint8_t n; // Index into JSDescription fields of length ZC_NUM_JS_OUTPUTS
- libzcash::SproutPaymentAddress zaddr; // zcash/Address.hpp
- std::string message; // parameter to RPC call
-
- ADD_SERIALIZE_METHODS;
-
- template
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(marker);
- READWRITE(version);
- READWRITE(esk);
- READWRITE(txid);
- READWRITE(js);
- READWRITE(n);
- READWRITE(zaddr);
- READWRITE(message);
- }
-
- std::string ToString() const;
-
- friend bool operator==(const PaymentDisclosurePayload& a, const PaymentDisclosurePayload& b) {
- return (
- a.version == b.version &&
- a.esk == b.esk &&
- a.txid == b.txid &&
- a.js == b.js &&
- a.n == b.n &&
- a.zaddr == b.zaddr &&
- a.message == b.message
- );
- }
-
- friend bool operator!=(const PaymentDisclosurePayload& a, const PaymentDisclosurePayload& b) {
- return !(a == b);
- }
-};
-
-struct PaymentDisclosure {
- PaymentDisclosurePayload payload;
- std::array payloadSig;
- // We use boost array because serialize doesn't like char buffer, otherwise we could do: unsigned char payloadSig[64];
-
- PaymentDisclosure() {};
- PaymentDisclosure(const PaymentDisclosurePayload payload, const std::array sig) : payload(payload), payloadSig(sig) {};
- PaymentDisclosure(const uint256& joinSplitPubKey, const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info, const std::string& message);
-
- ADD_SERIALIZE_METHODS;
-
- template
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(payload);
- READWRITE(payloadSig);
- }
-
- std::string ToString() const;
-
- friend bool operator==(const PaymentDisclosure& a, const PaymentDisclosure& b) {
- return (a.payload == b.payload && a.payloadSig == b.payloadSig);
- }
-
- friend bool operator!=(const PaymentDisclosure& a, const PaymentDisclosure& b) {
- return !(a == b);
- }
-};
-
-
-
-typedef std::pair PaymentDisclosureKeyInfo;
-
-
-#endif // ZCASH_PAYMENTDISCLOSURE_H
diff --git a/src/paymentdisclosuredb.cpp b/src/paymentdisclosuredb.cpp
deleted file mode 100644
index 8840dcda0..000000000
--- a/src/paymentdisclosuredb.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2017 The Zcash developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "paymentdisclosuredb.h"
-
-#include "util.h"
-#include "dbwrapper.h"
-
-#include
-
-using namespace std;
-
-static boost::filesystem::path emptyPath;
-
-/**
- * Static method to return the shared/default payment disclosure database.
- */
-shared_ptr PaymentDisclosureDB::sharedInstance() {
- // Thread-safe in C++11 and gcc 4.3
- static shared_ptr ptr = std::make_shared();
- return ptr;
-}
-
-// C++11 delegated constructor
-PaymentDisclosureDB::PaymentDisclosureDB() : PaymentDisclosureDB(emptyPath) {
-}
-
-PaymentDisclosureDB::PaymentDisclosureDB(const boost::filesystem::path& dbPath) {
- boost::filesystem::path path(dbPath);
- if (path.empty()) {
- path = GetDataDir() / "paymentdisclosure";
- LogPrintf("PaymentDisclosure: using default path for database: %s\n", path.string());
- } else {
- LogPrintf("PaymentDisclosure: using custom path for database: %s\n", path.string());
- }
-
- TryCreateDirectory(path);
- options.create_if_missing = true;
- leveldb::Status status = leveldb::DB::Open(options, path.string(), &db);
- dbwrapper_private::HandleError(status); // throws exception
- LogPrintf("PaymentDisclosure: Opened LevelDB successfully\n");
-}
-
-PaymentDisclosureDB::~PaymentDisclosureDB() {
- if (db != nullptr) {
- delete db;
- }
-}
-
-bool PaymentDisclosureDB::Put(const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info)
-{
- if (db == nullptr) {
- return false;
- }
-
- std::lock_guard guard(lock_);
-
- CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- ssValue.reserve(GetSerializeSize(ssValue, info));
- ssValue << info;
- leveldb::Slice slice(&ssValue[0], ssValue.size());
-
- leveldb::Status status = db->Put(writeOptions, key.ToString(), slice);
- dbwrapper_private::HandleError(status);
- return true;
-}
-
-bool PaymentDisclosureDB::Get(const PaymentDisclosureKey& key, PaymentDisclosureInfo& info)
-{
- if (db == nullptr) {
- return false;
- }
-
- std::lock_guard guard(lock_);
-
- std::string strValue;
- leveldb::Status status = db->Get(readOptions, key.ToString(), &strValue);
- if (!status.ok()) {
- if (status.IsNotFound())
- return false;
- LogPrintf("PaymentDisclosure: LevelDB read failure: %s\n", status.ToString());
- dbwrapper_private::HandleError(status);
- }
-
- try {
- CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
- ssValue >> info;
- } catch (const std::exception&) {
- return false;
- }
- return true;
-}
diff --git a/src/paymentdisclosuredb.h b/src/paymentdisclosuredb.h
deleted file mode 100644
index 9352cac8f..000000000
--- a/src/paymentdisclosuredb.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2017 The Zcash developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef ZCASH_PAYMENTDISCLOSUREDB_H
-#define ZCASH_PAYMENTDISCLOSUREDB_H
-
-#include "paymentdisclosure.h"
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include
-
-
-class PaymentDisclosureDB
-{
-protected:
- leveldb::DB* db = nullptr;
- leveldb::Options options;
- leveldb::ReadOptions readOptions;
- leveldb::WriteOptions writeOptions;
- mutable std::mutex lock_;
-
-public:
- static std::shared_ptr sharedInstance();
-
- PaymentDisclosureDB();
- PaymentDisclosureDB(const boost::filesystem::path& dbPath);
- ~PaymentDisclosureDB();
-
- bool Put(const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info);
- bool Get(const PaymentDisclosureKey& key, PaymentDisclosureInfo& info);
-};
-
-
-#endif // ZCASH_PAYMENTDISCLOSUREDB_H
diff --git a/src/primitives/block.h b/src/primitives/block.h
index ea93d6f50..9a6ddf100 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2013 The Bitcoin Core developers
-// Copyright (c) 2019 The Hush developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -23,7 +23,7 @@
#define BITCOIN_PRIMITIVES_BLOCK_H
#include "primitives/transaction.h"
-#include "primitives/nonce.h"
+//#include "primitives/nonce.h"
#include "serialize.h"
#include "uint256.h"
#include "arith_uint256.h"
diff --git a/src/primitives/nonce.cpp b/src/primitives/nonce.cpp
deleted file mode 100644
index a1fbd667d..000000000
--- a/src/primitives/nonce.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2019 The Hush Developers
-// Copyright (c) 2018 Michael Toutonghi
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-/******************************************************************************
- * Copyright © 2014-2019 The SuperNET Developers. *
- * *
- * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
- * the top-level directory of this distribution for the individual copyright *
- * holder information and the developer policies on copyright and licensing. *
- * *
- * Unless otherwise agreed in a custom licensing agreement, no part of the *
- * SuperNET software, including this file may be copied, modified, propagated *
- * or distributed except according to the terms contained in the LICENSE file *
- * *
- * Removal or modification of this copyright notice is prohibited. *
- * *
- ******************************************************************************/
-
-#include "hash.h"
-#include "nonce.h"
-#include
-
diff --git a/src/primitives/nonce.h b/src/primitives/nonce.h
deleted file mode 100644
index b17a9f01b..000000000
--- a/src/primitives/nonce.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2019 Hush Developers
-// Copyright (c) 2018 Michael Toutonghi
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-/******************************************************************************
- * Copyright © 2014-2019 The SuperNET Developers. *
- * *
- * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
- * the top-level directory of this distribution for the individual copyright *
- * holder information and the developer policies on copyright and licensing. *
- * *
- * Unless otherwise agreed in a custom licensing agreement, no part of the *
- * SuperNET software, including this file may be copied, modified, propagated *
- * or distributed except according to the terms contained in the LICENSE file *
- * *
- * Removal or modification of this copyright notice is prohibited. *
- * *
- ******************************************************************************/
-
-#ifndef BITCOIN_PRIMITIVES_NONCE_H
-#define BITCOIN_PRIMITIVES_NONCE_H
-
-#include "serialize.h"
-#include "uint256.h"
-#include "arith_uint256.h"
-
-
-#endif // BITCOIN_PRIMITIVES_NONCE_H
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 2cde04f2c..53aeeda99 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -26,83 +27,6 @@
#include "librustzcash.h"
-JSDescription::JSDescription(
- ZCJoinSplit& params,
- const uint256& joinSplitPubKey,
- const uint256& anchor,
- const std::array& inputs,
- const std::array& outputs,
- CAmount vpub_old,
- CAmount vpub_new,
- bool computeProof,
- uint256 *esk // payment disclosure
-) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor)
-{
- std::array notes;
-
- proof = params.prove(
- inputs,
- outputs,
- notes,
- ciphertexts,
- ephemeralKey,
- joinSplitPubKey,
- randomSeed,
- macs,
- nullifiers,
- commitments,
- vpub_old,
- vpub_new,
- anchor,
- computeProof,
- esk // payment disclosure
- );
-}
-
-JSDescription JSDescription::Randomized(
- ZCJoinSplit& params,
- const uint256& joinSplitPubKey,
- const uint256& anchor,
- std::array& inputs,
- std::array& outputs,
- std::array& inputMap,
- std::array& outputMap,
- CAmount vpub_old,
- CAmount vpub_new,
- bool computeProof,
- uint256 *esk, // payment disclosure
- std::function gen
-)
-{
- // Randomize the order of the inputs and outputs
- inputMap = {0, 1};
- outputMap = {0, 1};
-
- assert(gen);
-
- MappedShuffle(inputs.begin(), inputMap.begin(), ZC_NUM_JS_INPUTS, gen);
- MappedShuffle(outputs.begin(), outputMap.begin(), ZC_NUM_JS_OUTPUTS, gen);
-
- return JSDescription(
- params, joinSplitPubKey, anchor, inputs, outputs,
- vpub_old, vpub_new, computeProof,
- esk // payment disclosure
- );
-}
-
-bool JSDescription::Verify(
- ZCJoinSplit& params,
- libzcash::ProofVerifier& verifier,
- const uint256& joinSplitPubKey
-) const {
- return false;
-}
-
-uint256 JSDescription::h_sig(ZCJoinSplit& params, const uint256& joinSplitPubKey) const
-{
- return params.h_sig(randomSeed, nullifiers, joinSplitPubKey);
-}
-
std::string COutPoint::ToString() const
{
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 2ece7b255..7a46b9c00 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -44,6 +44,7 @@
#include "zcash/Zcash.h"
#include "zcash/JoinSplit.hpp"
#include "zcash/Proof.hpp"
+#include "zcash/Note.hpp"
extern uint32_t ASSETCHAINS_MAGIC;
extern std::string ASSETCHAINS_SELFIMPORT;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 76375b80c..faed5b957 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1668,9 +1668,10 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp, const CPubKey& my
obj.push_back(Pair("chainwork", chainActive.LastTip()->chainPower.chainWork.GetHex()));
obj.push_back(Pair("pruned", fPruneMode));
- SproutMerkleTree tree;
- pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), tree);
- obj.push_back(Pair("commitments", static_cast(tree.size())));
+ //SproutMerkleTree tree;
+ //pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), tree);
+ //obj.push_back(Pair("commitments", static_cast(tree.size())));
+ obj.push_back(Pair("commitments", 0));
CBlockIndex* tip = chainActive.LastTip();
UniValue valuePools(UniValue::VARR);
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 4107ad6f8..4f11a476f 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -139,6 +139,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "z_listunspent", 2 },
{ "z_listunspent", 3 },
{ "z_getbalance", 1},
+ { "z_getnotescount", 0},
{ "z_gettotalbalance", 0},
{ "z_gettotalbalance", 1},
{ "z_gettotalbalance", 2},
@@ -163,8 +164,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "kvupdate", 4 },
{ "z_importkey", 2 },
{ "z_importviewingkey", 2 },
- { "z_getpaymentdisclosure", 1},
- { "z_getpaymentdisclosure", 2},
{ "z_listsentbyaddress", 1},
{ "z_listsentbyaddress", 2},
{ "z_listsentbyaddress", 3},
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index fc4b39ef0..a41a8169d 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -1,5 +1,6 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -203,7 +204,7 @@ UniValue getinfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
" \"version\": xxxxx, (numeric) the server version\n"
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
- " \"balance\": xxxxxxx, (numeric) the total Komodo balance of the wallet\n"
+ " \"balance\": xxxxxxx, (numeric) the total Hush balance of the wallet\n"
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
@@ -536,14 +537,14 @@ UniValue validateaddress(const UniValue& params, bool fHelp, const CPubKey& mypk
{
if (fHelp || params.size() != 1)
throw runtime_error(
- "validateaddress \"komodoaddress\"\n"
- "\nReturn information about the given Komodo address.\n"
+ "validateaddress \"hushaddress\"\n"
+ "\nReturn information about the given Hush address.\n"
"\nArguments:\n"
- "1. \"komodoaddress\" (string, required) The Komodo address to validate\n"
+ "1. \"hushaddress\" (string, required) The Hush address to validate\n"
"\nResult:\n"
"{\n"
" \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
- " \"address\" : \"komodoaddress\", (string) The Komodo address validated\n"
+ " \"address\" : \"hushaddress\", (string) The Hush address validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
" \"isscript\" : true|false, (boolean) If the key is a script\n"
@@ -589,43 +590,6 @@ UniValue validateaddress(const UniValue& params, bool fHelp, const CPubKey& mypk
}
-class DescribePaymentAddressVisitor : public boost::static_visitor
-{
-public:
- UniValue operator()(const libzcash::InvalidEncoding &zaddr) const { return UniValue(UniValue::VOBJ); }
-
- UniValue operator()(const libzcash::SproutPaymentAddress &zaddr) const {
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("type", "sprout"));
- obj.push_back(Pair("payingkey", zaddr.a_pk.GetHex()));
- obj.push_back(Pair("transmissionkey", zaddr.pk_enc.GetHex()));
-#ifdef ENABLE_WALLET
- if (pwalletMain) {
- obj.push_back(Pair("ismine", pwalletMain->HaveSproutSpendingKey(zaddr)));
- }
-#endif
- return obj;
- }
-
- UniValue operator()(const libzcash::SaplingPaymentAddress &zaddr) const {
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("type", "sapling"));
- obj.push_back(Pair("diversifier", HexStr(zaddr.d)));
- obj.push_back(Pair("diversifiedtransmissionkey", zaddr.pk_d.GetHex()));
-#ifdef ENABLE_WALLET
- if (pwalletMain) {
- libzcash::SaplingIncomingViewingKey ivk;
- libzcash::SaplingFullViewingKey fvk;
- bool isMine = pwalletMain->GetSaplingIncomingViewingKey(zaddr, ivk) &&
- pwalletMain->GetSaplingFullViewingKey(ivk, fvk) &&
- pwalletMain->HaveSaplingSpendingKey(fvk);
- obj.push_back(Pair("ismine", isMine));
- }
-#endif
- return obj;
- }
-};
-
UniValue z_validateaddress(const UniValue& params, bool fHelp, const CPubKey& mypk)
{
if (fHelp || params.size() != 1)
@@ -662,11 +626,25 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp, const CPubKey& my
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("isvalid", isValid));
- if (isValid)
+ auto zaddr = boost::get(&address);
+ if (isValid && (zaddr != nullptr))
{
ret.push_back(Pair("address", strAddress));
- UniValue detail = boost::apply_visitor(DescribePaymentAddressVisitor(), address);
- ret.pushKVs(detail);
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("type", "sapling"));
+ obj.push_back(Pair("diversifier", HexStr(zaddr->d)));
+ obj.push_back(Pair("diversifiedtransmissionkey", zaddr->pk_d.GetHex()));
+#ifdef ENABLE_WALLET
+ if (pwalletMain) {
+ libzcash::SaplingIncomingViewingKey ivk;
+ libzcash::SaplingFullViewingKey fvk;
+ bool isMine = pwalletMain->GetSaplingIncomingViewingKey(*zaddr, ivk) &&
+ pwalletMain->GetSaplingFullViewingKey(ivk, fvk) &&
+ pwalletMain->HaveSaplingSpendingKey(fvk);
+ obj.push_back(Pair("ismine", isMine));
+ }
+#endif
+ ret.pushKVs(obj);
}
return ret;
}
@@ -745,9 +723,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp, const CPubKey& mypk)
"\nArguments:\n"
"1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
- "2. \"keys\" (string, required) A json array of keys which are Komodo addresses or hex-encoded public keys\n"
+ "2. \"keys\" (string, required) A json array of keys which are Hush addresses or hex-encoded public keys\n"
" [\n"
- " \"key\" (string) Komodo address or hex-encoded public key\n"
+ " \"key\" (string) Hush address or hex-encoded public key\n"
" ,...\n"
" ]\n"
@@ -781,10 +759,10 @@ UniValue verifymessage(const UniValue& params, bool fHelp, const CPubKey& mypk)
{
if (fHelp || params.size() != 3)
throw runtime_error(
- "verifymessage \"komodoaddress\" \"signature\" \"message\"\n"
+ "verifymessage \"hushaddress\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
- "1. \"komodoaddress\" (string, required) The Komodo address to use for the signature.\n"
+ "1. \"hushaddress\" (string, required) The Hush address to use for the signature.\n"
"2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
"3. \"message\" (string, required) The message that was signed.\n"
"\nResult:\n"
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 181de29bb..56c038596 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
-// Copyright (c) 2019 The Hush developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -669,11 +669,7 @@ static const CRPCCommand vRPCCommands[] =
{ "wallet", "z_importviewingkey", &z_importviewingkey, true },
{ "wallet", "z_exportwallet", &z_exportwallet, true },
{ "wallet", "z_importwallet", &z_importwallet, true },
- { "wallet", "opreturn_burn", &opreturn_burn, true },
-
- // TODO: rearrange into another category
- { "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true },
- { "disclosure", "z_validatepaymentdisclosure", &z_validatepaymentdisclosure, true }
+ { "wallet", "opreturn_burn", &opreturn_burn, true }
#endif // ENABLE_WALLET
};
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 1cd4e993d..6568977d7 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -489,6 +489,7 @@ extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp, const C
extern UniValue z_getoperationresult(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
extern UniValue z_listoperationids(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
extern UniValue opreturn_burn(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
+extern UniValue rescan(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
extern UniValue z_validateaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcmisc.cpp
extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdisclosure.cpp
extern UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdisclosure.cpp
diff --git a/src/rpcblockchain.old b/src/rpcblockchain.old
deleted file mode 100644
index a91f73a63..000000000
--- a/src/rpcblockchain.old
+++ /dev/null
@@ -1,1625 +0,0 @@
-// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "amount.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "checkpoints.h"
-#include "crosschain.h"
-#include "base58.h"
-#include "consensus/validation.h"
-#include "cc/eval.h"
-#include "main.h"
-#include "primitives/transaction.h"
-#include "rpcserver.h"
-#include "sync.h"
-#include "util.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/sign.h"
-#include "script/standard.h"
-
-#include
-
-#include
-
-#include
-
-using namespace std;
-
-extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
-void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
-int32_t komodo_longestchain();
-int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
-<<<<<<< HEAD:src/rpcblockchain.old
-extern int32_t KOMODO_LONGESTCHAIN;
-=======
->>>>>>> master:src/rpcblockchain.cpp
-
-double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty)
-{
- // Floating point number that is a multiple of the minimum difficulty,
- // minimum difficulty = 1.0.
- if (blockindex == NULL)
- {
- if (chainActive.LastTip() == NULL)
- return 1.0;
- else
- blockindex = chainActive.LastTip();
- }
-
- uint32_t bits;
- if (networkDifficulty) {
- bits = GetNextWorkRequired(blockindex, nullptr, Params().GetConsensus());
- } else {
- bits = blockindex->nBits;
- }
-
- uint32_t powLimit =
- UintToArith256(Params().GetConsensus().powLimit).GetCompact();
- int nShift = (bits >> 24) & 0xff;
- int nShiftAmount = (powLimit >> 24) & 0xff;
-
- double dDiff =
- (double)(powLimit & 0x00ffffff) /
- (double)(bits & 0x00ffffff);
-
- while (nShift < nShiftAmount)
- {
- dDiff *= 256.0;
- nShift++;
- }
- while (nShift > nShiftAmount)
- {
- dDiff /= 256.0;
- nShift--;
- }
-
- return dDiff;
-}
-
-double GetDifficulty(const CBlockIndex* blockindex)
-{
- return GetDifficultyINTERNAL(blockindex, false);
-}
-
-double GetNetworkDifficulty(const CBlockIndex* blockindex)
-{
- return GetDifficultyINTERNAL(blockindex, true);
-}
-
-static UniValue ValuePoolDesc(
- const std::string &name,
- const boost::optional chainValue,
- const boost::optional valueDelta)
-{
- UniValue rv(UniValue::VOBJ);
- rv.push_back(Pair("id", name));
- rv.push_back(Pair("monitored", (bool)chainValue));
- if (chainValue) {
- rv.push_back(Pair("chainValue", ValueFromAmount(*chainValue)));
- rv.push_back(Pair("chainValueZat", *chainValue));
- }
- if (valueDelta) {
- rv.push_back(Pair("valueDelta", ValueFromAmount(*valueDelta)));
- rv.push_back(Pair("valueDeltaZat", *valueDelta));
- }
- return rv;
-}
-
-UniValue blockheaderToJSON(const CBlockIndex* blockindex)
-{
- UniValue result(UniValue::VOBJ);
- if ( blockindex == 0 )
- {
- result.push_back(Pair("error", "null blockhash"));
- return(result);
- }
- result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
- int confirmations = -1;
- // Only report confirmations if the block is on the main chain
- if (chainActive.Contains(blockindex))
- confirmations = chainActive.Height() - blockindex->nHeight + 1;
- result.push_back(Pair("confirmations", komodo_dpowconfs(blockindex->nHeight,confirmations)));
- result.push_back(Pair("rawconfirmations", confirmations));
- result.push_back(Pair("height", blockindex->nHeight));
- result.push_back(Pair("version", blockindex->nVersion));
- result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex()));
- result.push_back(Pair("time", (int64_t)blockindex->nTime));
- result.push_back(Pair("nonce", blockindex->nNonce.GetHex()));
- result.push_back(Pair("solution", HexStr(blockindex->nSolution)));
- result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits)));
- result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
- result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
- result.push_back(Pair("segid", (int64_t)blockindex->segid));
-
- if (blockindex->pprev)
- result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
- CBlockIndex *pnext = chainActive.Next(blockindex);
- if (pnext)
- result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
- return result;
-}
-
-UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
-{
- UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hash", block.GetHash().GetHex()));
- int confirmations = -1;
- // Only report confirmations if the block is on the main chain
- if (chainActive.Contains(blockindex)) {
- confirmations = chainActive.Height() - blockindex->nHeight + 1;
- } else {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block is an orphan");
- }
- result.push_back(Pair("confirmations", komodo_dpowconfs(blockindex->nHeight,confirmations)));
- result.push_back(Pair("rawconfirmations", confirmations));
- result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
- result.push_back(Pair("height", blockindex->nHeight));
- result.push_back(Pair("version", block.nVersion));
- result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
- result.push_back(Pair("segid", (int64_t)blockindex->segid));
-
- UniValue deltas(UniValue::VARR);
-
- for (unsigned int i = 0; i < block.vtx.size(); i++) {
- const CTransaction &tx = block.vtx[i];
- const uint256 txhash = tx.GetHash();
-
- UniValue entry(UniValue::VOBJ);
- entry.push_back(Pair("txid", txhash.GetHex()));
- entry.push_back(Pair("index", (int)i));
-
- UniValue inputs(UniValue::VARR);
-
- if (!tx.IsCoinBase()) {
-
- for (size_t j = 0; j < tx.vin.size(); j++) {
- const CTxIn input = tx.vin[j];
-
- UniValue delta(UniValue::VOBJ);
-
- CSpentIndexValue spentInfo;
- CSpentIndexKey spentKey(input.prevout.hash, input.prevout.n);
-
- if (GetSpentIndex(spentKey, spentInfo)) {
- if (spentInfo.addressType == 1) {
- delta.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString()));
- }
- else if (spentInfo.addressType == 2) {
- delta.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString()));
- }
- else {
- continue;
- }
- delta.push_back(Pair("satoshis", -1 * spentInfo.satoshis));
- delta.push_back(Pair("index", (int)j));
- delta.push_back(Pair("prevtxid", input.prevout.hash.GetHex()));
- delta.push_back(Pair("prevout", (int)input.prevout.n));
-
- inputs.push_back(delta);
- } else {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Spent information not available");
- }
-
- }
- }
-
- entry.push_back(Pair("inputs", inputs));
-
- UniValue outputs(UniValue::VARR);
-
- for (unsigned int k = 0; k < tx.vout.size(); k++) {
- const CTxOut &out = tx.vout[k];
-
- UniValue delta(UniValue::VOBJ);
-
- if (out.scriptPubKey.IsPayToScriptHash()) {
- vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
- delta.push_back(Pair("address", CBitcoinAddress(CScriptID(uint160(hashBytes))).ToString()));
-
- }
- else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
- vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
- delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString()));
- }
- else if (out.scriptPubKey.IsPayToPublicKey() || out.scriptPubKey.IsPayToCryptoCondition()) {
- CTxDestination address;
- if (ExtractDestination(out.scriptPubKey, address))
- {
- //vector hashBytes(out.scriptPubKey.begin()+1, out.scriptPubKey.begin()+34);
- //xxx delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString()));
- delta.push_back(Pair("address", CBitcoinAddress(address).ToString()));
- }
- }
- else {
- continue;
- }
-
- delta.push_back(Pair("satoshis", out.nValue));
- delta.push_back(Pair("index", (int)k));
-
- outputs.push_back(delta);
- }
-
- entry.push_back(Pair("outputs", outputs));
- deltas.push_back(entry);
-
- }
- result.push_back(Pair("deltas", deltas));
- result.push_back(Pair("time", block.GetBlockTime()));
- result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
- result.push_back(Pair("nonce", block.nNonce.GetHex()));
- result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
- result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
- result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
-
- if (blockindex->pprev)
- result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
- CBlockIndex *pnext = chainActive.Next(blockindex);
- if (pnext)
- result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
- return result;
-}
-
-UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
-{
- UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hash", block.GetHash().GetHex()));
- int confirmations = -1;
- // Only report confirmations if the block is on the main chain
- if (chainActive.Contains(blockindex))
- confirmations = chainActive.Height() - blockindex->nHeight + 1;
- result.push_back(Pair("confirmations", komodo_dpowconfs(blockindex->nHeight,confirmations)));
- result.push_back(Pair("rawconfirmations", confirmations));
- result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
- result.push_back(Pair("height", blockindex->nHeight));
- result.push_back(Pair("version", block.nVersion));
- result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
- result.push_back(Pair("segid", (int64_t)blockindex->segid));
- UniValue txs(UniValue::VARR);
- BOOST_FOREACH(const CTransaction&tx, block.vtx)
- {
- if(txDetails)
- {
- UniValue objTx(UniValue::VOBJ);
- TxToJSON(tx, uint256(), objTx);
- txs.push_back(objTx);
- }
- else
- txs.push_back(tx.GetHash().GetHex());
- }
- result.push_back(Pair("tx", txs));
- result.push_back(Pair("time", block.GetBlockTime()));
- result.push_back(Pair("nonce", block.nNonce.GetHex()));
- result.push_back(Pair("solution", HexStr(block.nSolution)));
- result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
- result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
- result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
- result.push_back(Pair("anchor", blockindex->hashAnchorEnd.GetHex()));
-
- UniValue valuePools(UniValue::VARR);
- valuePools.push_back(ValuePoolDesc("sprout", blockindex->nChainSproutValue, blockindex->nSproutValue));
- result.push_back(Pair("valuePools", valuePools));
-
- if (blockindex->pprev)
- result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
- CBlockIndex *pnext = chainActive.Next(blockindex);
- if (pnext)
- result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
- return result;
-}
-
-UniValue getblockcount(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 0)
- throw runtime_error(
- "getblockcount\n"
- "\nReturns the number of blocks in the best valid block chain.\n"
- "\nResult:\n"
- "n (numeric) The current block count\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockcount", "")
- + HelpExampleRpc("getblockcount", "")
- );
-
- LOCK(cs_main);
- return chainActive.Height();
-}
-
-UniValue getbestblockhash(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 0)
- throw runtime_error(
- "getbestblockhash\n"
- "\nReturns the hash of the best (tip) block in the longest block chain.\n"
- "\nResult\n"
- "\"hex\" (string) the block hash hex encoded\n"
- "\nExamples\n"
- + HelpExampleCli("getbestblockhash", "")
- + HelpExampleRpc("getbestblockhash", "")
- );
-
- LOCK(cs_main);
- return chainActive.LastTip()->GetBlockHash().GetHex();
-}
-
-UniValue getdifficulty(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 0)
- throw runtime_error(
- "getdifficulty\n"
- "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
- "\nResult:\n"
- "n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
- "\nExamples:\n"
- + HelpExampleCli("getdifficulty", "")
- + HelpExampleRpc("getdifficulty", "")
- );
-
- LOCK(cs_main);
- return GetNetworkDifficulty();
-}
-
-bool myIsutxo_spentinmempool(uint256 txid,int32_t vout)
-{
- //char *uint256_str(char *str,uint256); char str[65];
- //LOCK(mempool.cs);
- BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
- {
- const CTransaction &tx = e.GetTx();
- const uint256 &hash = tx.GetHash();
- BOOST_FOREACH(const CTxIn &txin,tx.vin)
- {
- //fprintf(stderr,"%s/v%d ",uint256_str(str,txin.prevout.hash),txin.prevout.n);
- if ( txin.prevout.n == vout && txin.prevout.hash == txid )
- return(true);
- }
- //fprintf(stderr,"are vins for %s\n",uint256_str(str,hash));
- }
- return(false);
-}
-
-bool mytxid_inmempool(uint256 txid)
-{
- BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
- {
- const CTransaction &tx = e.GetTx();
- const uint256 &hash = tx.GetHash();
- if ( txid == hash )
- return(true);
- }
- return(false);
-}
-
-UniValue mempoolToJSON(bool fVerbose = false)
-{
- if (fVerbose)
- {
- LOCK(mempool.cs);
- UniValue o(UniValue::VOBJ);
- BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx)
- {
- const uint256& hash = e.GetTx().GetHash();
- UniValue info(UniValue::VOBJ);
- info.push_back(Pair("size", (int)e.GetTxSize()));
- info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
- info.push_back(Pair("time", e.GetTime()));
- info.push_back(Pair("height", (int)e.GetHeight()));
- info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
- info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
- const CTransaction& tx = e.GetTx();
- set setDepends;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- if (mempool.exists(txin.prevout.hash))
- setDepends.insert(txin.prevout.hash.ToString());
- }
-
- UniValue depends(UniValue::VARR);
- BOOST_FOREACH(const string& dep, setDepends)
- {
- depends.push_back(dep);
- }
-
- info.push_back(Pair("depends", depends));
- o.push_back(Pair(hash.ToString(), info));
- }
- return o;
- }
- else
- {
- vector vtxid;
- mempool.queryHashes(vtxid);
-
- UniValue a(UniValue::VARR);
- BOOST_FOREACH(const uint256& hash, vtxid)
- a.push_back(hash.ToString());
-
- return a;
- }
-}
-
-UniValue getrawmempool(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() > 1)
- throw runtime_error(
- "getrawmempool ( verbose )\n"
- "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
- "\nArguments:\n"
- "1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
- "\nResult: (for verbose = false):\n"
- "[ (json array of string)\n"
- " \"transactionid\" (string) The transaction id\n"
- " ,...\n"
- "]\n"
- "\nResult: (for verbose = true):\n"
- "{ (json object)\n"
- " \"transactionid\" : { (json object)\n"
- " \"size\" : n, (numeric) transaction size in bytes\n"
- " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
- " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
- " \"height\" : n, (numeric) block height when transaction entered pool\n"
- " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
- " \"currentpriority\" : n, (numeric) transaction priority now\n"
- " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
- " \"transactionid\", (string) parent transaction id\n"
- " ... ]\n"
- " }, ...\n"
- "}\n"
- "\nExamples\n"
- + HelpExampleCli("getrawmempool", "true")
- + HelpExampleRpc("getrawmempool", "true")
- );
-
- LOCK(cs_main);
-
- bool fVerbose = false;
- if (params.size() > 0)
- fVerbose = params[0].get_bool();
-
- return mempoolToJSON(fVerbose);
-}
-
-UniValue getblockdeltas(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 1)
- throw runtime_error("");
-
- std::string strHash = params[0].get_str();
- uint256 hash(uint256S(strHash));
-
- if (mapBlockIndex.count(hash) == 0)
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
-
- CBlock block;
- CBlockIndex* pblockindex = mapBlockIndex[hash];
-
- 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");
-
- return blockToDeltasJSON(block, pblockindex);
-}
-
-UniValue getblockhashes(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() < 2)
- throw runtime_error(
- "getblockhashes timestamp\n"
- "\nReturns array of hashes of blocks within the timestamp range provided.\n"
- "\nArguments:\n"
- "1. high (numeric, required) The newer block timestamp\n"
- "2. low (numeric, required) The older block timestamp\n"
- "3. options (string, required) A json object\n"
- " {\n"
- " \"noOrphans\":true (boolean) will only include blocks on the main chain\n"
- " \"logicalTimes\":true (boolean) will include logical timestamps with hashes\n"
- " }\n"
- "\nResult:\n"
- "[\n"
- " \"hash\" (string) The block hash\n"
- "]\n"
- "[\n"
- " {\n"
- " \"blockhash\": (string) The block hash\n"
- " \"logicalts\": (numeric) The logical timestamp\n"
- " }\n"
- "]\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockhashes", "1231614698 1231024505")
- + HelpExampleRpc("getblockhashes", "1231614698, 1231024505")
- + HelpExampleCli("getblockhashes", "1231614698 1231024505 '{\"noOrphans\":false, \"logicalTimes\":true}'")
- );
-
- unsigned int high = params[0].get_int();
- unsigned int low = params[1].get_int();
- bool fActiveOnly = false;
- bool fLogicalTS = false;
-
- if (params.size() > 2) {
- if (params[2].isObject()) {
- UniValue noOrphans = find_value(params[2].get_obj(), "noOrphans");
- UniValue returnLogical = find_value(params[2].get_obj(), "logicalTimes");
-
- if (noOrphans.isBool())
- fActiveOnly = noOrphans.get_bool();
-
- if (returnLogical.isBool())
- fLogicalTS = returnLogical.get_bool();
- }
- }
-
- std::vector > blockHashes;
-
- if (fActiveOnly)
- LOCK(cs_main);
-
- if (!GetTimestampIndex(high, low, fActiveOnly, blockHashes)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for block hashes");
- }
-
- UniValue result(UniValue::VARR);
-
- for (std::vector >::const_iterator it=blockHashes.begin(); it!=blockHashes.end(); it++) {
- if (fLogicalTS) {
- UniValue item(UniValue::VOBJ);
- item.push_back(Pair("blockhash", it->first.GetHex()));
- item.push_back(Pair("logicalts", (int)it->second));
- result.push_back(item);
- } else {
- result.push_back(it->first.GetHex());
- }
- }
-
- return result;
-}
-
-UniValue getblockhash(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "getblockhash index\n"
- "\nReturns hash of block in best-block-chain at index provided.\n"
- "\nArguments:\n"
- "1. index (numeric, required) The block index\n"
- "\nResult:\n"
- "\"hash\" (string) The block hash\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockhash", "1000")
- + HelpExampleRpc("getblockhash", "1000")
- );
-
- LOCK(cs_main);
-
- int nHeight = params[0].get_int();
- if (nHeight < 0 || nHeight > chainActive.Height())
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
-
- CBlockIndex* pblockindex = chainActive[nHeight];
- return pblockindex->GetBlockHash().GetHex();
-}
-
-/*uint256 _komodo_getblockhash(int32_t nHeight)
-{
- uint256 hash;
- LOCK(cs_main);
- if ( nHeight >= 0 && nHeight <= chainActive.Height() )
- {
- CBlockIndex* pblockindex = chainActive[nHeight];
- hash = pblockindex->GetBlockHash();
- int32_t i;
- for (i=0; i<32; i++)
- printf("%02x",((uint8_t *)&hash)[i]);
- printf(" blockhash.%d\n",nHeight);
- } else memset(&hash,0,sizeof(hash));
- return(hash);
-}*/
-
-UniValue getblockheader(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
- "getblockheader \"hash\" ( verbose )\n"
- "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
- "If verbose is true, returns an Object with information about blockheader .\n"
- "\nArguments:\n"
- "1. \"hash\" (string, required) The block hash\n"
- "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
- "\nResult (for verbose = true):\n"
- "{\n"
- " \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
- " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
- " \"height\" : n, (numeric) The block height or index\n"
- " \"version\" : n, (numeric) The block version\n"
- " \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
- " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
- " \"nonce\" : n, (numeric) The nonce\n"
- " \"bits\" : \"1d00ffff\", (string) The bits\n"
- " \"difficulty\" : x.xxx, (numeric) The difficulty\n"
- " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
- " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
- "}\n"
- "\nResult (for verbose=false):\n"
- "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
- + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
- );
-
- LOCK(cs_main);
-
- std::string strHash = params[0].get_str();
- uint256 hash(uint256S(strHash));
-
- bool fVerbose = true;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
-
- if (mapBlockIndex.count(hash) == 0)
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
-
- CBlockIndex* pblockindex = mapBlockIndex[hash];
-
- if (!fVerbose)
- {
- CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
- ssBlock << pblockindex->GetBlockHeader();
- std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
- return strHex;
- }
-
- return blockheaderToJSON(pblockindex);
-}
-
-UniValue getblock(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
- "getblock \"hash|height\" ( verbose )\n"
- "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash|height'.\n"
- "If verbose is true, returns an Object with information about block .\n"
- "\nArguments:\n"
- "1. \"hash|height\" (string, required) The block hash or height\n"
- "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
- "\nResult (for verbose = true):\n"
- "{\n"
- " \"hash\" : \"hash\", (string) the block hash (same as provided hash)\n"
- " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
- " \"size\" : n, (numeric) The block size\n"
- " \"height\" : n, (numeric) The block height or index (same as provided height)\n"
- " \"version\" : n, (numeric) The block version\n"
- " \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
- " \"tx\" : [ (array of string) The transaction ids\n"
- " \"transactionid\" (string) The transaction id\n"
- " ,...\n"
- " ],\n"
- " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
- " \"nonce\" : n, (numeric) The nonce\n"
- " \"bits\" : \"1d00ffff\", (string) The bits\n"
- " \"difficulty\" : x.xxx, (numeric) The difficulty\n"
- " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
- " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
- "}\n"
- "\nResult (for verbose=false):\n"
- "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
- "\nExamples:\n"
- + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
- + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
- + HelpExampleCli("getblock", "12800")
- + HelpExampleRpc("getblock", "12800")
- );
-
- LOCK(cs_main);
-
- std::string strHash = params[0].get_str();
-
- // If height is supplied, find the hash
- if (strHash.size() < (2 * sizeof(uint256))) {
- // std::stoi allows characters, whereas we want to be strict
- regex r("[[:digit:]]+");
- if (!regex_match(strHash, r)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter");
- }
-
- int nHeight = -1;
- try {
- nHeight = std::stoi(strHash);
- }
- catch (const std::exception &e) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter");
- }
-
- if (nHeight < 0 || nHeight > chainActive.Height()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
- }
- strHash = chainActive[nHeight]->GetBlockHash().GetHex();
- }
-
- uint256 hash(uint256S(strHash));
-
- bool fVerbose = true;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
-
- if (mapBlockIndex.count(hash) == 0)
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
-
- CBlock block;
- CBlockIndex* pblockindex = mapBlockIndex[hash];
-
- 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 (!fVerbose)
- {
- CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
- ssBlock << block;
- std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
- return strHex;
- }
-
- return blockToJSON(block, pblockindex);
-}
-
-UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 0)
- throw runtime_error(
- "gettxoutsetinfo\n"
- "\nReturns statistics about the unspent transaction output set.\n"
- "Note this call may take some time.\n"
- "\nResult:\n"
- "{\n"
- " \"height\":n, (numeric) The current block height (index)\n"
- " \"bestblock\": \"hex\", (string) the best block hash hex\n"
- " \"transactions\": n, (numeric) The number of transactions\n"
- " \"txouts\": n, (numeric) The number of output transactions\n"
- " \"bytes_serialized\": n, (numeric) The serialized size\n"
- " \"hash_serialized\": \"hash\", (string) The serialized hash\n"
- " \"total_amount\": x.xxx (numeric) The total amount\n"
- "}\n"
- "\nExamples:\n"
- + HelpExampleCli("gettxoutsetinfo", "")
- + HelpExampleRpc("gettxoutsetinfo", "")
- );
-
- UniValue ret(UniValue::VOBJ);
-
- CCoinsStats stats;
- FlushStateToDisk();
- if (pcoinsTip->GetStats(stats)) {
- ret.push_back(Pair("height", (int64_t)stats.nHeight));
- ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
- ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
- ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs));
- ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
- ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
- ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
- }
- return ret;
-}
-
-#include "komodo_defs.h"
-#include "komodo_structs.h"
-
-#define IGUANA_MAXSCRIPTSIZE 10001
-#define KOMODO_KVDURATION 1440
-#define KOMODO_KVBINARY 2
-extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
-uint64_t komodo_paxprice(uint64_t *seedp,int32_t height,char *base,char *rel,uint64_t basevolume);
-int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *base,char *rel);
-int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
-char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len);
-int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width);
-int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen);
-
-UniValue kvsearch(const UniValue& params, bool fHelp)
-{
- UniValue ret(UniValue::VOBJ); uint32_t flags; uint8_t value[IGUANA_MAXSCRIPTSIZE*8],key[IGUANA_MAXSCRIPTSIZE*8]; int32_t duration,j,height,valuesize,keylen; uint256 refpubkey; static uint256 zeroes;
- if (fHelp || params.size() != 1 )
- throw runtime_error(
- "kvsearch key\n"
- "\nSearch for a key stored via the kvupdate command. This feature is only available for asset chains.\n"
- "\nArguments:\n"
- "1. key (string, required) search the chain for this key\n"
- "\nResult:\n"
- "{\n"
- " \"coin\": \"xxxxx\", (string) chain the key is stored on\n"
- " \"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"
- " \"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"
- " \"value\": \"xxxxx\", (string) stored value\n"
- " \"valuesize\": xxxxx (string) amount of characters stored\n"
- "}\n"
- "\nExamples:\n"
- + HelpExampleCli("kvsearch", "examplekey")
- + HelpExampleRpc("kvsearch", "\"examplekey\"")
- );
- LOCK(cs_main);
- if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
- {
- ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
- ret.push_back(Pair("currentheight", (int64_t)chainActive.LastTip()->nHeight));
- ret.push_back(Pair("key",params[0].get_str()));
- ret.push_back(Pair("keylen",keylen));
- if ( keylen < sizeof(key) )
- {
- memcpy(key,params[0].get_str().c_str(),keylen);
- if ( (valuesize= komodo_kvsearch(&refpubkey,chainActive.LastTip()->nHeight,&flags,&height,value,key,keylen)) >= 0 )
- {
- std::string val; char *valuestr;
- val.resize(valuesize);
- valuestr = (char *)val.data();
- memcpy(valuestr,value,valuesize);
- if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
- ret.push_back(Pair("owner",refpubkey.GetHex()));
- ret.push_back(Pair("height",height));
- duration = ((flags >> 2) + 1) * KOMODO_KVDURATION;
- ret.push_back(Pair("expiration", (int64_t)(height+duration)));
- ret.push_back(Pair("flags",(int64_t)flags));
- ret.push_back(Pair("value",val));
- ret.push_back(Pair("valuesize",valuesize));
- } else ret.push_back(Pair("error",(char *)"cant find key"));
- } else ret.push_back(Pair("error",(char *)"key too big"));
- } else ret.push_back(Pair("error",(char *)"null key"));
- return ret;
-}
-
-UniValue minerids(const UniValue& params, bool fHelp)
-{
- uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); uint8_t minerids[2000],pubkeys[65][33]; int32_t i,j,n,numnotaries,tally[129];
- if ( fHelp || params.size() != 1 )
- throw runtime_error("minerids needs height\n");
- LOCK(cs_main);
- int32_t height = atoi(params[0].get_str().c_str());
- if ( height <= 0 )
- height = chainActive.LastTip()->nHeight;
- else
- {
- CBlockIndex *pblockindex = chainActive[height];
- if ( pblockindex != 0 )
- timestamp = pblockindex->GetBlockTime();
- }
- if ( (n= komodo_minerids(minerids,height,(int32_t)(sizeof(minerids)/sizeof(*minerids)))) > 0 )
- {
- memset(tally,0,sizeof(tally));
- numnotaries = komodo_notaries(pubkeys,height,timestamp);
- if ( numnotaries > 0 )
- {
- for (i=0; i= numnotaries )
- tally[128]++;
- else tally[minerids[i]]++;
- }
- for (i=0; i<64; i++)
- {
- UniValue item(UniValue::VOBJ); std::string hex,kmdaddress; char *hexstr,kmdaddr[64],*ptr; int32_t m;
- hex.resize(66);
- hexstr = (char *)hex.data();
- for (j=0; j<33; j++)
- sprintf(&hexstr[j*2],"%02x",pubkeys[i][j]);
- item.push_back(Pair("notaryid", i));
-
- bitcoin_address(kmdaddr,60,pubkeys[i],33);
- m = (int32_t)strlen(kmdaddr);
- kmdaddress.resize(m);
- ptr = (char *)kmdaddress.data();
- memcpy(ptr,kmdaddr,m);
- item.push_back(Pair("KMDaddress", kmdaddress));
-
- item.push_back(Pair("pubkey", hex));
- item.push_back(Pair("blocks", tally[i]));
- a.push_back(item);
- }
- UniValue item(UniValue::VOBJ);
- item.push_back(Pair("pubkey", (char *)"external miners"));
- item.push_back(Pair("blocks", tally[128]));
- a.push_back(item);
- }
- ret.push_back(Pair("mined", a));
- ret.push_back(Pair("numnotaries", numnotaries));
- } else ret.push_back(Pair("error", (char *)"couldnt extract minerids"));
- return ret;
-}
-
-UniValue notaries(const UniValue& params, bool fHelp)
-{
- UniValue a(UniValue::VARR); uint32_t timestamp=0; UniValue ret(UniValue::VOBJ); int32_t i,j,n,m; char *hexstr; uint8_t pubkeys[64][33]; char btcaddr[64],kmdaddr[64],*ptr;
- if ( fHelp || (params.size() != 1 && params.size() != 2) )
- throw runtime_error("notaries height timestamp\n");
- LOCK(cs_main);
- int32_t height = atoi(params[0].get_str().c_str());
- if ( params.size() == 2 )
- timestamp = (uint32_t)atol(params[1].get_str().c_str());
- else timestamp = (uint32_t)time(NULL);
- if ( height < 0 )
- {
- height = chainActive.LastTip()->nHeight;
- timestamp = chainActive.LastTip()->GetBlockTime();
- }
- else if ( params.size() < 2 )
- {
- CBlockIndex *pblockindex = chainActive[height];
- if ( pblockindex != 0 )
- timestamp = pblockindex->GetBlockTime();
- }
- if ( (n= komodo_notaries(pubkeys,height,timestamp)) > 0 )
- {
- for (i=0; i 0 )
- ret.push_back(Pair("withdraws", opretbuf));
- else ret.push_back(Pair("withdraws", (char *)""));
- for (baseid=0; baseid<32; baseid++)
- {
- UniValue item(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
- if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,CURRENCIES[baseid]) == 0 )
- {
- if ( deposited != 0 || issued != 0 || withdrawn != 0 || approved != 0 || redeemed != 0 )
- {
- item.push_back(Pair("available", ValueFromAmount(available)));
- item.push_back(Pair("deposited", ValueFromAmount(deposited)));
- item.push_back(Pair("issued", ValueFromAmount(issued)));
- item.push_back(Pair("withdrawn", ValueFromAmount(withdrawn)));
- item.push_back(Pair("approved", ValueFromAmount(approved)));
- item.push_back(Pair("redeemed", ValueFromAmount(redeemed)));
- obj.push_back(Pair(CURRENCIES[baseid],item));
- a.push_back(obj);
- }
- }
- }
- ret.push_back(Pair("fiatstatus", a));
- return ret;
-}
-
-UniValue paxprice(const UniValue& params, bool fHelp)
-{
- if ( fHelp || params.size() > 4 || params.size() < 2 )
- throw runtime_error("paxprice \"base\" \"rel\" height\n");
- LOCK(cs_main);
- UniValue ret(UniValue::VOBJ); uint64_t basevolume=0,relvolume,seed;
- std::string base = params[0].get_str();
- std::string rel = params[1].get_str();
- int32_t height;
- if ( params.size() == 2 )
- height = chainActive.LastTip()->nHeight;
- else height = atoi(params[2].get_str().c_str());
- //if ( params.size() == 3 || (basevolume= COIN * atof(params[3].get_str().c_str())) == 0 )
- basevolume = 100000;
- relvolume = komodo_paxprice(&seed,height,(char *)base.c_str(),(char *)rel.c_str(),basevolume);
- ret.push_back(Pair("base", base));
- ret.push_back(Pair("rel", rel));
- ret.push_back(Pair("height", height));
- char seedstr[32];
- sprintf(seedstr,"%llu",(long long)seed);
- ret.push_back(Pair("seed", seedstr));
- if ( height < 0 || height > chainActive.Height() )
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
- else
- {
- CBlockIndex *pblockindex = chainActive[height];
- if ( pblockindex != 0 )
- ret.push_back(Pair("timestamp", (int64_t)pblockindex->nTime));
- if ( basevolume != 0 && relvolume != 0 )
- {
- ret.push_back(Pair("price",((double)relvolume / (double)basevolume)));
- ret.push_back(Pair("invprice",((double)basevolume / (double)relvolume)));
- ret.push_back(Pair("basevolume",ValueFromAmount(basevolume)));
- ret.push_back(Pair("relvolume",ValueFromAmount(relvolume)));
- } else ret.push_back(Pair("error", "overflow or error in one or more of parameters"));
- }
- return ret;
-}
-
-UniValue paxprices(const UniValue& params, bool fHelp)
-{
- if ( fHelp || params.size() != 3 )
- throw runtime_error("paxprices \"base\" \"rel\" maxsamples\n");
- LOCK(cs_main);
- UniValue ret(UniValue::VOBJ); uint64_t relvolume,prices[4096]; uint32_t i,n; int32_t heights[sizeof(prices)/sizeof(*prices)];
- std::string base = params[0].get_str();
- std::string rel = params[1].get_str();
- int32_t maxsamples = atoi(params[2].get_str().c_str());
- if ( maxsamples < 1 )
- maxsamples = 1;
- else if ( maxsamples > sizeof(heights)/sizeof(*heights) )
- maxsamples = sizeof(heights)/sizeof(*heights);
- ret.push_back(Pair("base", base));
- ret.push_back(Pair("rel", rel));
- n = komodo_paxprices(heights,prices,maxsamples,(char *)base.c_str(),(char *)rel.c_str());
- UniValue a(UniValue::VARR);
- for (i=0; i chainActive.Height() )
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
- else
- {
- CBlockIndex *pblockindex = chainActive[heights[i]];
-
- item.push_back(Pair("t", (int64_t)pblockindex->nTime));
- item.push_back(Pair("p", (double)prices[i] / COIN));
- a.push_back(item);
- }
- }
- ret.push_back(Pair("array", a));
- return ret;
-}
-
-uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
-
-UniValue gettxout(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() < 2 || params.size() > 3)
- throw runtime_error(
- "gettxout \"txid\" n ( includemempool )\n"
- "\nReturns details about an unspent transaction output.\n"
- "\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id\n"
- "2. n (numeric, required) vout value\n"
- "3. includemempool (boolean, optional) Whether to include the mempool\n"
- "\nResult:\n"
- "{\n"
- " \"bestblock\" : \"hash\", (string) the block hash\n"
- " \"confirmations\" : n, (numeric) The number of confirmations\n"
- " \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n"
- " \"scriptPubKey\" : { (json object)\n"
- " \"asm\" : \"code\", (string) \n"
- " \"hex\" : \"hex\", (string) \n"
- " \"reqSigs\" : n, (numeric) Number of required signatures\n"
- " \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n"
- " \"addresses\" : [ (array of string) array of Komodo addresses\n"
- " \"komodoaddress\" (string) Komodo address\n"
- " ,...\n"
- " ]\n"
- " },\n"
- " \"version\" : n, (numeric) The version\n"
- " \"coinbase\" : true|false (boolean) Coinbase or not\n"
- "}\n"
-
- "\nExamples:\n"
- "\nGet unspent transactions\n"
- + HelpExampleCli("listunspent", "") +
- "\nView the details\n"
- + HelpExampleCli("gettxout", "\"txid\" 1") +
- "\nAs a json rpc call\n"
- + HelpExampleRpc("gettxout", "\"txid\", 1")
- );
-
- LOCK(cs_main);
-
- UniValue ret(UniValue::VOBJ);
-
- std::string strHash = params[0].get_str();
- uint256 hash(uint256S(strHash));
- int n = params[1].get_int();
- bool fMempool = true;
- if (params.size() > 2)
- fMempool = params[2].get_bool();
-
- CCoins coins;
- if (fMempool) {
- LOCK(mempool.cs);
- CCoinsViewMemPool view(pcoinsTip, mempool);
- if (!view.GetCoins(hash, coins))
- return NullUniValue;
- mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
- } else {
- if (!pcoinsTip->GetCoins(hash, coins))
- return NullUniValue;
- }
- if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
- return NullUniValue;
-
- BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
- CBlockIndex *pindex = it->second;
- ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex()));
- if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
- ret.push_back(Pair("confirmations", 0));
- else
- {
- ret.push_back(Pair("confirmations", komodo_dpowconfs(coins.nHeight,pindex->nHeight - coins.nHeight + 1)));
- ret.push_back(Pair("rawconfirmations", pindex->nHeight - coins.nHeight + 1));
- }
- ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
- uint64_t interest; int32_t txheight; uint32_t locktime;
- if ( (interest= komodo_accrued_interest(&txheight,&locktime,hash,n,coins.nHeight,coins.vout[n].nValue,(int32_t)pindex->nHeight)) != 0 )
- ret.push_back(Pair("interest", ValueFromAmount(interest)));
- UniValue o(UniValue::VOBJ);
- ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
- ret.push_back(Pair("scriptPubKey", o));
- ret.push_back(Pair("version", coins.nVersion));
- ret.push_back(Pair("coinbase", coins.fCoinBase));
-
- return ret;
-}
-
-UniValue verifychain(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() > 2)
- throw runtime_error(
- "verifychain ( checklevel numblocks )\n"
- "\nVerifies blockchain database.\n"
- "\nArguments:\n"
- "1. checklevel (numeric, optional, 0-4, default=3) How thorough the block verification is.\n"
- "2. numblocks (numeric, optional, default=288, 0=all) The number of blocks to check.\n"
- "\nResult:\n"
- "true|false (boolean) Verified or not\n"
- "\nExamples:\n"
- + HelpExampleCli("verifychain", "")
- + HelpExampleRpc("verifychain", "")
- );
-
- LOCK(cs_main);
-
- int nCheckLevel = GetArg("-checklevel", 3);
- int nCheckDepth = GetArg("-checkblocks", 288);
- if (params.size() > 0)
- nCheckLevel = params[0].get_int();
- if (params.size() > 1)
- nCheckDepth = params[1].get_int();
-
- return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth);
-}
-
-/** Implementation of IsSuperMajority with better feedback */
-static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams)
-{
- int nFound = 0;
- CBlockIndex* pstart = pindex;
- for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++)
- {
- if (pstart->nVersion >= minVersion)
- ++nFound;
- pstart = pstart->pprev;
- }
-
- UniValue rv(UniValue::VOBJ);
- rv.push_back(Pair("status", nFound >= nRequired));
- rv.push_back(Pair("found", nFound));
- rv.push_back(Pair("required", nRequired));
- rv.push_back(Pair("window", consensusParams.nMajorityWindow));
- return rv;
-}
-
-static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
-{
- UniValue rv(UniValue::VOBJ);
- rv.push_back(Pair("id", name));
- rv.push_back(Pair("version", version));
- rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)));
- rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams)));
- return rv;
-}
-
-static UniValue NetworkUpgradeDesc(const Consensus::Params& consensusParams, Consensus::UpgradeIndex idx, int height)
-{
- UniValue rv(UniValue::VOBJ);
- auto upgrade = NetworkUpgradeInfo[idx];
- rv.push_back(Pair("name", upgrade.strName));
- rv.push_back(Pair("activationheight", consensusParams.vUpgrades[idx].nActivationHeight));
- switch (NetworkUpgradeState(height, consensusParams, idx)) {
- case UPGRADE_DISABLED: rv.push_back(Pair("status", "disabled")); break;
- case UPGRADE_PENDING: rv.push_back(Pair("status", "pending")); break;
- case UPGRADE_ACTIVE: rv.push_back(Pair("status", "active")); break;
- }
- rv.push_back(Pair("info", upgrade.strInfo));
- return rv;
-}
-
-void NetworkUpgradeDescPushBack(
- UniValue& networkUpgrades,
- const Consensus::Params& consensusParams,
- Consensus::UpgradeIndex idx,
- int height)
-{
- // Network upgrades with an activation height of NO_ACTIVATION_HEIGHT are
- // hidden. This is used when network upgrade implementations are merged
- // without specifying the activation height.
- if (consensusParams.vUpgrades[idx].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) {
- networkUpgrades.push_back(Pair(
- HexInt(NetworkUpgradeInfo[idx].nBranchId),
- NetworkUpgradeDesc(consensusParams, idx, height)));
- }
-}
-
-
-UniValue getblockchaininfo(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 0)
- throw runtime_error(
- "getblockchaininfo\n"
- "Returns an object containing various state info regarding block chain processing.\n"
- "\nNote that when the chain tip is at the last block before a network upgrade activation,\n"
- "consensus.chaintip != consensus.nextblock.\n"
- "\nResult:\n"
- "{\n"
- " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
- " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
- " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
- " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
- " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
- " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
- " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
- " \"size_on_disk\": xxxxxx, (numeric) the estimated size of the block and undo files on disk\n"
- " \"commitments\": xxxxxx, (numeric) the current number of note commitments in the commitment tree\n"
- " \"softforks\": [ (array) status of softforks in progress\n"
- " {\n"
- " \"id\": \"xxxx\", (string) name of softfork\n"
- " \"version\": xx, (numeric) block version\n"
- " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n"
- " \"status\": xx, (boolean) true if threshold reached\n"
- " \"found\": xx, (numeric) number of blocks with the new version found\n"
- " \"required\": xx, (numeric) number of blocks required to trigger\n"
- " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n"
- " },\n"
- " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
- " }, ...\n"
- " ],\n"
- " \"upgrades\": { (object) status of network upgrades\n"
- " \"xxxx\" : { (string) branch ID of the upgrade\n"
- " \"name\": \"xxxx\", (string) name of upgrade\n"
- " \"activationheight\": xxxxxx, (numeric) block height of activation\n"
- " \"status\": \"xxxx\", (string) status of upgrade\n"
- " \"info\": \"xxxx\", (string) additional information about upgrade\n"
- " }, ...\n"
- " },\n"
- " \"consensus\": { (object) branch IDs of the current and upcoming consensus rules\n"
- " \"chaintip\": \"xxxxxxxx\", (string) branch ID used to validate the current chain tip\n"
- " \"nextblock\": \"xxxxxxxx\" (string) branch ID that the next block will be validated under\n"
- " }\n"
- "}\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockchaininfo", "")
- + HelpExampleRpc("getblockchaininfo", "")
- );
-
- LOCK(cs_main);
- double progress;
- if ( ASSETCHAINS_SYMBOL[0] == 0 ) {
- progress = Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.LastTip());
- } else {
- int32_t longestchain = KOMODO_LONGESTCHAIN;//komodo_longestchain();
- progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 1.0;
- }
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("chain", Params().NetworkIDString()));
- obj.push_back(Pair("blocks", (int)chainActive.Height()));
- obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
- obj.push_back(Pair("bestblockhash", chainActive.LastTip()->GetBlockHash().GetHex()));
- obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty()));
- obj.push_back(Pair("verificationprogress", progress));
- obj.push_back(Pair("chainwork", chainActive.LastTip()->nChainWork.GetHex()));
- obj.push_back(Pair("pruned", fPruneMode));
- obj.push_back(Pair("size_on_disk", CalculateCurrentUsage()));
-
- ZCIncrementalMerkleTree tree;
- pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), tree);
- #ifdef __APPLE__
- obj.push_back(Pair("commitments", (uint64_t)tree.size()));
- #else
- obj.push_back(Pair("commitments", tree.size()));
- #endif
-
- CBlockIndex* tip = chainActive.LastTip();
- UniValue valuePools(UniValue::VARR);
- valuePools.push_back(ValuePoolDesc("sprout", tip->nChainSproutValue, boost::none));
- obj.push_back(Pair("valuePools", valuePools));
-
- const Consensus::Params& consensusParams = Params().GetConsensus();
- UniValue softforks(UniValue::VARR);
- softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
- softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
- softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
- obj.push_back(Pair("softforks", softforks));
-
- UniValue upgrades(UniValue::VOBJ);
- for (int i = Consensus::UPGRADE_OVERWINTER; i < Consensus::MAX_NETWORK_UPGRADES; i++) {
- NetworkUpgradeDescPushBack(upgrades, consensusParams, Consensus::UpgradeIndex(i), tip->nHeight);
- }
- obj.push_back(Pair("upgrades", upgrades));
-
- UniValue consensus(UniValue::VOBJ);
- consensus.push_back(Pair("chaintip", HexInt(CurrentEpochBranchId(tip->nHeight, consensusParams))));
- consensus.push_back(Pair("nextblock", HexInt(CurrentEpochBranchId(tip->nHeight + 1, consensusParams))));
- obj.push_back(Pair("consensus", consensus));
-
- if (fPruneMode)
- {
- CBlockIndex *block = chainActive.LastTip();
- while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA))
- block = block->pprev;
-
- obj.push_back(Pair("pruneheight", block->nHeight));
- }
- return obj;
-}
-
-/** Comparison function for sorting the getchaintips heads. */
-struct CompareBlocksByHeight
-{
- bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
- {
- /* Make sure that unequal blocks with the same height do not compare
- equal. Use the pointers themselves to make a distinction. */
-
- if (a->nHeight != b->nHeight)
- return (a->nHeight > b->nHeight);
-
- return a < b;
- }
-};
-
-#include
-
-UniValue getchaintips(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 0)
- throw runtime_error(
- "getchaintips\n"
- "Return information about all known tips in the block tree,"
- " including the main chain as well as orphaned branches.\n"
- "\nResult:\n"
- "[\n"
- " {\n"
- " \"height\": xxxx, (numeric) height of the chain tip\n"
- " \"hash\": \"xxxx\", (string) block hash of the tip\n"
- " \"branchlen\": 0 (numeric) zero for main chain\n"
- " \"status\": \"active\" (string) \"active\" for the main chain\n"
- " },\n"
- " {\n"
- " \"height\": xxxx,\n"
- " \"hash\": \"xxxx\",\n"
- " \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n"
- " \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
- " }\n"
- "]\n"
- "Possible values for status:\n"
- "1. \"invalid\" This branch contains at least one invalid block\n"
- "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
- "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
- "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
- "5. \"active\" This is the tip of the active main chain, which is certainly valid\n"
- "\nExamples:\n"
- + HelpExampleCli("getchaintips", "")
- + HelpExampleRpc("getchaintips", "")
- );
-
- LOCK(cs_main);
-
- /* Build up a list of chain tips. We start with the list of all
- known blocks, and successively remove blocks that appear as pprev
- of another block. */
- /*static pthread_mutex_t mutex; static int32_t didinit;
- if ( didinit == 0 )
- {
- pthread_mutex_init(&mutex,NULL);
- didinit = 1;
- }
- pthread_mutex_lock(&mutex);*/
- std::set setTips;
- int32_t n = 0;
- BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
- {
- n++;
- setTips.insert(item.second);
- }
- fprintf(stderr,"iterations getchaintips %d\n",n);
- n = 0;
- BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
- {
- const CBlockIndex* pprev=0;
- n++;
- if ( item.second != 0 )
- pprev = item.second->pprev;
- if (pprev)
- setTips.erase(pprev);
- }
- fprintf(stderr,"iterations getchaintips %d\n",n);
- //pthread_mutex_unlock(&mutex);
-
- // Always report the currently active tip.
- setTips.insert(chainActive.LastTip());
-
- /* Construct the output array. */
- UniValue res(UniValue::VARR); const CBlockIndex *forked;
- BOOST_FOREACH(const CBlockIndex* block, setTips)
- BOOST_FOREACH(const CBlockIndex* block, setTips)
- {
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("height", block->nHeight));
- obj.push_back(Pair("hash", block->phashBlock->GetHex()));
- forked = chainActive.FindFork(block);
- if ( forked != 0 )
- {
- const int branchLen = block->nHeight - forked->nHeight;
- obj.push_back(Pair("branchlen", branchLen));
-
- string status;
- if (chainActive.Contains(block)) {
- // This block is part of the currently active chain.
- status = "active";
- } else if (block->nStatus & BLOCK_FAILED_MASK) {
- // This block or one of its ancestors is invalid.
- status = "invalid";
- } else if (block->nChainTx == 0) {
- // This block cannot be connected because full block data for it or one of its parents is missing.
- status = "headers-only";
- } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
- // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
- status = "valid-fork";
- } else if (block->IsValid(BLOCK_VALID_TREE)) {
- // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
- status = "valid-headers";
- } else {
- // No clue.
- status = "unknown";
- }
- obj.push_back(Pair("status", status));
- }
- res.push_back(obj);
- }
-
- return res;
-}
-
-UniValue mempoolInfoToJSON()
-{
- UniValue ret(UniValue::VOBJ);
- ret.push_back(Pair("size", (int64_t) mempool.size()));
- ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
- ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage()));
-
- return ret;
-}
-
-UniValue getmempoolinfo(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 0)
- throw runtime_error(
- "getmempoolinfo\n"
- "\nReturns details on the active state of the TX memory pool.\n"
- "\nResult:\n"
- "{\n"
- " \"size\": xxxxx (numeric) Current tx count\n"
- " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n"
- " \"usage\": xxxxx (numeric) Total memory usage for the mempool\n"
- "}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmempoolinfo", "")
- + HelpExampleRpc("getmempoolinfo", "")
- );
-
- return mempoolInfoToJSON();
-}
-
-UniValue invalidateblock(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "invalidateblock \"hash\"\n"
- "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
- "\nArguments:\n"
- "1. hash (string, required) the hash of the block to mark as invalid\n"
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("invalidateblock", "\"blockhash\"")
- + HelpExampleRpc("invalidateblock", "\"blockhash\"")
- );
-
- std::string strHash = params[0].get_str();
- uint256 hash(uint256S(strHash));
- CValidationState state;
-
- {
- LOCK(cs_main);
- if (mapBlockIndex.count(hash) == 0)
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
-
- CBlockIndex* pblockindex = mapBlockIndex[hash];
- InvalidateBlock(state, pblockindex);
- }
-
- if (state.IsValid()) {
- ActivateBestChain(state);
- }
-
- if (!state.IsValid()) {
- throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
- }
-
- return NullUniValue;
-}
-
-UniValue reconsiderblock(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "reconsiderblock \"hash\"\n"
- "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
- "This can be used to undo the effects of invalidateblock.\n"
- "\nArguments:\n"
- "1. hash (string, required) the hash of the block to reconsider\n"
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("reconsiderblock", "\"blockhash\"")
- + HelpExampleRpc("reconsiderblock", "\"blockhash\"")
- );
-
- std::string strHash = params[0].get_str();
- uint256 hash(uint256S(strHash));
- CValidationState state;
-
- {
- LOCK(cs_main);
- if (mapBlockIndex.count(hash) == 0)
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
-
- CBlockIndex* pblockindex = mapBlockIndex[hash];
- ReconsiderBlock(state, pblockindex);
- }
-
- if (state.IsValid()) {
- ActivateBestChain(state);
- }
-
- if (!state.IsValid()) {
- throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
- }
-
- return NullUniValue;
-}
diff --git a/src/serialize.h b/src/serialize.h
index 3d9c3fae6..9d23b469c 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2014 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index dc795ad7a..8067b42b9 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -39,22 +40,6 @@ public:
hashBestSaplingAnchor_ = SaplingMerkleTree::empty_root();
}
- bool GetSproutAnchorAt(const uint256& rt, SproutMerkleTree &tree) const {
- if (rt == SproutMerkleTree::empty_root()) {
- SproutMerkleTree new_tree;
- tree = new_tree;
- return true;
- }
-
- std::map::const_iterator it = mapSproutAnchors_.find(rt);
- if (it == mapSproutAnchors_.end()) {
- return false;
- } else {
- tree = it->second;
- return true;
- }
- }
-
bool GetSaplingAnchorAt(const uint256& rt, SaplingMerkleTree &tree) const {
if (rt == SaplingMerkleTree::empty_root()) {
SaplingMerkleTree new_tree;
@@ -632,7 +617,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits)
CMutableTransaction mtx;
mtx.vjoinsplit.push_back(js2);
- BOOST_CHECK(!cache.HaveJoinSplitRequirements(mtx));
+ BOOST_CHECK(!cache.HaveShieldedRequirements(mtx));
}
{
@@ -642,7 +627,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits)
mtx.vjoinsplit.push_back(js2);
mtx.vjoinsplit.push_back(js1);
- BOOST_CHECK(!cache.HaveJoinSplitRequirements(mtx));
+ BOOST_CHECK(!cache.HaveShieldedRequirements(mtx));
}
{
@@ -650,7 +635,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits)
mtx.vjoinsplit.push_back(js1);
mtx.vjoinsplit.push_back(js2);
- BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx));
+ BOOST_CHECK(cache.HaveShieldedRequirements(mtx));
}
{
@@ -659,7 +644,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits)
mtx.vjoinsplit.push_back(js2);
mtx.vjoinsplit.push_back(js3);
- BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx));
+ BOOST_CHECK(cache.HaveShieldedRequirements(mtx));
}
{
@@ -669,7 +654,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits)
mtx.vjoinsplit.push_back(js2);
mtx.vjoinsplit.push_back(js3);
- BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx));
+ BOOST_CHECK(cache.HaveShieldedRequirements(mtx));
}
}
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 220d6a9b7..390b2bc7b 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2012-2013 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,6 +23,7 @@
using namespace std;
using namespace libzcash;
+//TODO: convert to Hush addresses
static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj";
static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3";
static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw";
@@ -186,41 +188,6 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
}
-BOOST_AUTO_TEST_CASE(zc_address_test)
-{
- for (size_t i = 0; i < 1000; i++) {
- auto sk = SproutSpendingKey::random();
- {
- string sk_string = EncodeSpendingKey(sk);
-
- BOOST_CHECK(sk_string[0] == 'S');
- BOOST_CHECK(sk_string[1] == 'K');
-
- auto spendingkey2 = DecodeSpendingKey(sk_string);
- BOOST_CHECK(IsValidSpendingKey(spendingkey2));
- BOOST_ASSERT(boost::get(&spendingkey2) != nullptr);
- auto sk2 = boost::get(spendingkey2);
- BOOST_CHECK(sk.inner() == sk2.inner());
- }
- {
- auto addr = sk.address();
-
- std::string addr_string = EncodePaymentAddress(addr);
-
- BOOST_CHECK(addr_string[0] == 'z');
- BOOST_CHECK(addr_string[1] == 'c');
-
- auto paymentaddr2 = DecodePaymentAddress(addr_string);
- BOOST_ASSERT(IsValidPaymentAddress(paymentaddr2));
-
- BOOST_ASSERT(boost::get(&paymentaddr2) != nullptr);
- auto addr2 = boost::get(paymentaddr2);
- BOOST_CHECK(addr.a_pk == addr2.a_pk);
- BOOST_CHECK(addr.pk_enc == addr2.pk_enc);
- }
- }
-}
-
BOOST_AUTO_TEST_CASE(zs_address_test)
{
SelectParams(CBaseChainParams::REGTEST);
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
index 1eaade55b..2abe2d782 100644
--- a/src/test/rpc_wallet_tests.cpp
+++ b/src/test/rpc_wallet_tests.cpp
@@ -1,6 +1,7 @@
// Copyright (c) 2013-2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://www.opensource.org/licenses/mit-license.php
#include "rpc/server.h"
#include "rpc/client.h"
@@ -341,38 +342,12 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_validateaddress)
BOOST_CHECK_THROW(CallRPC("z_validateaddress"), runtime_error);
BOOST_CHECK_THROW(CallRPC("z_validateaddress toomany args"), runtime_error);
- // Wallet should be empty
- std::set addrs;
- pwalletMain->GetSproutPaymentAddresses(addrs);
- BOOST_CHECK(addrs.size()==0);
-
// This address is not valid, it belongs to another network
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress ztaaga95QAPyp1kSQ1hD2kguCpzyMHjxWZqaYDEkzbvo7uYQYAw2S8X4Kx98AvhhofMtQL8PAXKHuZsmhRcanavKRKmdCzk"));
UniValue resultObj = retValue.get_obj();
bool b = find_value(resultObj, "isvalid").get_bool();
BOOST_CHECK_EQUAL(b, false);
- // This address is valid, but the spending key is not in this wallet
- BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zcfA19SDAKRYHLoRDoShcoz4nPohqWxuHcqg8WAxsiB2jFrrs6k7oSvst3UZvMYqpMNSRBkxBsnyjjngX5L55FxMzLKach8"));
- resultObj = retValue.get_obj();
- b = find_value(resultObj, "isvalid").get_bool();
- BOOST_CHECK_EQUAL(b, true);
- BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sprout");
- b = find_value(resultObj, "ismine").get_bool();
- BOOST_CHECK_EQUAL(b, false);
-
- // Let's import a spending key to the wallet and validate its payment address
- BOOST_CHECK_NO_THROW(CallRPC("z_importkey SKxoWv77WGwFnUJitQKNEcD636bL4X5Gd6wWmgaA4Q9x8jZBPJXT"));
- BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL"));
- resultObj = retValue.get_obj();
- b = find_value(resultObj, "isvalid").get_bool();
- BOOST_CHECK_EQUAL(b, true);
- BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sprout");
- b = find_value(resultObj, "ismine").get_bool();
- BOOST_CHECK_EQUAL(b, true);
- BOOST_CHECK_EQUAL(find_value(resultObj, "payingkey").get_str(), "f5bb3c888ccc9831e3f6ba06e7528e26a312eec3acc1823be8918b6a3a5e20ad");
- BOOST_CHECK_EQUAL(find_value(resultObj, "transmissionkey").get_str(), "7a58c7132446564e6b810cf895c20537b3528357dc00150a8e201f491efa9c1a");
-
// This Sapling address is not valid, it belongs to another network
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress ztestsapling1knww2nyjc62njkard0jmx7hlsj6twxmxwprn7anvrv4dc2zxanl3nemc0qx2hvplxmd2uau8gyw"));
resultObj = retValue.get_obj();
@@ -398,16 +373,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
{
LOCK2(cs_main, pwalletMain->cs_wallet);
- // wallet should be empty
- std::set addrs;
- pwalletMain->GetSproutPaymentAddresses(addrs);
- BOOST_CHECK(addrs.size()==0);
-
- // wallet should have one key
- libzcash::SproutPaymentAddress addr = pwalletMain->GenerateNewSproutZKey();
- pwalletMain->GetSproutPaymentAddresses(addrs);
- BOOST_CHECK(addrs.size()==1);
-
// Set up paths
boost::filesystem::path tmppath = boost::filesystem::temp_directory_path();
boost::filesystem::path tmpfilename = boost::filesystem::unique_path("%%%%%%%%");
@@ -429,9 +394,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()));
- libzcash::SproutSpendingKey key;
- BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, key));
-
std::string s1 = EncodePaymentAddress(addr);
std::string s2 = EncodeSpendingKey(key);
@@ -474,13 +436,13 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
BOOST_CHECK_THROW(CallRPC("z_importwallet toomany args"), runtime_error);
// create a random key locally
- auto testSpendingKey = libzcash::SproutSpendingKey::random();
+ auto testSpendingKey = libzcash::SaplingSpendingKey::random();
auto testPaymentAddress = testSpendingKey.address();
std::string testAddr = EncodePaymentAddress(testPaymentAddress);
std::string testKey = EncodeSpendingKey(testSpendingKey);
// create test data using the random key
- std::string format_str = "# Wallet dump created by Komodo v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n"
+ std::string format_str = "# Wallet dump created by Hush v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n"
"# * Created on 2016-08-12T21:55:36Z\n"
"# * Best block at time of backup was 0 (0de0a3851fef2d433b9b4f51d4342bdd24c5ddd793eb8fba57189f07e9235d52),\n"
"# mined on 2009-01-03T18:15:05Z\n"
@@ -503,28 +465,31 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
file << std::flush;
// wallet should currently be empty
- std::set addrs;
- pwalletMain->GetSproutPaymentAddresses(addrs);
+ std::set addrs;
+ pwalletMain->GetSaplingPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0);
// import test data from file into wallet
BOOST_CHECK_NO_THROW(CallRPC(string("z_importwallet ") + path));
// wallet should now have one zkey
- pwalletMain->GetSproutPaymentAddresses(addrs);
+ pwalletMain->GetSaplingPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==1);
// check that we have the spending key for the address
+ /*
auto address = DecodePaymentAddress(testAddr);
BOOST_CHECK(IsValidPaymentAddress(address));
BOOST_ASSERT(boost::get(&address) != nullptr);
auto addr = boost::get(address);
BOOST_CHECK(pwalletMain->HaveSproutSpendingKey(addr));
+ */
+
// Verify the spending key is the same as the test data
- libzcash::SproutSpendingKey k;
- BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, k));
- BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k));
+ //libzcash::SproutSpendingKey k;
+ //BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, k));
+ //BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k));
}
@@ -606,9 +571,8 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
// Verify number of addresses stored in wallet is n1+n2
int numAddrs = myaddrs.size();
BOOST_CHECK(numAddrs == (2 * n1) + n2);
- pwalletMain->GetSproutPaymentAddresses(addrs);
pwalletMain->GetSaplingPaymentAddresses(saplingAddrs);
- BOOST_CHECK(addrs.size() + saplingAddrs.size() == numAddrs);
+ BOOST_CHECK(saplingAddrs.size() == numAddrs);
// Ask wallet to list addresses
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
@@ -630,9 +594,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
std::string newaddress = retValue.get_str();
auto address = DecodePaymentAddress(newaddress);
BOOST_CHECK(IsValidPaymentAddress(address));
- BOOST_ASSERT(boost::get(&address) != nullptr);
- auto newAddr = boost::get(address);
- BOOST_CHECK(pwalletMain->HaveSproutSpendingKey(newAddr));
// Check if too many args
BOOST_CHECK_THROW(CallRPC("z_getnewaddress toomanyargs"), runtime_error);
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index b6a6ebc26..eb948f92d 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -1,3 +1,4 @@
+// Copyright (c) 2019-2020 The Hush developers
// Copyright (c) 2011-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/timedata.cpp b/src/timedata.cpp
index 584e0db8c..64a3955ff 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/timedata.h b/src/timedata.h
index 2296baf11..13cff12b3 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -1,4 +1,5 @@
// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 99c76995b..c2eb490da 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -1,5 +1,6 @@
// Copyright (c) 2015-2017 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/torcontrol.h b/src/torcontrol.h
index 72dc82c5b..44611c7b6 100644
--- a/src/torcontrol.h
+++ b/src/torcontrol.h
@@ -1,4 +1,5 @@
// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp
index 8b1acaca9..e1879e1d4 100644
--- a/src/transaction_builder.cpp
+++ b/src/transaction_builder.cpp
@@ -1,7 +1,5 @@
// Copyright (c) 2018 The Zcash developers
// Copyright (c) 2019-2020 The Hush developers
-// Released under the GPLv3
-
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,6 +12,7 @@
#include
#include
#include
+#include "zcash/Note.hpp"
SpendDescriptionInfo::SpendDescriptionInfo(
libzcash::SaplingExpandedSpendingKey expsk,
diff --git a/src/transaction_builder.h b/src/transaction_builder.h
index 49c09294d..39225433a 100644
--- a/src/transaction_builder.h
+++ b/src/transaction_builder.h
@@ -1,4 +1,5 @@
// Copyright (c) 2018 The Zcash developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 46140f546..6fe8bd575 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -67,18 +67,6 @@ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(Get
}
-bool CCoinsViewDB::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const {
- if (rt == SproutMerkleTree::empty_root()) {
- SproutMerkleTree new_tree;
- tree = new_tree;
- return true;
- }
-
- bool read = db.Read(make_pair(DB_SPROUT_ANCHOR, rt), tree);
-
- return read;
-}
-
bool CCoinsViewDB::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
if (rt == SaplingMerkleTree::empty_root()) {
SaplingMerkleTree new_tree;
diff --git a/src/txdb.h b/src/txdb.h
index e089d0190..81c0bb3ad 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -63,7 +63,7 @@ protected:
public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
- bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const;
+ //bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const;
bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const;
bool GetNullifier(const uint256 &nf, ShieldedType type) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 8a99a99e6..2f10856d4 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -513,7 +513,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list
int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag);
extern char ASSETCHAINS_SYMBOL[];
-void CTxMemPool::removeExpired(unsigned int nBlockHeight)
+std::vector CTxMemPool::removeExpired(unsigned int nBlockHeight)
{
CBlockIndex *tipindex;
// Remove expired txs from the mempool
@@ -523,16 +523,23 @@ void CTxMemPool::removeExpired(unsigned int nBlockHeight)
{
const CTransaction& tx = it->GetTx();
tipindex = chainActive.LastTip();
- if (IsExpiredTx(tx, nBlockHeight) || (ASSETCHAINS_SYMBOL[0] == 0 && tipindex != 0 && komodo_validate_interest(tx,tipindex->GetHeight()+1,tipindex->GetMedianTimePast() + 777,0)) < 0)
+
+ bool fInterestNotValidated = ASSETCHAINS_SYMBOL[0] == 0 && tipindex != 0 && komodo_validate_interest(tx,tipindex->GetHeight()+1,tipindex->GetMedianTimePast() + 777,0) < 0;
+ if (IsExpiredTx(tx, nBlockHeight) || fInterestNotValidated)
{
+ if (fInterestNotValidated && tipindex != 0)
+ LogPrintf("Removing interest violate txid.%s nHeight.%d nTime.%u vs locktime.%u\n",tx.GetHash().ToString(),tipindex->GetHeight()+1,tipindex->GetMedianTimePast() + 777,tx.nLockTime);
transactionsToRemove.push_back(tx);
}
}
+ std::vector ids;
for (const CTransaction& tx : transactionsToRemove) {
list removed;
remove(tx, removed, true);
+ ids.push_back(tx.GetHash());
LogPrint("mempool", "Removing expired txid: %s\n", tx.GetHash().ToString());
}
+ return ids;
}
/**
@@ -637,8 +644,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
i++;
}
- boost::unordered_map intermediates;
+ /*
+ boost::unordered_map intermediates;
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
assert(!pcoins->GetNullifier(nf, SPROUT));
@@ -659,6 +667,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
intermediates.insert(std::make_pair(tree.root(), tree));
}
+ */
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
SaplingMerkleTree tree;
diff --git a/src/txmempool.h b/src/txmempool.h
index f8aa0e9a7..59eeb0d98 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -218,7 +218,7 @@ public:
void removeWithAnchor(const uint256 &invalidRoot, ShieldedType type);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx, std::list& removed);
- void removeExpired(unsigned int nBlockHeight);
+ std::vector removeExpired(unsigned int nBlockHeight);
void removeForBlock(const std::vector& vtx, unsigned int nBlockHeight,
std::list& conflicts, bool fCurrentEstimate = true);
void removeWithoutBranchId(uint32_t nMemPoolBranchId);
diff --git a/src/ui_interface.h b/src/ui_interface.h
index ee0fd9113..59a549a9d 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -98,6 +98,9 @@ public:
/** New block has been accepted */
boost::signals2::signal NotifyBlockTip;
+
+ /** Transaction expired */
+ boost::signals2::signal NotifyTxExpiration;
};
extern CClientUIInterface uiInterface;
diff --git a/src/util.h b/src/util.h
index 2e8232871..d1bbdd26d 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index d4bba72ee..132ae82ab 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -20,7 +20,8 @@ static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
static const string SAFE_CHARS[] =
{
CHARS_ALPHA_NUM + " .,;_/:?@()", // SAFE_CHARS_DEFAULT
- CHARS_ALPHA_NUM + " .,;_?@" // SAFE_CHARS_UA_COMMENT
+ CHARS_ALPHA_NUM + " .,;_?@", // SAFE_CHARS_UA_COMMENT
+ CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%" // SAFE_CHARS_URI
};
string SanitizeString(const string& str, int rule)
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index 37a07ea06..2d851093f 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -26,7 +26,8 @@
enum SafeChars
{
SAFE_CHARS_DEFAULT, //!< The full set of allowed chars
- SAFE_CHARS_UA_COMMENT //!< BIP-0014 subset
+ SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset
+ SAFE_CHARS_URI //!< Chars allowed in URIs (RFC 3986)
};
std::string SanitizeFilename(const std::string& str);
diff --git a/src/utiltest.cpp b/src/utiltest.cpp
deleted file mode 100644
index ead7fe6a0..000000000
--- a/src/utiltest.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright (c) 2016 The Zcash developers
-// Copyright (c) 2019-2020 The Hush developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "utiltest.h"
-
-#include "consensus/upgrades.h"
-
-#include
-
-CWalletTx GetValidReceive(ZCJoinSplit& params,
- const libzcash::SproutSpendingKey& sk, CAmount value,
- bool randomInputs,
- int32_t version /* = 2 */) {
- CMutableTransaction mtx;
- mtx.nVersion = version;
- mtx.vin.resize(2);
- if (randomInputs) {
- mtx.vin[0].prevout.hash = GetRandHash();
- mtx.vin[1].prevout.hash = GetRandHash();
- } else {
- mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
- mtx.vin[1].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
- }
- mtx.vin[0].prevout.n = 0;
- mtx.vin[1].prevout.n = 0;
-
- // Generate an ephemeral keypair.
- uint256 joinSplitPubKey;
- unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
- crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
- mtx.joinSplitPubKey = joinSplitPubKey;
-
- std::array inputs = {
- libzcash::JSInput(), // dummy input
- libzcash::JSInput() // dummy input
- };
-
- std::array outputs = {
- libzcash::JSOutput(sk.address(), value),
- libzcash::JSOutput(sk.address(), value)
- };
-
- // Prepare JoinSplits
- uint256 rt;
- JSDescription jsdesc {params, mtx.joinSplitPubKey, rt,
- inputs, outputs, 2*value, 0, false};
- mtx.vjoinsplit.push_back(jsdesc);
-
- if (version >= 4) {
- // Shielded Output
- OutputDescription od;
- mtx.vShieldedOutput.push_back(od);
- }
-
- // Empty output script.
- uint32_t consensusBranchId = SPROUT_BRANCH_ID;
- CScript scriptCode;
- CTransaction signTx(mtx);
- uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
-
- // Add the signature
- assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
- dataToBeSigned.begin(), 32,
- joinSplitPrivKey
- ) == 0);
-
- CTransaction tx {mtx};
- CWalletTx wtx {NULL, tx};
- return wtx;
-}
-
-libzcash::SproutNote GetNote(ZCJoinSplit& params,
- const libzcash::SproutSpendingKey& sk,
- const CTransaction& tx, size_t js, size_t n) {
- ZCNoteDecryption decryptor {sk.receiving_key()};
- auto hSig = tx.vjoinsplit[js].h_sig(params, tx.joinSplitPubKey);
- auto note_pt = libzcash::SproutNotePlaintext::decrypt(
- decryptor,
- tx.vjoinsplit[js].ciphertexts[n],
- tx.vjoinsplit[js].ephemeralKey,
- hSig,
- (unsigned char) n);
- return note_pt.note(sk.address());
-}
-
-CWalletTx GetValidSpend(ZCJoinSplit& params,
- const libzcash::SproutSpendingKey& sk,
- const libzcash::SproutNote& note, CAmount value) {
- CMutableTransaction mtx;
- mtx.vout.resize(2);
- mtx.vout[0].nValue = value;
- mtx.vout[1].nValue = 0;
-
- // Generate an ephemeral keypair.
- uint256 joinSplitPubKey;
- unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
- crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
- mtx.joinSplitPubKey = joinSplitPubKey;
-
- // Fake tree for the unused witness
- SproutMerkleTree tree;
-
- libzcash::JSOutput dummyout;
- libzcash::JSInput dummyin;
-
- {
- if (note.value() > value) {
- libzcash::SproutSpendingKey dummykey = libzcash::SproutSpendingKey::random();
- libzcash::SproutPaymentAddress dummyaddr = dummykey.address();
- dummyout = libzcash::JSOutput(dummyaddr, note.value() - value);
- } else if (note.value() < value) {
- libzcash::SproutSpendingKey dummykey = libzcash::SproutSpendingKey::random();
- libzcash::SproutPaymentAddress dummyaddr = dummykey.address();
- libzcash::SproutNote dummynote(dummyaddr.a_pk, (value - note.value()), uint256(), uint256());
- tree.append(dummynote.cm());
- dummyin = libzcash::JSInput(tree.witness(), dummynote, dummykey);
- }
- }
-
- tree.append(note.cm());
-
- std::array inputs = {
- libzcash::JSInput(tree.witness(), note, sk),
- dummyin
- };
-
- std::array outputs = {
- dummyout, // dummy output
- libzcash::JSOutput() // dummy output
- };
-
- // Prepare JoinSplits
- uint256 rt = tree.root();
- JSDescription jsdesc {params, mtx.joinSplitPubKey, rt,
- inputs, outputs, 0, value, false};
- mtx.vjoinsplit.push_back(jsdesc);
-
- // Empty output script.
- uint32_t consensusBranchId = SPROUT_BRANCH_ID;
- CScript scriptCode;
- CTransaction signTx(mtx);
- uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
-
- // Add the signature
- assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
- dataToBeSigned.begin(), 32,
- joinSplitPrivKey
- ) == 0);
- CTransaction tx {mtx};
- CWalletTx wtx {NULL, tx};
- return wtx;
-}
diff --git a/src/utiltest.h b/src/utiltest.h
deleted file mode 100644
index 327dc7be4..000000000
--- a/src/utiltest.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2016 The Zcash developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "wallet/wallet.h"
-#include "zcash/JoinSplit.hpp"
-#include "zcash/Note.hpp"
-#include "zcash/NoteEncryption.hpp"
-
-CWalletTx GetValidReceive(ZCJoinSplit& params,
- const libzcash::SproutSpendingKey& sk, CAmount value,
- bool randomInputs,
- int32_t version = 2);
-libzcash::SproutNote GetNote(ZCJoinSplit& params,
- const libzcash::SproutSpendingKey& sk,
- const CTransaction& tx, size_t js, size_t n);
-CWalletTx GetValidSpend(ZCJoinSplit& params,
- const libzcash::SproutSpendingKey& sk,
- const libzcash::SproutNote& note, CAmount value);
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 799a60ceb..44b5115d6 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
@@ -138,7 +139,8 @@ void ThreadNotifyWallets(CBlockIndex *pindexLastTip)
while (pindex && pindex != pindexFork) {
// Get the Sprout commitment tree as of the start of this block.
SproutMerkleTree oldSproutTree;
- assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, oldSproutTree));
+ //TODO: how important is oldSproutTree ?
+ //assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, oldSproutTree));
// Get the Sapling commitment tree as of the start of this block.
// We can get this from the `hashFinalSaplingRoot` of the last block
diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp
index 2e77195f3..79eaee5a9 100644
--- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp
+++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp
@@ -46,7 +46,6 @@
#include
#include
-#include "paymentdisclosuredb.h"
int32_t komodo_blockheight(uint256 hash);
using namespace libzcash;
@@ -75,19 +74,17 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress(
boost::optional builder,
CMutableTransaction contextualTx,
std::vector utxoInputs,
- std::vector sproutNoteInputs,
std::vector saplingNoteInputs,
MergeToAddressRecipient recipient,
CAmount fee,
UniValue contextInfo) :
-tx_(contextualTx), utxoInputs_(utxoInputs), sproutNoteInputs_(sproutNoteInputs),
-saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), contextinfo_(contextInfo)
+tx_(contextualTx), utxoInputs_(utxoInputs), saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), contextinfo_(contextInfo)
{
if (fee < 0 || fee > MAX_MONEY) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Fee is out of range");
}
- if (utxoInputs.empty() && sproutNoteInputs.empty() && saplingNoteInputs.empty()) {
+ if (utxoInputs.empty() && saplingNoteInputs.empty()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "No inputs");
}
@@ -95,14 +92,6 @@ saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), context
throw JSONRPCError(RPC_INVALID_PARAMETER, "Recipient parameter missing");
}
- if (sproutNoteInputs.size() > 0 && saplingNoteInputs.size() > 0) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress");
- }
-
- if (sproutNoteInputs.size() > 0 && builder) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Sprout notes are not supported by the TransactionBuilder");
- }
-
isUsingBuilder_ = false;
if (builder) {
isUsingBuilder_ = true;
@@ -133,9 +122,6 @@ saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), context
// Lock UTXOs
lock_utxos();
lock_notes();
-
- // Enable payment disclosure if requested
- paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", true);
}
AsyncRPCOperation_mergetoaddress::~AsyncRPCOperation_mergetoaddress()
@@ -210,31 +196,16 @@ void AsyncRPCOperation_mergetoaddress::main()
unlock_utxos(); // clean up
unlock_notes(); // clean up
-
- // !!! Payment disclosure START
- if (success && paymentDisclosureMode && paymentDisclosureData_.size() > 0) {
- uint256 txidhash = tx_.GetHash();
- std::shared_ptr db = PaymentDisclosureDB::sharedInstance();
- for (PaymentDisclosureKeyInfo p : paymentDisclosureData_) {
- p.first.hash = txidhash;
- if (!db->Put(p.first, p.second)) {
- LogPrint("paymentdisclosure", "%s: Payment Disclosure: Error writing entry to database for key %s\n", getId(), p.first.ToString());
- } else {
- LogPrint("paymentdisclosure", "%s: Payment Disclosure: Successfully added entry to database for key %s\n", getId(), p.first.ToString());
- }
- }
- }
- // !!! Payment disclosure END
}
// Notes:
-// 1. #1359 Currently there is no limit set on the number of joinsplits, so size of tx could be invalid.
+// 1. #1359 Currently there is no limit set on the number of inputs+outputs, so size of tx could be invalid.
// 2. #1277 Spendable notes are not locked, so an operation running in parallel could also try to use them.
bool AsyncRPCOperation_mergetoaddress::main_impl()
{
assert(isToTaddr_ != isToZaddr_);
- bool isPureTaddrOnlyTx = (sproutNoteInputs_.empty() && saplingNoteInputs_.empty() && isToTaddr_);
+ bool isPureTaddrOnlyTx = (saplingNoteInputs_.empty() && isToTaddr_);
CAmount minersFee = fee_;
size_t numInputs = utxoInputs_.size();
@@ -259,9 +230,6 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
}
CAmount z_inputs_total = 0;
- for (const MergeToAddressInputSproutNote& t : sproutNoteInputs_) {
- z_inputs_total += std::get<2>(t);
- }
for (const MergeToAddressInputSaplingNote& t : saplingNoteInputs_) {
z_inputs_total += std::get<2>(t);
@@ -312,7 +280,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
/**
* SCENARIO #0
*
- * Sprout not involved, so we just use the TransactionBuilder and we're done.
+ * Only sapling involved, so we just use the TransactionBuilder and we're done.
*
* This is based on code from AsyncRPCOperation_sendmany::main_impl() and should be refactored.
*/
@@ -429,7 +397,6 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
* END SCENARIO #0
*/
-
/**
* SCENARIO #1
*
@@ -447,337 +414,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
* END SCENARIO #1
*/
-
- // Prepare raw transaction to handle JoinSplits
- CMutableTransaction mtx(tx_);
- crypto_sign_keypair(joinSplitPubKey_.begin(), joinSplitPrivKey_);
- mtx.joinSplitPubKey = joinSplitPubKey_;
- tx_ = CTransaction(mtx);
- std::string hexMemo = std::get<1>(recipient_);
-
-
- /**
- * SCENARIO #2
- *
- * taddrs -> zaddr
- *
- * We only need a single JoinSplit.
- */
- if (sproutNoteInputs_.empty() && isToZaddr_) {
- // Create JoinSplit to target z-addr.
- MergeToAddressJSInfo info;
- info.vpub_old = sendAmount;
- info.vpub_new = 0;
-
- JSOutput jso = JSOutput(boost::get(toPaymentAddress_), sendAmount);
- if (hexMemo.size() > 0) {
- jso.memo = get_memo_from_hex_string(hexMemo);
- }
- info.vjsout.push_back(jso);
-
- UniValue obj(UniValue::VOBJ);
- obj = perform_joinsplit(info);
- sign_send_raw_transaction(obj);
- return true;
- }
- /**
- * END SCENARIO #2
- */
-
-
- // Copy zinputs to more flexible containers
- std::deque zInputsDeque;
- for (const auto& o : sproutNoteInputs_) {
- zInputsDeque.push_back(o);
- }
-
- // When spending notes, take a snapshot of note witnesses and anchors as the treestate will
- // change upon arrival of new blocks which contain joinsplit transactions. This is likely
- // to happen as creating a chained joinsplit transaction can take longer than the block interval.
- {
- LOCK2(cs_main, pwalletMain->cs_wallet);
- for (auto t : sproutNoteInputs_) {
- JSOutPoint jso = std::get<0>(t);
- std::vector vOutPoints = {jso};
- uint256 inputAnchor;
- std::vector> vInputWitnesses;
- pwalletMain->GetSproutNoteWitnesses(vOutPoints, vInputWitnesses, inputAnchor);
- jsopWitnessAnchorMap[jso.ToString()] = MergeToAddressWitnessAnchorData{vInputWitnesses[0], inputAnchor};
- }
- }
-
- /**
- * SCENARIO #3
- *
- * zaddrs -> zaddr
- * taddrs ->
- *
- * zaddrs ->
- * taddrs -> taddr
- *
- * Send to zaddr by chaining JoinSplits together and immediately consuming any change
- * Send to taddr by creating dummy z outputs and accumulating value in a change note
- * which is used to set vpub_new in the last chained joinsplit.
- */
- UniValue obj(UniValue::VOBJ);
- CAmount jsChange = 0; // this is updated after each joinsplit
- int changeOutputIndex = -1; // this is updated after each joinsplit if jsChange > 0
- bool vpubOldProcessed = false; // updated when vpub_old for taddr inputs is set in first joinsplit
- bool vpubNewProcessed = false; // updated when vpub_new for miner fee and taddr outputs is set in last joinsplit
-
- // At this point, we are guaranteed to have at least one input note.
- // Use address of first input note as the temporary change address.
- SproutSpendingKey changeKey = std::get<3>(zInputsDeque.front());
- SproutPaymentAddress changeAddress = changeKey.address();
-
- CAmount vpubOldTarget = 0;
- CAmount vpubNewTarget = 0;
- if (isToTaddr_) {
- vpubNewTarget = z_inputs_total;
- } else {
- if (utxoInputs_.empty()) {
- vpubNewTarget = minersFee;
- } else {
- vpubOldTarget = t_inputs_total - minersFee;
- }
- }
-
- // Keep track of treestate within this transaction
- boost::unordered_map intermediates;
- std::vector previousCommitments;
-
- while (!vpubNewProcessed) {
- MergeToAddressJSInfo info;
- info.vpub_old = 0;
- info.vpub_new = 0;
-
- // Set vpub_old in the first joinsplit
- if (!vpubOldProcessed) {
- if (t_inputs_total < vpubOldTarget) {
- throw JSONRPCError(RPC_WALLET_ERROR,
- strprintf("Insufficient transparent funds for vpub_old %s (miners fee %s, taddr inputs %s)",
- FormatMoney(vpubOldTarget), FormatMoney(minersFee), FormatMoney(t_inputs_total)));
- }
- info.vpub_old += vpubOldTarget; // funds flowing from public pool
- vpubOldProcessed = true;
- }
-
- CAmount jsInputValue = 0;
- uint256 jsAnchor;
- std::vector> witnesses;
-
- JSDescription prevJoinSplit;
-
- // Keep track of previous JoinSplit and its commitments
- if (tx_.vjoinsplit.size() > 0) {
- prevJoinSplit = tx_.vjoinsplit.back();
- }
-
- // If there is no change, the chain has terminated so we can reset the tracked treestate.
- if (jsChange == 0 && tx_.vjoinsplit.size() > 0) {
- intermediates.clear();
- previousCommitments.clear();
- }
-
- //
- // Consume change as the first input of the JoinSplit.
- //
- if (jsChange > 0) {
- LOCK2(cs_main, pwalletMain->cs_wallet);
-
- // Update tree state with previous joinsplit
- SproutMerkleTree tree;
- auto it = intermediates.find(prevJoinSplit.anchor);
- if (it != intermediates.end()) {
- tree = it->second;
- } else if (!pcoinsTip->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Could not find previous JoinSplit anchor");
- }
-
- assert(changeOutputIndex != -1);
- boost::optional changeWitness;
- int n = 0;
- for (const uint256& commitment : prevJoinSplit.commitments) {
- tree.append(commitment);
- previousCommitments.push_back(commitment);
- if (!changeWitness && changeOutputIndex == n++) {
- changeWitness = tree.witness();
- } else if (changeWitness) {
- changeWitness.get().append(commitment);
- }
- }
- if (changeWitness) {
- witnesses.push_back(changeWitness);
- }
- jsAnchor = tree.root();
- intermediates.insert(std::make_pair(tree.root(), tree)); // chained js are interstitial (found in between block boundaries)
-
- // Decrypt the change note's ciphertext to retrieve some data we need
- ZCNoteDecryption decryptor(changeKey.receiving_key());
- auto hSig = prevJoinSplit.h_sig(*pzcashParams, tx_.joinSplitPubKey);
- try {
- SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt(
- decryptor,
- prevJoinSplit.ciphertexts[changeOutputIndex],
- prevJoinSplit.ephemeralKey,
- hSig,
- (unsigned char)changeOutputIndex);
-
- SproutNote note = plaintext.note(changeAddress);
- info.notes.push_back(note);
- info.zkeys.push_back(changeKey);
-
- jsInputValue += plaintext.value();
-
- LogPrint("zrpcunsafe", "%s: spending change (amount=%s)\n",
- getId(),
- FormatMoney(plaintext.value()));
-
- } catch (const std::exception& e) {
- throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error decrypting output note of previous JoinSplit: %s", e.what()));
- }
- }
-
-
- //
- // Consume spendable non-change notes
- //
- std::vector vInputNotes;
- std::vector vInputZKeys;
- std::vector vOutPoints;
- std::vector> vInputWitnesses;
- uint256 inputAnchor;
- int numInputsNeeded = (jsChange > 0) ? 1 : 0;
- while (numInputsNeeded++ < ZC_NUM_JS_INPUTS && zInputsDeque.size() > 0) {
- MergeToAddressInputSproutNote t = zInputsDeque.front();
- JSOutPoint jso = std::get<0>(t);
- SproutNote note = std::get<1>(t);
- CAmount noteFunds = std::get<2>(t);
- SproutSpendingKey zkey = std::get<3>(t);
- zInputsDeque.pop_front();
-
- MergeToAddressWitnessAnchorData wad = jsopWitnessAnchorMap[jso.ToString()];
- vInputWitnesses.push_back(wad.witness);
- if (inputAnchor.IsNull()) {
- inputAnchor = wad.anchor;
- } else if (inputAnchor != wad.anchor) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Selected input notes do not share the same anchor");
- }
-
- vOutPoints.push_back(jso);
- vInputNotes.push_back(note);
- vInputZKeys.push_back(zkey);
-
- jsInputValue += noteFunds;
-
- int wtxHeight = -1;
- int wtxDepth = -1;
- {
- LOCK2(cs_main, pwalletMain->cs_wallet);
- const CWalletTx& wtx = pwalletMain->mapWallet[jso.hash];
- // Zero confirmation notes belong to transactions which have not yet been mined
- if (mapBlockIndex.find(wtx.hashBlock) == mapBlockIndex.end()) {
- throw JSONRPCError(RPC_WALLET_ERROR, strprintf("mapBlockIndex does not contain block hash %s", wtx.hashBlock.ToString()));
- }
- wtxHeight = komodo_blockheight(wtx.hashBlock);
- wtxDepth = wtx.GetDepthInMainChain();
- }
- LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n",
- getId(),
- jso.hash.ToString().substr(0, 10),
- jso.js,
- int(jso.n), // uint8_t
- FormatMoney(noteFunds),
- wtxHeight,
- wtxDepth);
- }
-
- // Add history of previous commitments to witness
- if (vInputNotes.size() > 0) {
- if (vInputWitnesses.size() == 0) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Could not find witness for note commitment");
- }
-
- for (auto& optionalWitness : vInputWitnesses) {
- if (!optionalWitness) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Witness for note commitment is null");
- }
- SproutWitness w = *optionalWitness; // could use .get();
- if (jsChange > 0) {
- for (const uint256& commitment : previousCommitments) {
- w.append(commitment);
- }
- if (jsAnchor != w.root()) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Witness for spendable note does not have same anchor as change input");
- }
- }
- witnesses.push_back(w);
- }
-
- // The jsAnchor is null if this JoinSplit is at the start of a new chain
- if (jsAnchor.IsNull()) {
- jsAnchor = inputAnchor;
- }
-
- // Add spendable notes as inputs
- std::copy(vInputNotes.begin(), vInputNotes.end(), std::back_inserter(info.notes));
- std::copy(vInputZKeys.begin(), vInputZKeys.end(), std::back_inserter(info.zkeys));
- }
-
- // Accumulate change
- jsChange = jsInputValue + info.vpub_old;
-
- // Set vpub_new in the last joinsplit (when there are no more notes to spend)
- if (zInputsDeque.empty()) {
- assert(!vpubNewProcessed);
- if (jsInputValue < vpubNewTarget) {
- throw JSONRPCError(RPC_WALLET_ERROR,
- strprintf("Insufficient funds for vpub_new %s (miners fee %s, taddr inputs %s)",
- FormatMoney(vpubNewTarget), FormatMoney(minersFee), FormatMoney(t_inputs_total)));
- }
- info.vpub_new += vpubNewTarget; // funds flowing back to public pool
- vpubNewProcessed = true;
- jsChange -= vpubNewTarget;
- // If we are merging to a t-addr, there should be no change
- if (isToTaddr_) assert(jsChange == 0);
- }
-
- // create dummy output
- info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new
-
- // create output for any change
- if (jsChange > 0) {
- std::string outputType = "change";
- auto jso = JSOutput(changeAddress, jsChange);
- // If this is the final output, set the target and memo
- if (isToZaddr_ && vpubNewProcessed) {
- outputType = "target";
- jso.addr = boost::get(toPaymentAddress_);
- if (!hexMemo.empty()) {
- jso.memo = get_memo_from_hex_string(hexMemo);
- }
- }
- info.vjsout.push_back(jso);
-
- LogPrint("zrpcunsafe", "%s: generating note for %s (amount=%s)\n",
- getId(),
- outputType,
- FormatMoney(jsChange));
- }
-
- obj = perform_joinsplit(info, witnesses, jsAnchor);
-
- if (jsChange > 0) {
- changeOutputIndex = mta_find_output(obj, 1);
- }
- }
-
- // Sanity check in case changes to code block above exits loop by invoking 'break'
- assert(zInputsDeque.size() == 0);
- assert(vpubNewProcessed);
-
- sign_send_raw_transaction(obj);
- return true;
+ return false;
}
@@ -849,190 +486,6 @@ void AsyncRPCOperation_mergetoaddress::sign_send_raw_transaction(UniValue obj)
tx_ = tx;
}
-
-UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(MergeToAddressJSInfo& info)
-{
- std::vector> witnesses;
- uint256 anchor;
- {
- LOCK(cs_main);
- anchor = pcoinsTip->GetBestAnchor(SPROUT); // As there are no inputs, ask the wallet for the best anchor
- }
- return perform_joinsplit(info, witnesses, anchor);
-}
-
-
-UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(MergeToAddressJSInfo& info, std::vector& outPoints)
-{
- std::vector> witnesses;
- uint256 anchor;
- {
- LOCK(cs_main);
- pwalletMain->GetSproutNoteWitnesses(outPoints, witnesses, anchor);
- }
- return perform_joinsplit(info, witnesses, anchor);
-}
-
-UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(
- MergeToAddressJSInfo& info,
- std::vector> witnesses,
- uint256 anchor)
-{
- if (anchor.IsNull()) {
- throw std::runtime_error("anchor is null");
- }
-
- if (witnesses.size() != info.notes.size()) {
- throw runtime_error("number of notes and witnesses do not match");
- }
-
- if (info.notes.size() != info.zkeys.size()) {
- throw runtime_error("number of notes and spending keys do not match");
- }
-
- for (size_t i = 0; i < witnesses.size(); i++) {
- if (!witnesses[i]) {
- throw runtime_error("joinsplit input could not be found in tree");
- }
- info.vjsin.push_back(JSInput(*witnesses[i], info.notes[i], info.zkeys[i]));
- }
-
- // Make sure there are two inputs and two outputs
- while (info.vjsin.size() < ZC_NUM_JS_INPUTS) {
- info.vjsin.push_back(JSInput());
- }
-
- while (info.vjsout.size() < ZC_NUM_JS_OUTPUTS) {
- info.vjsout.push_back(JSOutput());
- }
-
- if (info.vjsout.size() != ZC_NUM_JS_INPUTS || info.vjsin.size() != ZC_NUM_JS_OUTPUTS) {
- throw runtime_error("unsupported joinsplit input/output counts");
- }
-
- CMutableTransaction mtx(tx_);
-
- LogPrint("zrpcunsafe", "%s: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n",
- getId(),
- tx_.vjoinsplit.size(),
- FormatMoney(info.vpub_old), FormatMoney(info.vpub_new),
- FormatMoney(info.vjsin[0].note.value()), FormatMoney(info.vjsin[1].note.value()),
- FormatMoney(info.vjsout[0].value), FormatMoney(info.vjsout[1].value));
-
- // Generate the proof, this can take over a minute.
- std::array inputs{info.vjsin[0], info.vjsin[1]};
- std::array outputs{info.vjsout[0], info.vjsout[1]};
- std::array inputMap;
- std::array outputMap;
-
- uint256 esk; // payment disclosure - secret
-
- JSDescription jsdesc = JSDescription::Randomized(
- *pzcashParams,
- joinSplitPubKey_,
- anchor,
- inputs,
- outputs,
- inputMap,
- outputMap,
- info.vpub_old,
- info.vpub_new,
- !this->testmode,
- &esk); // parameter expects pointer to esk, so pass in address
- {
- auto verifier = libzcash::ProofVerifier::Strict();
- if (!(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey_))) {
- throw std::runtime_error("error verifying joinsplit");
- }
- }
-
- mtx.vjoinsplit.push_back(jsdesc);
-
- // Empty output script.
- CScript scriptCode;
- CTransaction signTx(mtx);
- uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_);
-
- // Add the signature
- if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
- dataToBeSigned.begin(), 32,
- joinSplitPrivKey_) == 0)) {
- throw std::runtime_error("crypto_sign_detached failed");
- }
-
- // Sanity check
- if (!(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
- dataToBeSigned.begin(), 32,
- mtx.joinSplitPubKey.begin()) == 0)) {
- throw std::runtime_error("crypto_sign_verify_detached failed");
- }
-
- CTransaction rawTx(mtx);
- tx_ = rawTx;
-
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
- ss << rawTx;
-
- std::string encryptedNote1;
- std::string encryptedNote2;
- {
- CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
- ss2 << ((unsigned char)0x00);
- ss2 << jsdesc.ephemeralKey;
- ss2 << jsdesc.ciphertexts[0];
- ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_);
-
- encryptedNote1 = HexStr(ss2.begin(), ss2.end());
- }
- {
- CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
- ss2 << ((unsigned char)0x01);
- ss2 << jsdesc.ephemeralKey;
- ss2 << jsdesc.ciphertexts[1];
- ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_);
-
- encryptedNote2 = HexStr(ss2.begin(), ss2.end());
- }
-
- UniValue arrInputMap(UniValue::VARR);
- UniValue arrOutputMap(UniValue::VARR);
- for (size_t i = 0; i < ZC_NUM_JS_INPUTS; i++) {
- arrInputMap.push_back(static_cast(inputMap[i]));
- }
- for (size_t i = 0; i < ZC_NUM_JS_OUTPUTS; i++) {
- arrOutputMap.push_back(static_cast(outputMap[i]));
- }
-
-
- // !!! Payment disclosure START
- unsigned char buffer[32] = {0};
- memcpy(&buffer[0], &joinSplitPrivKey_[0], 32); // private key in first half of 64 byte buffer
- std::vector vch(&buffer[0], &buffer[0] + 32);
- uint256 joinSplitPrivKey = uint256(vch);
- size_t js_index = tx_.vjoinsplit.size() - 1;
- uint256 placeholder;
- for (int i = 0; i < ZC_NUM_JS_OUTPUTS; i++) {
- uint8_t mapped_index = outputMap[i];
- // placeholder for txid will be filled in later when tx has been finalized and signed.
- PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index};
- JSOutput output = outputs[mapped_index];
- libzcash::SproutPaymentAddress zaddr = output.addr; // randomized output
- PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
- paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));
-
- LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr));
- }
- // !!! Payment disclosure END
-
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("encryptednote1", encryptedNote1));
- obj.push_back(Pair("encryptednote2", encryptedNote2));
- obj.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
- obj.push_back(Pair("inputmap", arrInputMap));
- obj.push_back(Pair("outputmap", arrOutputMap));
- return obj;
-}
-
std::array AsyncRPCOperation_mergetoaddress::get_memo_from_hex_string(std::string s)
{
std::array memo = {{0x00}};
@@ -1099,9 +552,6 @@ void AsyncRPCOperation_mergetoaddress::unlock_utxos() {
*/
void AsyncRPCOperation_mergetoaddress::lock_notes() {
LOCK2(cs_main, pwalletMain->cs_wallet);
- for (auto note : sproutNoteInputs_) {
- pwalletMain->LockNote(std::get<0>(note));
- }
for (auto note : saplingNoteInputs_) {
pwalletMain->LockNote(std::get<0>(note));
}
@@ -1112,9 +562,6 @@ void AsyncRPCOperation_mergetoaddress::lock_notes() {
*/
void AsyncRPCOperation_mergetoaddress::unlock_notes() {
LOCK2(cs_main, pwalletMain->cs_wallet);
- for (auto note : sproutNoteInputs_) {
- pwalletMain->UnlockNote(std::get<0>(note));
- }
for (auto note : saplingNoteInputs_) {
pwalletMain->UnlockNote(std::get<0>(note));
}
diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.h b/src/wallet/asyncrpcoperation_mergetoaddress.h
index be49baff0..69150161e 100644
--- a/src/wallet/asyncrpcoperation_mergetoaddress.h
+++ b/src/wallet/asyncrpcoperation_mergetoaddress.h
@@ -1,4 +1,6 @@
// Copyright (c) 2017 The Zcash developers
+// Copyright (c) 2019-2020 The Hush developers
+
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,7 +24,6 @@
#include "amount.h"
#include "asyncrpcoperation.h"
-#include "paymentdisclosure.h"
#include "primitives/transaction.h"
#include "transaction_builder.h"
#include "wallet.h"
@@ -43,29 +44,11 @@ using namespace libzcash;
// Input UTXO is a tuple of txid, vout, amount, script
typedef std::tuple MergeToAddressInputUTXO;
-// Input JSOP is a tuple of JSOutpoint, note, amount, spending key
-typedef std::tuple MergeToAddressInputSproutNote;
-
typedef std::tuple