Merge branch 'dev' into devmerge
# Conflicts: # src/init.cpp # src/komodo_bitcoind.h # src/komodo_events.h # src/komodo_notary.h # src/komodo_structs.h # src/main.cpp # src/pow.cpp # src/rpcblockchain.cpp
This commit is contained in:
@@ -5,7 +5,7 @@ RUN apt-get -y update && \
|
||||
apt-get -y upgrade && \
|
||||
apt-get -y install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev \
|
||||
unzip python zlib1g-dev wget bsdmainutils automake libssl-dev libprotobuf-dev \
|
||||
protobuf-compiler libqrencode-dev libdb++-dev software-properties-common libcurl4-openssl-dev && \
|
||||
protobuf-compiler libqrencode-dev libdb++-dev software-properties-common libcurl4-openssl-dev curl && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
|
||||
188
Makefile.am
188
Makefile.am
@@ -15,6 +15,7 @@ endif
|
||||
|
||||
BITCOIND_BIN=$(top_builddir)/src/zcashd$(EXEEXT)
|
||||
BITCOIN_CLI_BIN=$(top_builddir)/src/zcash-cli$(EXEEXT)
|
||||
WALLET_UTILITY_BIN=$(top_builddir)/src/wallet-utility$(EXEEXT)
|
||||
BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT)
|
||||
|
||||
if TARGET_DARWIN
|
||||
@@ -32,26 +33,26 @@ endif
|
||||
DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md)
|
||||
|
||||
BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \
|
||||
$(top_srcdir)/contrib/devtools/security-check.py
|
||||
$(top_srcdir)/contrib/devtools/security-check.py
|
||||
|
||||
|
||||
WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \
|
||||
$(top_srcdir)/share/pixmaps/nsis-header.bmp \
|
||||
$(top_srcdir)/share/pixmaps/nsis-wizard.bmp
|
||||
$(top_srcdir)/share/pixmaps/nsis-header.bmp \
|
||||
$(top_srcdir)/share/pixmaps/nsis-wizard.bmp
|
||||
|
||||
if TARGET_DARWIN
|
||||
OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) $(OSX_BASE_LPROJ_DIR) \
|
||||
$(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \
|
||||
$(top_srcdir)/contrib/macdeploy/DS_Store \
|
||||
$(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \
|
||||
$(top_srcdir)/contrib/macdeploy/detached-sig-create.sh
|
||||
$(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \
|
||||
$(top_srcdir)/contrib/macdeploy/DS_Store \
|
||||
$(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \
|
||||
$(top_srcdir)/contrib/macdeploy/detached-sig-create.sh
|
||||
endif
|
||||
|
||||
if TARGET_DARWIN
|
||||
COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \
|
||||
leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \
|
||||
baseline_filtered.info block_test_filtered.info \
|
||||
leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info
|
||||
leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \
|
||||
baseline_filtered.info block_test_filtered.info \
|
||||
leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info
|
||||
# zcash-gtest.info zcash-gtest_filtered.info zcash-gtest_coverage.info
|
||||
else
|
||||
COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \
|
||||
@@ -104,8 +105,8 @@ $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: $(OSX_BASE_LPROJ_DIR
|
||||
$(INSTALL_DATA) $< $@
|
||||
|
||||
OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \
|
||||
$(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \
|
||||
$(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings
|
||||
$(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \
|
||||
$(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings
|
||||
|
||||
endif
|
||||
|
||||
@@ -155,6 +156,9 @@ $(BITCOIND_BIN): FORCE
|
||||
$(BITCOIN_CLI_BIN): FORCE
|
||||
$(MAKE) -C src $(@F)
|
||||
|
||||
$(WALLET_UTILITY_BIN): FORCE
|
||||
$(MAKE) -C src $(@F)
|
||||
|
||||
if USE_LCOV
|
||||
|
||||
baseline.info:
|
||||
@@ -163,27 +167,27 @@ baseline.info:
|
||||
if BUILD_DARWIN
|
||||
baseline_filtered.info: baseline.info
|
||||
$(LCOV) -r $< "/usr/include/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
else
|
||||
baseline_filtered.info: baseline.info
|
||||
$(LCOV) -r $< "/usr/include/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
endif
|
||||
|
||||
leveldb_baseline.info: baseline_filtered.info
|
||||
@@ -192,27 +196,27 @@ leveldb_baseline.info: baseline_filtered.info
|
||||
if BUILD_DARWIN
|
||||
leveldb_baseline_filtered.info: leveldb_baseline.info
|
||||
$(LCOV) -r $< "/usr/include/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
else
|
||||
leveldb_baseline_filtered.info: leveldb_baseline.info
|
||||
$(LCOV) -r $< "/usr/include/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
endif
|
||||
|
||||
baseline_filtered_combined.info: leveldb_baseline_filtered.info baseline_filtered.info
|
||||
@@ -227,27 +231,27 @@ test_bitcoin.info: baseline_filtered_combined.info
|
||||
if BUILD_DARWIN
|
||||
test_bitcoin_filtered.info: test_bitcoin.info
|
||||
$(LCOV) -r $< "/usr/include/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
else
|
||||
test_bitcoin_filtered.info: test_bitcoin.info
|
||||
$(LCOV) -r $< "/usr/include/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
endif
|
||||
|
||||
|
||||
@@ -261,32 +265,32 @@ block_test.info: test_bitcoin_filtered.info
|
||||
if BUILD_DARWIN
|
||||
block_test_filtered.info: block_test.info
|
||||
$(LCOV) -r $< "/usr/include/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
else
|
||||
block_test_filtered.info: block_test.info
|
||||
$(LCOV) -r $< "/usr/include/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
endif
|
||||
|
||||
|
||||
test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info
|
||||
$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@
|
||||
$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@
|
||||
|
||||
if ! BUILD_DARWIN
|
||||
zcash-gtest_coverage.info: baseline_filtered_combined.info zcash-gtest_filtered.info
|
||||
@@ -295,7 +299,7 @@ endif
|
||||
|
||||
if BUILD_DARWIN
|
||||
total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info zcash-gtest_filtered.info block_test_filtered.info
|
||||
$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a zcash-gtest_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
|
||||
$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a zcash-gtest_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
|
||||
else
|
||||
total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info zcash-gtest_filtered.info block_test_filtered.info
|
||||
$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a zcash-gtest_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
|
||||
@@ -303,19 +307,19 @@ endif
|
||||
|
||||
|
||||
test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info
|
||||
$(GENHTML) -s $< -o $(@D)
|
||||
@touch $@
|
||||
$(GENHTML) -s $< -o $(@D)
|
||||
@touch $@
|
||||
|
||||
if TARGET_DARWIN
|
||||
zcash-gtest.coverage/.dirstamp: zcash-gtest_coverage.info
|
||||
$(GENHTML) -s $< -o $(@D)
|
||||
@touch $@
|
||||
$(GENHTML) -s $< -o $(@D)
|
||||
@touch $@
|
||||
cov-zcash: zcash-gtest.coverage/.dirstamp
|
||||
endif
|
||||
|
||||
total.coverage/.dirstamp: total_coverage.info
|
||||
$(GENHTML) -s $< -o $(@D)
|
||||
@touch $@
|
||||
$(GENHTML) -s $< -o $(@D)
|
||||
@touch $@
|
||||
|
||||
if BUILD_DARWIN
|
||||
cov: test_bitcoin.coverage/.dirstamp cov-zcash total.coverage/.dirstamp
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Komodo 1.0.15
|
||||
|
||||
## Komodo with Bitcore
|
||||
This version of Komodo contains Bitcore support for komodo and all its assetchains.
|
||||
## Komodod
|
||||
This software is Komodo client, generally you will use this if you want to mine KMD or setup a full node.
|
||||
It downloads and stores the entire history of Komodo transactions; depending on the speed of your computer and network connection, the synchronization process could take a day or more once the blockchain has reached a significant size.
|
||||
@@ -34,7 +34,7 @@ Dependencies
|
||||
|
||||
```
|
||||
#The following packages are needed:
|
||||
sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python python-zmq zlib1g-dev wget libcurl3-gnutls-dev bsdmainutils automake
|
||||
sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python python-zmq zlib1g-dev wget libcurl4-openssl-dev bsdmainutils automake curl
|
||||
```
|
||||
|
||||
Komodo
|
||||
|
||||
@@ -232,7 +232,7 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS"
|
||||
|
||||
AC_ARG_WITH([utils],
|
||||
[AS_HELP_STRING([--with-utils],
|
||||
[build zcash-cli zcash-tx (default=yes)])],
|
||||
[build zcash-cli zcash-tx wallet-utility (default=yes)])],
|
||||
[build_bitcoin_utils=$withval],
|
||||
[build_bitcoin_utils=yes])
|
||||
|
||||
@@ -805,7 +805,7 @@ AC_MSG_CHECKING([whether to build bitcoind])
|
||||
AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes])
|
||||
AC_MSG_RESULT($build_bitcoind)
|
||||
|
||||
AC_MSG_CHECKING([whether to build utils (zcash-cli zcash-tx)])
|
||||
AC_MSG_CHECKING([whether to build utils (zcash-cli zcash-tx wallet-utility)])
|
||||
AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes])
|
||||
AC_MSG_RESULT($build_bitcoin_utils)
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ testScripts=(
|
||||
'key_import_export.py'
|
||||
'nodehandling.py'
|
||||
'reindex.py'
|
||||
'addressindex.py'
|
||||
'timestampindex.py'
|
||||
'spentindex.py'
|
||||
'decodescript.py'
|
||||
'disablewallet.py'
|
||||
'zcjoinsplit.py'
|
||||
|
||||
349
qa/rpc-tests/addressindex.py
Normal file
349
qa/rpc-tests/addressindex.py
Normal file
@@ -0,0 +1,349 @@
|
||||
#!/usr/bin/env python2
|
||||
# Copyright (c) 2014-2015 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test addressindex generation and fetching
|
||||
#
|
||||
|
||||
import time
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
from test_framework.script import *
|
||||
from test_framework.mininode import *
|
||||
import binascii
|
||||
|
||||
class AddressIndexTest(BitcoinTestFramework):
|
||||
|
||||
def setup_chain(self):
|
||||
print("Initializing test directory "+self.options.tmpdir)
|
||||
initialize_chain_clean(self.options.tmpdir, 4)
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
# Nodes 0/1 are "wallet" nodes
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-relaypriority=0"]))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-addressindex"]))
|
||||
# Nodes 2/3 are used for testing
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-addressindex", "-relaypriority=0"]))
|
||||
self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-addressindex"]))
|
||||
connect_nodes(self.nodes[0], 1)
|
||||
connect_nodes(self.nodes[0], 2)
|
||||
connect_nodes(self.nodes[0], 3)
|
||||
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
print "Mining blocks..."
|
||||
self.nodes[0].generate(105)
|
||||
self.sync_all()
|
||||
|
||||
chain_height = self.nodes[1].getblockcount()
|
||||
assert_equal(chain_height, 105)
|
||||
assert_equal(self.nodes[1].getbalance(), 0)
|
||||
assert_equal(self.nodes[2].getbalance(), 0)
|
||||
|
||||
# Check that balances are correct
|
||||
balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br")
|
||||
assert_equal(balance0["balance"], 0)
|
||||
|
||||
# Check p2pkh and p2sh address indexes
|
||||
print "Testing p2pkh and p2sh address index..."
|
||||
|
||||
txid0 = self.nodes[0].sendtoaddress("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 10)
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
txidb0 = self.nodes[0].sendtoaddress("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 10)
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
txid1 = self.nodes[0].sendtoaddress("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 15)
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
txidb1 = self.nodes[0].sendtoaddress("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 15)
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
txid2 = self.nodes[0].sendtoaddress("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 20)
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
txidb2 = self.nodes[0].sendtoaddress("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 20)
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
self.sync_all()
|
||||
|
||||
txids = self.nodes[1].getaddresstxids("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs")
|
||||
assert_equal(len(txids), 3)
|
||||
assert_equal(txids[0], txid0)
|
||||
assert_equal(txids[1], txid1)
|
||||
assert_equal(txids[2], txid2)
|
||||
|
||||
txidsb = self.nodes[1].getaddresstxids("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br")
|
||||
assert_equal(len(txidsb), 3)
|
||||
assert_equal(txidsb[0], txidb0)
|
||||
assert_equal(txidsb[1], txidb1)
|
||||
assert_equal(txidsb[2], txidb2)
|
||||
|
||||
# Check that limiting by height works
|
||||
print "Testing querying txids by range of block heights.."
|
||||
height_txids = self.nodes[1].getaddresstxids({
|
||||
"addresses": ["2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br"],
|
||||
"start": 105,
|
||||
"end": 110
|
||||
})
|
||||
assert_equal(len(height_txids), 2)
|
||||
assert_equal(height_txids[0], txidb0)
|
||||
assert_equal(height_txids[1], txidb1)
|
||||
|
||||
# Check that multiple addresses works
|
||||
multitxids = self.nodes[1].getaddresstxids({"addresses": ["2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs"]})
|
||||
assert_equal(len(multitxids), 6)
|
||||
assert_equal(multitxids[0], txid0)
|
||||
assert_equal(multitxids[1], txidb0)
|
||||
assert_equal(multitxids[2], txid1)
|
||||
assert_equal(multitxids[3], txidb1)
|
||||
assert_equal(multitxids[4], txid2)
|
||||
assert_equal(multitxids[5], txidb2)
|
||||
|
||||
# Check that balances are correct
|
||||
balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br")
|
||||
assert_equal(balance0["balance"], 45 * 100000000)
|
||||
|
||||
# Check that outputs with the same address will only return one txid
|
||||
print "Testing for txid uniqueness..."
|
||||
addressHash = "6349a418fc4578d10a372b54b45c280cc8c4382f".decode("hex")
|
||||
scriptPubKey = CScript([OP_HASH160, addressHash, OP_EQUAL])
|
||||
unspent = self.nodes[0].listunspent()
|
||||
tx = CTransaction()
|
||||
tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))]
|
||||
tx.vout = [CTxOut(10, scriptPubKey), CTxOut(11, scriptPubKey)]
|
||||
tx.rehash()
|
||||
|
||||
signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8"))
|
||||
sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True)
|
||||
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
txidsmany = self.nodes[1].getaddresstxids("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br")
|
||||
assert_equal(len(txidsmany), 4)
|
||||
assert_equal(txidsmany[3], sent_txid)
|
||||
|
||||
# Check that balances are correct
|
||||
print "Testing balances..."
|
||||
balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br")
|
||||
assert_equal(balance0["balance"], 45 * 100000000 + 21)
|
||||
|
||||
# Check that balances are correct after spending
|
||||
print "Testing balances after spending..."
|
||||
privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG"
|
||||
address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW"
|
||||
addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex")
|
||||
scriptPubKey2 = CScript([OP_DUP, OP_HASH160, addressHash2, OP_EQUALVERIFY, OP_CHECKSIG])
|
||||
self.nodes[0].importprivkey(privkey2)
|
||||
|
||||
unspent = self.nodes[0].listunspent()
|
||||
tx = CTransaction()
|
||||
tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))]
|
||||
amount = unspent[0]["amount"] * 100000000
|
||||
tx.vout = [CTxOut(amount, scriptPubKey2)]
|
||||
tx.rehash()
|
||||
signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8"))
|
||||
spending_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True)
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
balance1 = self.nodes[1].getaddressbalance(address2)
|
||||
assert_equal(balance1["balance"], amount)
|
||||
|
||||
tx = CTransaction()
|
||||
tx.vin = [CTxIn(COutPoint(int(spending_txid, 16), 0))]
|
||||
send_amount = 1 * 100000000 + 12840
|
||||
change_amount = amount - send_amount - 10000
|
||||
tx.vout = [CTxOut(change_amount, scriptPubKey2), CTxOut(send_amount, scriptPubKey)]
|
||||
tx.rehash()
|
||||
|
||||
signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8"))
|
||||
sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True)
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
balance2 = self.nodes[1].getaddressbalance(address2)
|
||||
assert_equal(balance2["balance"], change_amount)
|
||||
|
||||
# Check that deltas are returned correctly
|
||||
deltas = self.nodes[1].getaddressdeltas({"addresses": [address2], "start": 1, "end": 200})
|
||||
balance3 = 0
|
||||
for delta in deltas:
|
||||
balance3 += delta["satoshis"]
|
||||
assert_equal(balance3, change_amount)
|
||||
assert_equal(deltas[0]["address"], address2)
|
||||
assert_equal(deltas[0]["blockindex"], 1)
|
||||
|
||||
# Check that entire range will be queried
|
||||
deltasAll = self.nodes[1].getaddressdeltas({"addresses": [address2]})
|
||||
assert_equal(len(deltasAll), len(deltas))
|
||||
|
||||
# Check that deltas can be returned from range of block heights
|
||||
deltas = self.nodes[1].getaddressdeltas({"addresses": [address2], "start": 113, "end": 113})
|
||||
assert_equal(len(deltas), 1)
|
||||
|
||||
# Check that unspent outputs can be queried
|
||||
print "Testing utxos..."
|
||||
utxos = self.nodes[1].getaddressutxos({"addresses": [address2]})
|
||||
assert_equal(len(utxos), 1)
|
||||
assert_equal(utxos[0]["satoshis"], change_amount)
|
||||
|
||||
# Check that indexes will be updated with a reorg
|
||||
print "Testing reorg..."
|
||||
|
||||
best_hash = self.nodes[0].getbestblockhash()
|
||||
self.nodes[0].invalidateblock(best_hash)
|
||||
self.nodes[1].invalidateblock(best_hash)
|
||||
self.nodes[2].invalidateblock(best_hash)
|
||||
self.nodes[3].invalidateblock(best_hash)
|
||||
self.sync_all()
|
||||
|
||||
balance4 = self.nodes[1].getaddressbalance(address2)
|
||||
assert_equal(balance4, balance1)
|
||||
|
||||
utxos2 = self.nodes[1].getaddressutxos({"addresses": [address2]})
|
||||
assert_equal(len(utxos2), 1)
|
||||
assert_equal(utxos2[0]["satoshis"], amount)
|
||||
|
||||
# Check sorting of utxos
|
||||
self.nodes[2].generate(150)
|
||||
|
||||
txidsort1 = self.nodes[2].sendtoaddress(address2, 50)
|
||||
self.nodes[2].generate(1)
|
||||
txidsort2 = self.nodes[2].sendtoaddress(address2, 50)
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
utxos3 = self.nodes[1].getaddressutxos({"addresses": [address2]})
|
||||
assert_equal(len(utxos3), 3)
|
||||
assert_equal(utxos3[0]["height"], 114)
|
||||
assert_equal(utxos3[1]["height"], 264)
|
||||
assert_equal(utxos3[2]["height"], 265)
|
||||
|
||||
# Check mempool indexing
|
||||
print "Testing mempool indexing..."
|
||||
|
||||
privKey3 = "cVfUn53hAbRrDEuMexyfgDpZPhF7KqXpS8UZevsyTDaugB7HZ3CD"
|
||||
address3 = "mw4ynwhS7MmrQ27hr82kgqu7zryNDK26JB"
|
||||
addressHash3 = "aa9872b5bbcdb511d89e0e11aa27da73fd2c3f50".decode("hex")
|
||||
scriptPubKey3 = CScript([OP_DUP, OP_HASH160, addressHash3, OP_EQUALVERIFY, OP_CHECKSIG])
|
||||
address4 = "2N8oFVB2vThAKury4vnLquW2zVjsYjjAkYQ"
|
||||
scriptPubKey4 = CScript([OP_HASH160, addressHash3, OP_EQUAL])
|
||||
unspent = self.nodes[2].listunspent()
|
||||
|
||||
tx = CTransaction()
|
||||
tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))]
|
||||
amount = unspent[0]["amount"] * 100000000
|
||||
tx.vout = [CTxOut(amount, scriptPubKey3)]
|
||||
tx.rehash()
|
||||
signed_tx = self.nodes[2].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8"))
|
||||
memtxid1 = self.nodes[2].sendrawtransaction(signed_tx["hex"], True)
|
||||
time.sleep(2)
|
||||
|
||||
tx2 = CTransaction()
|
||||
tx2.vin = [CTxIn(COutPoint(int(unspent[1]["txid"], 16), unspent[1]["vout"]))]
|
||||
amount = unspent[1]["amount"] * 100000000
|
||||
tx2.vout = [
|
||||
CTxOut(amount / 4, scriptPubKey3),
|
||||
CTxOut(amount / 4, scriptPubKey3),
|
||||
CTxOut(amount / 4, scriptPubKey4),
|
||||
CTxOut(amount / 4, scriptPubKey4)
|
||||
]
|
||||
tx2.rehash()
|
||||
signed_tx2 = self.nodes[2].signrawtransaction(binascii.hexlify(tx2.serialize()).decode("utf-8"))
|
||||
memtxid2 = self.nodes[2].sendrawtransaction(signed_tx2["hex"], True)
|
||||
time.sleep(2)
|
||||
|
||||
mempool = self.nodes[2].getaddressmempool({"addresses": [address3]})
|
||||
assert_equal(len(mempool), 3)
|
||||
assert_equal(mempool[0]["txid"], memtxid1)
|
||||
assert_equal(mempool[0]["address"], address3)
|
||||
assert_equal(mempool[0]["index"], 0)
|
||||
assert_equal(mempool[1]["txid"], memtxid2)
|
||||
assert_equal(mempool[1]["index"], 0)
|
||||
assert_equal(mempool[2]["txid"], memtxid2)
|
||||
assert_equal(mempool[2]["index"], 1)
|
||||
|
||||
self.nodes[2].generate(1);
|
||||
self.sync_all();
|
||||
mempool2 = self.nodes[2].getaddressmempool({"addresses": [address3]})
|
||||
assert_equal(len(mempool2), 0)
|
||||
|
||||
tx = CTransaction()
|
||||
tx.vin = [
|
||||
CTxIn(COutPoint(int(memtxid2, 16), 0)),
|
||||
CTxIn(COutPoint(int(memtxid2, 16), 1))
|
||||
]
|
||||
tx.vout = [CTxOut(amount / 2 - 10000, scriptPubKey2)]
|
||||
tx.rehash()
|
||||
self.nodes[2].importprivkey(privKey3)
|
||||
signed_tx3 = self.nodes[2].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8"))
|
||||
memtxid3 = self.nodes[2].sendrawtransaction(signed_tx3["hex"], True)
|
||||
time.sleep(2)
|
||||
|
||||
mempool3 = self.nodes[2].getaddressmempool({"addresses": [address3]})
|
||||
assert_equal(len(mempool3), 2)
|
||||
assert_equal(mempool3[0]["prevtxid"], memtxid2)
|
||||
assert_equal(mempool3[0]["prevout"], 0)
|
||||
assert_equal(mempool3[1]["prevtxid"], memtxid2)
|
||||
assert_equal(mempool3[1]["prevout"], 1)
|
||||
|
||||
# sending and receiving to the same address
|
||||
privkey1 = "cQY2s58LhzUCmEXN8jtAp1Etnijx78YRZ466w4ikX1V4UpTpbsf8"
|
||||
address1 = "myAUWSHnwsQrhuMWv4Br6QsCnpB41vFwHn"
|
||||
address1hash = "c192bff751af8efec15135d42bfeedf91a6f3e34".decode("hex")
|
||||
address1script = CScript([OP_DUP, OP_HASH160, address1hash, OP_EQUALVERIFY, OP_CHECKSIG])
|
||||
|
||||
self.nodes[0].sendtoaddress(address1, 10)
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
utxos = self.nodes[1].getaddressutxos({"addresses": [address1]})
|
||||
assert_equal(len(utxos), 1)
|
||||
|
||||
tx = CTransaction()
|
||||
tx.vin = [
|
||||
CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["outputIndex"]))
|
||||
]
|
||||
amount = utxos[0]["satoshis"] - 1000
|
||||
tx.vout = [CTxOut(amount, address1script)]
|
||||
tx.rehash()
|
||||
self.nodes[0].importprivkey(privkey1)
|
||||
signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8"))
|
||||
mem_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True)
|
||||
|
||||
self.sync_all()
|
||||
mempool_deltas = self.nodes[2].getaddressmempool({"addresses": [address1]})
|
||||
assert_equal(len(mempool_deltas), 2)
|
||||
|
||||
# Include chaininfo in results
|
||||
print "Testing results with chain info..."
|
||||
|
||||
deltas_with_info = self.nodes[1].getaddressdeltas({
|
||||
"addresses": [address2],
|
||||
"start": 1,
|
||||
"end": 200,
|
||||
"chainInfo": True
|
||||
})
|
||||
start_block_hash = self.nodes[1].getblockhash(1);
|
||||
end_block_hash = self.nodes[1].getblockhash(200);
|
||||
assert_equal(deltas_with_info["start"]["height"], 1)
|
||||
assert_equal(deltas_with_info["start"]["hash"], start_block_hash)
|
||||
assert_equal(deltas_with_info["end"]["height"], 200)
|
||||
assert_equal(deltas_with_info["end"]["hash"], end_block_hash)
|
||||
|
||||
utxos_with_info = self.nodes[1].getaddressutxos({"addresses": [address2], "chainInfo": True})
|
||||
expected_tip_block_hash = self.nodes[1].getblockhash(267);
|
||||
assert_equal(utxos_with_info["height"], 267)
|
||||
assert_equal(utxos_with_info["hash"], expected_tip_block_hash)
|
||||
|
||||
print "Passed\n"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
AddressIndexTest().main()
|
||||
139
qa/rpc-tests/spentindex.py
Normal file
139
qa/rpc-tests/spentindex.py
Normal file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python2
|
||||
# Copyright (c) 2014-2015 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test addressindex generation and fetching
|
||||
#
|
||||
|
||||
import time
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
from test_framework.script import *
|
||||
from test_framework.mininode import *
|
||||
import binascii
|
||||
|
||||
class SpentIndexTest(BitcoinTestFramework):
|
||||
|
||||
def setup_chain(self):
|
||||
print("Initializing test directory "+self.options.tmpdir)
|
||||
initialize_chain_clean(self.options.tmpdir, 4)
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
# Nodes 0/1 are "wallet" nodes
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-spentindex"]))
|
||||
# Nodes 2/3 are used for testing
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-spentindex"]))
|
||||
self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-spentindex", "-txindex"]))
|
||||
connect_nodes(self.nodes[0], 1)
|
||||
connect_nodes(self.nodes[0], 2)
|
||||
connect_nodes(self.nodes[0], 3)
|
||||
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
print "Mining blocks..."
|
||||
self.nodes[0].generate(105)
|
||||
self.sync_all()
|
||||
|
||||
chain_height = self.nodes[1].getblockcount()
|
||||
assert_equal(chain_height, 105)
|
||||
|
||||
# Check that
|
||||
print "Testing spent index..."
|
||||
|
||||
privkey = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG"
|
||||
address = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW"
|
||||
addressHash = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex")
|
||||
scriptPubKey = CScript([OP_DUP, OP_HASH160, addressHash, OP_EQUALVERIFY, OP_CHECKSIG])
|
||||
unspent = self.nodes[0].listunspent()
|
||||
tx = CTransaction()
|
||||
amount = unspent[0]["amount"] * 100000000
|
||||
tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))]
|
||||
tx.vout = [CTxOut(amount, scriptPubKey)]
|
||||
tx.rehash()
|
||||
|
||||
signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8"))
|
||||
txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True)
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
print "Testing getspentinfo method..."
|
||||
|
||||
# Check that the spentinfo works standalone
|
||||
info = self.nodes[1].getspentinfo({"txid": unspent[0]["txid"], "index": unspent[0]["vout"]})
|
||||
assert_equal(info["txid"], txid)
|
||||
assert_equal(info["index"], 0)
|
||||
assert_equal(info["height"], 106)
|
||||
|
||||
print "Testing getrawtransaction method..."
|
||||
|
||||
# Check that verbose raw transaction includes spent info
|
||||
txVerbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1)
|
||||
assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentTxId"], txid)
|
||||
assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentIndex"], 0)
|
||||
assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentHeight"], 106)
|
||||
|
||||
# Check that verbose raw transaction includes input values
|
||||
txVerbose2 = self.nodes[3].getrawtransaction(txid, 1)
|
||||
assert_equal(txVerbose2["vin"][0]["value"], Decimal(unspent[0]["amount"]))
|
||||
assert_equal(txVerbose2["vin"][0]["valueSat"], amount)
|
||||
|
||||
# Check that verbose raw transaction includes address values and input values
|
||||
privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG"
|
||||
address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW"
|
||||
addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex")
|
||||
scriptPubKey2 = CScript([OP_DUP, OP_HASH160, addressHash2, OP_EQUALVERIFY, OP_CHECKSIG])
|
||||
tx2 = CTransaction()
|
||||
tx2.vin = [CTxIn(COutPoint(int(txid, 16), 0))]
|
||||
tx2.vout = [CTxOut(amount, scriptPubKey2)]
|
||||
tx.rehash()
|
||||
self.nodes[0].importprivkey(privkey)
|
||||
signed_tx2 = self.nodes[0].signrawtransaction(binascii.hexlify(tx2.serialize()).decode("utf-8"))
|
||||
txid2 = self.nodes[0].sendrawtransaction(signed_tx2["hex"], True)
|
||||
|
||||
# Check the mempool index
|
||||
self.sync_all()
|
||||
txVerbose3 = self.nodes[1].getrawtransaction(txid2, 1)
|
||||
assert_equal(txVerbose3["vin"][0]["address"], address2)
|
||||
assert_equal(txVerbose3["vin"][0]["value"], Decimal(unspent[0]["amount"]))
|
||||
assert_equal(txVerbose3["vin"][0]["valueSat"], amount)
|
||||
|
||||
# Check the database index
|
||||
block_hash = self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
txVerbose4 = self.nodes[3].getrawtransaction(txid2, 1)
|
||||
assert_equal(txVerbose4["vin"][0]["address"], address2)
|
||||
assert_equal(txVerbose4["vin"][0]["value"], Decimal(unspent[0]["amount"]))
|
||||
assert_equal(txVerbose4["vin"][0]["valueSat"], amount)
|
||||
|
||||
|
||||
# Check block deltas
|
||||
print "Testing getblockdeltas..."
|
||||
|
||||
block = self.nodes[3].getblockdeltas(block_hash[0])
|
||||
assert_equal(len(block["deltas"]), 2)
|
||||
assert_equal(block["deltas"][0]["index"], 0)
|
||||
assert_equal(len(block["deltas"][0]["inputs"]), 0)
|
||||
assert_equal(len(block["deltas"][0]["outputs"]), 0)
|
||||
assert_equal(block["deltas"][1]["index"], 1)
|
||||
assert_equal(block["deltas"][1]["txid"], txid2)
|
||||
assert_equal(block["deltas"][1]["inputs"][0]["index"], 0)
|
||||
assert_equal(block["deltas"][1]["inputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW")
|
||||
assert_equal(block["deltas"][1]["inputs"][0]["satoshis"], amount * -1)
|
||||
assert_equal(block["deltas"][1]["inputs"][0]["prevtxid"], txid)
|
||||
assert_equal(block["deltas"][1]["inputs"][0]["prevout"], 0)
|
||||
assert_equal(block["deltas"][1]["outputs"][0]["index"], 0)
|
||||
assert_equal(block["deltas"][1]["outputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW")
|
||||
assert_equal(block["deltas"][1]["outputs"][0]["satoshis"], amount)
|
||||
|
||||
print "Passed\n"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
SpentIndexTest().main()
|
||||
61
qa/rpc-tests/timestampindex.py
Normal file
61
qa/rpc-tests/timestampindex.py
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python2
|
||||
# Copyright (c) 2014-2015 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test timestampindex generation and fetching
|
||||
#
|
||||
|
||||
import time
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
|
||||
|
||||
class TimestampIndexTest(BitcoinTestFramework):
|
||||
|
||||
def setup_chain(self):
|
||||
print("Initializing test directory "+self.options.tmpdir)
|
||||
initialize_chain_clean(self.options.tmpdir, 4)
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
# Nodes 0/1 are "wallet" nodes
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-timestampindex"]))
|
||||
# Nodes 2/3 are used for testing
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"]))
|
||||
self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-timestampindex"]))
|
||||
connect_nodes(self.nodes[0], 1)
|
||||
connect_nodes(self.nodes[0], 2)
|
||||
connect_nodes(self.nodes[0], 3)
|
||||
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
print "Mining 25 blocks..."
|
||||
blockhashes = self.nodes[0].generate(25)
|
||||
time.sleep(3)
|
||||
print "Mining 25 blocks..."
|
||||
blockhashes.extend(self.nodes[0].generate(25))
|
||||
time.sleep(3)
|
||||
print "Mining 25 blocks..."
|
||||
blockhashes.extend(self.nodes[0].generate(25))
|
||||
self.sync_all()
|
||||
low = self.nodes[1].getblock(blockhashes[0])["time"]
|
||||
high = low + 76
|
||||
|
||||
print "Checking timestamp index..."
|
||||
hashes = self.nodes[1].getblockhashes(high, low)
|
||||
|
||||
assert_equal(len(hashes), len(blockhashes))
|
||||
|
||||
assert_equal(hashes, blockhashes)
|
||||
|
||||
print "Passed\n"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TimestampIndexTest().main()
|
||||
73
qa/rpc-tests/txindex.py
Normal file
73
qa/rpc-tests/txindex.py
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python2
|
||||
# Copyright (c) 2014-2015 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test txindex generation and fetching
|
||||
#
|
||||
|
||||
import time
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
from test_framework.script import *
|
||||
from test_framework.mininode import *
|
||||
import binascii
|
||||
|
||||
class TxIndexTest(BitcoinTestFramework):
|
||||
|
||||
def setup_chain(self):
|
||||
print("Initializing test directory "+self.options.tmpdir)
|
||||
initialize_chain_clean(self.options.tmpdir, 4)
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
# Nodes 0/1 are "wallet" nodes
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-txindex"]))
|
||||
# Nodes 2/3 are used for testing
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-txindex"]))
|
||||
self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-txindex"]))
|
||||
connect_nodes(self.nodes[0], 1)
|
||||
connect_nodes(self.nodes[0], 2)
|
||||
connect_nodes(self.nodes[0], 3)
|
||||
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
print "Mining blocks..."
|
||||
self.nodes[0].generate(105)
|
||||
self.sync_all()
|
||||
|
||||
chain_height = self.nodes[1].getblockcount()
|
||||
assert_equal(chain_height, 105)
|
||||
|
||||
print "Testing transaction index..."
|
||||
|
||||
privkey = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG"
|
||||
address = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW"
|
||||
addressHash = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex")
|
||||
scriptPubKey = CScript([OP_DUP, OP_HASH160, addressHash, OP_EQUALVERIFY, OP_CHECKSIG])
|
||||
unspent = self.nodes[0].listunspent()
|
||||
tx = CTransaction()
|
||||
amount = unspent[0]["amount"] * 100000000
|
||||
tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))]
|
||||
tx.vout = [CTxOut(amount, scriptPubKey)]
|
||||
tx.rehash()
|
||||
|
||||
signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8"))
|
||||
txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True)
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
# Check verbose raw transaction results
|
||||
verbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1)
|
||||
assert_equal(verbose["vout"][0]["valueSat"], 5000000000);
|
||||
assert_equal(verbose["vout"][0]["value"], 50);
|
||||
|
||||
print "Passed\n"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TxIndexTest().main()
|
||||
0
qa/zcash/create_wallet_200k_utxos.py
Executable file → Normal file
0
qa/zcash/create_wallet_200k_utxos.py
Executable file → Normal file
201
qa/zcash/full-test-suite.sh
Executable file
201
qa/zcash/full-test-suite.sh
Executable file
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python2
|
||||
#
|
||||
# Execute all of the automated tests related to Zcash.
|
||||
#
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
REPOROOT = os.path.dirname(
|
||||
os.path.dirname(
|
||||
os.path.dirname(
|
||||
os.path.abspath(__file__)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def repofile(filename):
|
||||
return os.path.join(REPOROOT, filename)
|
||||
|
||||
|
||||
#
|
||||
# Custom test runners
|
||||
#
|
||||
|
||||
RE_RPATH_RUNPATH = re.compile('No RPATH.*No RUNPATH')
|
||||
RE_FORTIFY_AVAILABLE = re.compile('FORTIFY_SOURCE support available.*Yes')
|
||||
RE_FORTIFY_USED = re.compile('Binary compiled with FORTIFY_SOURCE support.*Yes')
|
||||
|
||||
def test_rpath_runpath(filename):
|
||||
output = subprocess.check_output(
|
||||
[repofile('qa/zcash/checksec.sh'), '--file', repofile(filename)]
|
||||
)
|
||||
if RE_RPATH_RUNPATH.search(output):
|
||||
print('PASS: %s has no RPATH or RUNPATH.' % filename)
|
||||
return True
|
||||
else:
|
||||
print('FAIL: %s has an RPATH or a RUNPATH.' % filename)
|
||||
print(output)
|
||||
return False
|
||||
|
||||
def test_fortify_source(filename):
|
||||
proc = subprocess.Popen(
|
||||
[repofile('qa/zcash/checksec.sh'), '--fortify-file', repofile(filename)],
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
line1 = proc.stdout.readline()
|
||||
line2 = proc.stdout.readline()
|
||||
proc.terminate()
|
||||
if RE_FORTIFY_AVAILABLE.search(line1) and RE_FORTIFY_USED.search(line2):
|
||||
print('PASS: %s has FORTIFY_SOURCE.' % filename)
|
||||
return True
|
||||
else:
|
||||
print('FAIL: %s is missing FORTIFY_SOURCE.' % filename)
|
||||
return False
|
||||
|
||||
def check_security_hardening():
|
||||
ret = True
|
||||
|
||||
# PIE, RELRO, Canary, and NX are tested by make check-security.
|
||||
ret &= subprocess.call(['make', '-C', repofile('src'), 'check-security']) == 0
|
||||
|
||||
ret &= test_rpath_runpath('src/zcashd')
|
||||
ret &= test_rpath_runpath('src/zcash-cli')
|
||||
ret &= test_rpath_runpath('src/zcash-gtest')
|
||||
ret &= test_rpath_runpath('src/zcash-tx')
|
||||
ret &= test_rpath_runpath('src/test/test_bitcoin')
|
||||
ret &= test_rpath_runpath('src/zcash/GenerateParams')
|
||||
|
||||
# NOTE: checksec.sh does not reliably determine whether FORTIFY_SOURCE
|
||||
# is enabled for the entire binary. See issue #915.
|
||||
ret &= test_fortify_source('src/zcashd')
|
||||
ret &= test_fortify_source('src/zcash-cli')
|
||||
ret &= test_fortify_source('src/zcash-gtest')
|
||||
ret &= test_fortify_source('src/zcash-tx')
|
||||
ret &= test_fortify_source('src/test/test_bitcoin')
|
||||
ret &= test_fortify_source('src/zcash/GenerateParams')
|
||||
|
||||
return ret
|
||||
|
||||
def ensure_no_dot_so_in_depends():
|
||||
arch_dir = os.path.join(
|
||||
REPOROOT,
|
||||
'depends',
|
||||
'x86_64-unknown-linux-gnu',
|
||||
)
|
||||
|
||||
exit_code = 0
|
||||
|
||||
if os.path.isdir(arch_dir):
|
||||
lib_dir = os.path.join(arch_dir, 'lib')
|
||||
libraries = os.listdir(lib_dir)
|
||||
|
||||
for lib in libraries:
|
||||
if lib.find(".so") != -1:
|
||||
print lib
|
||||
exit_code = 1
|
||||
else:
|
||||
exit_code = 2
|
||||
print "arch-specific build dir not present: {}".format(arch_dir)
|
||||
print "Did you build the ./depends tree?"
|
||||
print "Are you on a currently unsupported architecture?"
|
||||
|
||||
if exit_code == 0:
|
||||
print "PASS."
|
||||
else:
|
||||
print "FAIL."
|
||||
|
||||
return exit_code == 0
|
||||
|
||||
def util_test():
|
||||
return subprocess.call(
|
||||
[repofile('src/test/bitcoin-util-test.py')],
|
||||
cwd=repofile('src'),
|
||||
env={'PYTHONPATH': repofile('src/test'), 'srcdir': repofile('src')}
|
||||
) == 0
|
||||
|
||||
|
||||
#
|
||||
# Tests
|
||||
#
|
||||
|
||||
STAGES = [
|
||||
'btest',
|
||||
'gtest',
|
||||
'sec-hard',
|
||||
'no-dot-so',
|
||||
'util-test',
|
||||
'secp256k1',
|
||||
'libsnark',
|
||||
'univalue',
|
||||
'rpc',
|
||||
]
|
||||
|
||||
STAGE_COMMANDS = {
|
||||
'btest': [repofile('src/test/test_bitcoin'), '-p'],
|
||||
'gtest': [repofile('src/zcash-gtest')],
|
||||
'sec-hard': check_security_hardening,
|
||||
'no-dot-so': ensure_no_dot_so_in_depends,
|
||||
'util-test': util_test,
|
||||
'secp256k1': ['make', '-C', repofile('src/secp256k1'), 'check'],
|
||||
'libsnark': ['make', '-C', repofile('src'), 'libsnark-tests'],
|
||||
'univalue': ['make', '-C', repofile('src/univalue'), 'check'],
|
||||
'rpc': [repofile('qa/pull-tester/rpc-tests.sh')],
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Test driver
|
||||
#
|
||||
|
||||
def run_stage(stage):
|
||||
print('Running stage %s' % stage)
|
||||
print('=' * (len(stage) + 14))
|
||||
print
|
||||
|
||||
cmd = STAGE_COMMANDS[stage]
|
||||
if type(cmd) == type([]):
|
||||
ret = subprocess.call(cmd) == 0
|
||||
else:
|
||||
ret = cmd()
|
||||
|
||||
print
|
||||
print('-' * (len(stage) + 15))
|
||||
print('Finished stage %s' % stage)
|
||||
print
|
||||
|
||||
return ret
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--list-stages', dest='list', action='store_true')
|
||||
parser.add_argument('stage', nargs='*', default=STAGES,
|
||||
help='One of %s'%STAGES)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Check for list
|
||||
if args.list:
|
||||
for s in STAGES:
|
||||
print(s)
|
||||
sys.exit(0)
|
||||
|
||||
# Check validity of stages
|
||||
for s in args.stage:
|
||||
if s not in STAGES:
|
||||
print("Invalid stage '%s' (choose from %s)" % (s, STAGES))
|
||||
sys.exit(1)
|
||||
|
||||
# Run the stages
|
||||
passed = True
|
||||
for s in args.stage:
|
||||
passed &= run_stage(s)
|
||||
|
||||
if not passed:
|
||||
print("!!! One or more test stages failed !!!")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
184
src/Makefile.am
184
src/Makefile.am
@@ -72,12 +72,12 @@ $(LIBCRYPTOCONDITIONS): $(wildcard cryptoconditions/src/*) $(wildcard cryptocond
|
||||
# Make is not made aware of per-object dependencies to avoid limiting building parallelization
|
||||
# But to build the less dependent modules first, we manually select their order here:
|
||||
EXTRA_LIBRARIES = \
|
||||
crypto/libbitcoin_crypto.a \
|
||||
libbitcoin_util.a \
|
||||
libbitcoin_common.a \
|
||||
libbitcoin_server.a \
|
||||
libbitcoin_cli.a \
|
||||
libzcash.a
|
||||
crypto/libbitcoin_crypto.a \
|
||||
libbitcoin_util.a \
|
||||
libbitcoin_common.a \
|
||||
libbitcoin_server.a \
|
||||
libbitcoin_cli.a \
|
||||
libzcash.a
|
||||
if ENABLE_WALLET
|
||||
BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
|
||||
EXTRA_LIBRARIES += libbitcoin_wallet.a
|
||||
@@ -105,7 +105,10 @@ if BUILD_BITCOIND
|
||||
endif
|
||||
|
||||
if BUILD_BITCOIN_UTILS
|
||||
bin_PROGRAMS += komodo-cli komodo-tx
|
||||
bin_PROGRAMS += komodo-cli komodo-tx
|
||||
if ENABLE_WALLET
|
||||
bin_PROGRAMS += wallet-utility
|
||||
endif
|
||||
endif
|
||||
|
||||
LIBZCASH_H = \
|
||||
@@ -122,6 +125,8 @@ LIBZCASH_H = \
|
||||
.PHONY: FORCE collate-libsnark check-symbols check-security
|
||||
# bitcoin core #
|
||||
BITCOIN_CORE_H = \
|
||||
addressindex.h \
|
||||
spentindex.h \
|
||||
addrman.h \
|
||||
alert.h \
|
||||
amount.h \
|
||||
@@ -235,7 +240,7 @@ BITCOIN_CORE_H = \
|
||||
obj/build.h: FORCE
|
||||
@$(MKDIR_P) $(builddir)/obj
|
||||
@$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \
|
||||
$(abs_top_srcdir)
|
||||
$(abs_top_srcdir)
|
||||
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
|
||||
|
||||
# server: zcashd
|
||||
@@ -292,9 +297,9 @@ LIBBITCOIN_ZMQ=libbitcoin_zmq.a
|
||||
libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
|
||||
libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libbitcoin_zmq_a_SOURCES = \
|
||||
zmq/zmqabstractnotifier.cpp \
|
||||
zmq/zmqnotificationinterface.cpp \
|
||||
zmq/zmqpublishnotifier.cpp
|
||||
zmq/zmqabstractnotifier.cpp \
|
||||
zmq/zmqnotificationinterface.cpp \
|
||||
zmq/zmqpublishnotifier.cpp
|
||||
endif
|
||||
|
||||
if ENABLE_PROTON
|
||||
@@ -336,33 +341,33 @@ libbitcoin_wallet_a_SOURCES = \
|
||||
crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES)
|
||||
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
crypto_libbitcoin_crypto_a_SOURCES = \
|
||||
crypto/common.h \
|
||||
crypto/equihash.cpp \
|
||||
crypto/equihash.h \
|
||||
crypto/equihash.tcc \
|
||||
crypto/hmac_sha256.cpp \
|
||||
crypto/hmac_sha256.h \
|
||||
crypto/hmac_sha512.cpp \
|
||||
crypto/hmac_sha512.h \
|
||||
crypto/ripemd160.cpp \
|
||||
crypto/ripemd160.h \
|
||||
crypto/sha1.cpp \
|
||||
crypto/sha1.h \
|
||||
crypto/sha256.cpp \
|
||||
crypto/sha256.h \
|
||||
crypto/sha512.cpp \
|
||||
crypto/sha512.h
|
||||
crypto/common.h \
|
||||
crypto/equihash.cpp \
|
||||
crypto/equihash.h \
|
||||
crypto/equihash.tcc \
|
||||
crypto/hmac_sha256.cpp \
|
||||
crypto/hmac_sha256.h \
|
||||
crypto/hmac_sha512.cpp \
|
||||
crypto/hmac_sha512.h \
|
||||
crypto/ripemd160.cpp \
|
||||
crypto/ripemd160.h \
|
||||
crypto/sha1.cpp \
|
||||
crypto/sha1.h \
|
||||
crypto/sha256.cpp \
|
||||
crypto/sha256.h \
|
||||
crypto/sha512.cpp \
|
||||
crypto/sha512.h
|
||||
|
||||
if ENABLE_MINING
|
||||
EQUIHASH_TROMP_SOURCES = \
|
||||
pow/tromp/equi_miner.h \
|
||||
pow/tromp/equi.h \
|
||||
pow/tromp/osx_barrier.h
|
||||
pow/tromp/equi_miner.h \
|
||||
pow/tromp/equi.h \
|
||||
pow/tromp/osx_barrier.h
|
||||
|
||||
crypto_libbitcoin_crypto_a_CPPFLAGS += \
|
||||
-DEQUIHASH_TROMP_ATOMIC
|
||||
-DEQUIHASH_TROMP_ATOMIC
|
||||
crypto_libbitcoin_crypto_a_SOURCES += \
|
||||
${EQUIHASH_TROMP_SOURCES}
|
||||
${EQUIHASH_TROMP_SOURCES}
|
||||
endif
|
||||
|
||||
# common: shared between zcashd and non-server tools
|
||||
@@ -402,23 +407,23 @@ libbitcoin_common_a_SOURCES = \
|
||||
libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
||||
libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libbitcoin_util_a_SOURCES = \
|
||||
support/pagelocker.cpp \
|
||||
chainparamsbase.cpp \
|
||||
clientversion.cpp \
|
||||
compat/glibc_sanity.cpp \
|
||||
compat/glibcxx_sanity.cpp \
|
||||
compat/strnlen.cpp \
|
||||
random.cpp \
|
||||
rpcprotocol.cpp \
|
||||
support/cleanse.cpp \
|
||||
sync.cpp \
|
||||
uint256.cpp \
|
||||
util.cpp \
|
||||
utilmoneystr.cpp \
|
||||
utilstrencodings.cpp \
|
||||
utiltime.cpp \
|
||||
$(BITCOIN_CORE_H) \
|
||||
$(LIBZCASH_H)
|
||||
support/pagelocker.cpp \
|
||||
chainparamsbase.cpp \
|
||||
clientversion.cpp \
|
||||
compat/glibc_sanity.cpp \
|
||||
compat/glibcxx_sanity.cpp \
|
||||
compat/strnlen.cpp \
|
||||
random.cpp \
|
||||
rpcprotocol.cpp \
|
||||
support/cleanse.cpp \
|
||||
sync.cpp \
|
||||
uint256.cpp \
|
||||
util.cpp \
|
||||
utilmoneystr.cpp \
|
||||
utilstrencodings.cpp \
|
||||
utiltime.cpp \
|
||||
$(BITCOIN_CORE_H) \
|
||||
$(LIBZCASH_H)
|
||||
|
||||
if GLIBC_BACK_COMPAT
|
||||
libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp
|
||||
@@ -428,9 +433,9 @@ endif
|
||||
libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
||||
libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libbitcoin_cli_a_SOURCES = \
|
||||
rpcclient.cpp \
|
||||
$(BITCOIN_CORE_H) \
|
||||
$(LIBZCASH_H)
|
||||
rpcclient.cpp \
|
||||
$(BITCOIN_CORE_H) \
|
||||
$(LIBZCASH_H)
|
||||
|
||||
nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
|
||||
#
|
||||
@@ -486,23 +491,44 @@ komodo_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS)
|
||||
komodo_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
komodo_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||
|
||||
# wallet-utility binary #
|
||||
if ENABLE_WALLET
|
||||
wallet_utility_SOURCES = wallet-utility.cpp
|
||||
wallet_utility_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
||||
wallet_utility_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
wallet_utility_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||
endif
|
||||
|
||||
if TARGET_WINDOWS
|
||||
komodo_cli_SOURCES += bitcoin-cli-res.rc
|
||||
endif
|
||||
|
||||
komodo_cli_LDADD = \
|
||||
$(LIBBITCOIN_CLI) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
$(BOOST_LIBS) \
|
||||
$(SSL_LIBS) \
|
||||
$(CRYPTO_LIBS) \
|
||||
$(EVENT_LIBS) \
|
||||
$(LIBZCASH) \
|
||||
$(LIBSNARK) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH_LIBS)
|
||||
#
|
||||
$(LIBBITCOIN_CLI) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
$(BOOST_LIBS) \
|
||||
$(SSL_LIBS) \
|
||||
$(CRYPTO_LIBS) \
|
||||
$(EVENT_LIBS) \
|
||||
$(LIBZCASH) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH_LIBS)
|
||||
|
||||
if ENABLE_WALLET
|
||||
wallet_utility_LDADD = \
|
||||
libbitcoin_wallet.a \
|
||||
$(LIBBITCOIN_COMMON) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBSECP256K1) \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
$(BOOST_LIBS) \
|
||||
$(BDB_LIBS) \
|
||||
$(CRYPTO_LIBS) \
|
||||
$(LIBZCASH) \
|
||||
$(LIBSNARK) \
|
||||
$(LIBZCASH_LIBS)
|
||||
endif
|
||||
|
||||
# zcash-tx binary #
|
||||
komodo_tx_SOURCES = komodo-tx.cpp
|
||||
@@ -531,20 +557,20 @@ komodo_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
|
||||
|
||||
# zcash protocol primitives #
|
||||
libzcash_a_SOURCES = \
|
||||
zcash/IncrementalMerkleTree.cpp \
|
||||
zcash/NoteEncryption.cpp \
|
||||
zcash/Address.cpp \
|
||||
zcash/JoinSplit.cpp \
|
||||
zcash/Proof.cpp \
|
||||
zcash/Note.cpp \
|
||||
zcash/prf.cpp \
|
||||
zcash/util.cpp \
|
||||
zcash/circuit/commitment.tcc \
|
||||
zcash/circuit/gadget.tcc \
|
||||
zcash/circuit/merkle.tcc \
|
||||
zcash/circuit/note.tcc \
|
||||
zcash/circuit/prfs.tcc \
|
||||
zcash/circuit/utils.tcc
|
||||
zcash/IncrementalMerkleTree.cpp \
|
||||
zcash/NoteEncryption.cpp \
|
||||
zcash/Address.cpp \
|
||||
zcash/JoinSplit.cpp \
|
||||
zcash/Proof.cpp \
|
||||
zcash/Note.cpp \
|
||||
zcash/prf.cpp \
|
||||
zcash/util.cpp \
|
||||
zcash/circuit/commitment.tcc \
|
||||
zcash/circuit/gadget.tcc \
|
||||
zcash/circuit/merkle.tcc \
|
||||
zcash/circuit/note.tcc \
|
||||
zcash/circuit/prfs.tcc \
|
||||
zcash/circuit/utils.tcc
|
||||
|
||||
libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) $(HARDENED_CXXFLAGS) $(HARDENED_LDFLAGS) -pipe $(SAN_LDFLAGS) -O1 -g -Wstack-protector $(SAN_CXXFLAGS) -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)
|
||||
|
||||
@@ -572,7 +598,7 @@ libzcashconsensus_la_SOURCES = \
|
||||
utilstrencodings.cpp
|
||||
|
||||
if GLIBC_BACK_COMPAT
|
||||
libzcashconsensus_la_SOURCES += compat/glibc_compat.cpp
|
||||
libzcashconsensus_la_SOURCES += compat/glibc_compat.cpp
|
||||
endif
|
||||
|
||||
libzcashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
|
||||
|
||||
@@ -15,87 +15,90 @@ EXTRA_DIST += \
|
||||
test/data/tx394b54bb.hex \
|
||||
test/data/txcreate1.hex \
|
||||
test/data/txcreate2.hex \
|
||||
test/data/txcreatesign.hex
|
||||
test/data/txcreatesign.hex \
|
||||
test/wallet-utility.py \
|
||||
test/data/wallet.dat
|
||||
|
||||
JSON_TEST_FILES = \
|
||||
test/data/script_valid.json \
|
||||
test/data/base58_keys_valid.json \
|
||||
test/data/base58_encode_decode.json \
|
||||
test/data/base58_keys_invalid.json \
|
||||
test/data/script_invalid.json \
|
||||
test/data/tx_invalid.json \
|
||||
test/data/tx_valid.json \
|
||||
test/data/sighash.json \
|
||||
test/data/merkle_roots.json \
|
||||
test/data/merkle_roots_empty.json \
|
||||
test/data/merkle_serialization.json \
|
||||
test/data/merkle_witness_serialization.json \
|
||||
test/data/merkle_path.json \
|
||||
test/data/merkle_commitments.json \
|
||||
test/data/g1_compressed.json \
|
||||
test/data/g2_compressed.json
|
||||
test/data/script_valid.json \
|
||||
test/data/base58_keys_valid.json \
|
||||
test/data/base58_encode_decode.json \
|
||||
test/data/base58_keys_invalid.json \
|
||||
test/data/script_invalid.json \
|
||||
test/data/tx_invalid.json \
|
||||
test/data/tx_valid.json \
|
||||
test/data/sighash.json \
|
||||
test/data/merkle_roots.json \
|
||||
test/data/merkle_roots_empty.json \
|
||||
test/data/merkle_serialization.json \
|
||||
test/data/merkle_witness_serialization.json \
|
||||
test/data/merkle_path.json \
|
||||
test/data/merkle_commitments.json \
|
||||
test/data/g1_compressed.json \
|
||||
test/data/g2_compressed.json
|
||||
|
||||
RAW_TEST_FILES = test/data/alertTests.raw
|
||||
|
||||
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
|
||||
|
||||
BITCOIN_TESTS =\
|
||||
test/arith_uint256_tests.cpp \
|
||||
test/bignum.h \
|
||||
test/addrman_tests.cpp \
|
||||
test/alert_tests.cpp \
|
||||
test/allocator_tests.cpp \
|
||||
test/base32_tests.cpp \
|
||||
test/base58_tests.cpp \
|
||||
test/base64_tests.cpp \
|
||||
test/bip32_tests.cpp \
|
||||
test/bloom_tests.cpp \
|
||||
test/checkblock_tests.cpp \
|
||||
test/Checkpoints_tests.cpp \
|
||||
test/coins_tests.cpp \
|
||||
test/compress_tests.cpp \
|
||||
test/crypto_tests.cpp \
|
||||
test/DoS_tests.cpp \
|
||||
test/equihash_tests.cpp \
|
||||
test/getarg_tests.cpp \
|
||||
test/hash_tests.cpp \
|
||||
test/key_tests.cpp \
|
||||
test/main_tests.cpp \
|
||||
test/mempool_tests.cpp \
|
||||
test/miner_tests.cpp \
|
||||
test/mruset_tests.cpp \
|
||||
test/multisig_tests.cpp \
|
||||
test/netbase_tests.cpp \
|
||||
test/pmt_tests.cpp \
|
||||
test/policyestimator_tests.cpp \
|
||||
test/pow_tests.cpp \
|
||||
test/raii_event_tests.cpp \
|
||||
test/reverselock_tests.cpp \
|
||||
test/rpc_tests.cpp \
|
||||
test/sanity_tests.cpp \
|
||||
test/scheduler_tests.cpp \
|
||||
test/script_P2SH_tests.cpp \
|
||||
test/script_tests.cpp \
|
||||
test/scriptnum_tests.cpp \
|
||||
test/serialize_tests.cpp \
|
||||
test/sighash_tests.cpp \
|
||||
test/sigopcount_tests.cpp \
|
||||
test/skiplist_tests.cpp \
|
||||
test/test_bitcoin.cpp \
|
||||
test/test_bitcoin.h \
|
||||
test/timedata_tests.cpp \
|
||||
test/torcontrol_tests.cpp \
|
||||
test/transaction_tests.cpp \
|
||||
test/uint256_tests.cpp \
|
||||
test/univalue_tests.cpp \
|
||||
test/util_tests.cpp \
|
||||
test/sha256compress_tests.cpp
|
||||
test/arith_uint256_tests.cpp \
|
||||
test/bignum.h \
|
||||
test/addrman_tests.cpp \
|
||||
test/alert_tests.cpp \
|
||||
test/allocator_tests.cpp \
|
||||
test/base32_tests.cpp \
|
||||
test/base58_tests.cpp \
|
||||
test/base64_tests.cpp \
|
||||
test/bip32_tests.cpp \
|
||||
test/bloom_tests.cpp \
|
||||
test/checkblock_tests.cpp \
|
||||
test/Checkpoints_tests.cpp \
|
||||
test/coins_tests.cpp \
|
||||
test/compress_tests.cpp \
|
||||
test/crypto_tests.cpp \
|
||||
test/DoS_tests.cpp \
|
||||
test/equihash_tests.cpp \
|
||||
test/getarg_tests.cpp \
|
||||
test/hash_tests.cpp \
|
||||
test/key_tests.cpp \
|
||||
test/main_tests.cpp \
|
||||
test/mempool_tests.cpp \
|
||||
test/miner_tests.cpp \
|
||||
test/mruset_tests.cpp \
|
||||
test/multisig_tests.cpp \
|
||||
test/netbase_tests.cpp \
|
||||
test/pmt_tests.cpp \
|
||||
test/policyestimator_tests.cpp \
|
||||
test/pow_tests.cpp \
|
||||
test/raii_event_tests.cpp \
|
||||
test/reverselock_tests.cpp \
|
||||
test/rpc_tests.cpp \
|
||||
test/sanity_tests.cpp \
|
||||
test/scheduler_tests.cpp \
|
||||
test/script_P2SH_tests.cpp \
|
||||
test/script_P2PKH_tests.cpp \
|
||||
test/script_tests.cpp \
|
||||
test/scriptnum_tests.cpp \
|
||||
test/serialize_tests.cpp \
|
||||
test/sighash_tests.cpp \
|
||||
test/sigopcount_tests.cpp \
|
||||
test/skiplist_tests.cpp \
|
||||
test/test_bitcoin.cpp \
|
||||
test/test_bitcoin.h \
|
||||
test/timedata_tests.cpp \
|
||||
test/torcontrol_tests.cpp \
|
||||
test/transaction_tests.cpp \
|
||||
test/uint256_tests.cpp \
|
||||
test/univalue_tests.cpp \
|
||||
test/util_tests.cpp \
|
||||
test/sha256compress_tests.cpp
|
||||
|
||||
if ENABLE_WALLET
|
||||
BITCOIN_TESTS += \
|
||||
test/accounting_tests.cpp \
|
||||
wallet/test/wallet_tests.cpp \
|
||||
test/rpc_wallet_tests.cpp
|
||||
test/accounting_tests.cpp \
|
||||
wallet/test/wallet_tests.cpp \
|
||||
test/rpc_wallet_tests.cpp
|
||||
endif
|
||||
|
||||
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
|
||||
@@ -137,6 +140,10 @@ bitcoin_test_clean : FORCE
|
||||
check-local:
|
||||
@echo "Running test/bitcoin-util-test.py..."
|
||||
$(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/bitcoin-util-test.py
|
||||
if ENABLE_WALLET
|
||||
@echo "Running test/wallet-utility.py..."
|
||||
$(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/wallet-utility.py
|
||||
endif
|
||||
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
|
||||
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check
|
||||
|
||||
|
||||
82
src/addressindex.h
Normal file
82
src/addressindex.h
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_ADDRESSINDEX_H
|
||||
#define BITCOIN_ADDRESSINDEX_H
|
||||
|
||||
#include "uint256.h"
|
||||
#include "amount.h"
|
||||
|
||||
struct CMempoolAddressDelta
|
||||
{
|
||||
int64_t time;
|
||||
CAmount amount;
|
||||
uint256 prevhash;
|
||||
unsigned int prevout;
|
||||
|
||||
CMempoolAddressDelta(int64_t t, CAmount a, uint256 hash, unsigned int out) {
|
||||
time = t;
|
||||
amount = a;
|
||||
prevhash = hash;
|
||||
prevout = out;
|
||||
}
|
||||
|
||||
CMempoolAddressDelta(int64_t t, CAmount a) {
|
||||
time = t;
|
||||
amount = a;
|
||||
prevhash.SetNull();
|
||||
prevout = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct CMempoolAddressDeltaKey
|
||||
{
|
||||
int type;
|
||||
uint160 addressBytes;
|
||||
uint256 txhash;
|
||||
unsigned int index;
|
||||
int spending;
|
||||
|
||||
CMempoolAddressDeltaKey(int addressType, uint160 addressHash, uint256 hash, unsigned int i, int s) {
|
||||
type = addressType;
|
||||
addressBytes = addressHash;
|
||||
txhash = hash;
|
||||
index = i;
|
||||
spending = s;
|
||||
}
|
||||
|
||||
CMempoolAddressDeltaKey(int addressType, uint160 addressHash) {
|
||||
type = addressType;
|
||||
addressBytes = addressHash;
|
||||
txhash.SetNull();
|
||||
index = 0;
|
||||
spending = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct CMempoolAddressDeltaKeyCompare
|
||||
{
|
||||
bool operator()(const CMempoolAddressDeltaKey& a, const CMempoolAddressDeltaKey& b) const {
|
||||
if (a.type == b.type) {
|
||||
if (a.addressBytes == b.addressBytes) {
|
||||
if (a.txhash == b.txhash) {
|
||||
if (a.index == b.index) {
|
||||
return a.spending < b.spending;
|
||||
} else {
|
||||
return a.index < b.index;
|
||||
}
|
||||
} else {
|
||||
return a.txhash < b.txhash;
|
||||
}
|
||||
} else {
|
||||
return a.addressBytes < b.addressBytes;
|
||||
}
|
||||
} else {
|
||||
return a.type < b.type;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_ADDRESSINDEX_H
|
||||
@@ -53,3 +53,5 @@ komodo_asset BEER 100000000
|
||||
komodo_asset NINJA 100000000
|
||||
komodo_asset OOT 216000000
|
||||
komodo_asset BNTN 500000000
|
||||
komodo_asset CHAIN 999999
|
||||
komodo_asset PRLPAY 500000000
|
||||
|
||||
@@ -30,6 +30,8 @@ echo $pubkey
|
||||
./komodod -pubkey=$pubkey -ac_name=NINJA -ac_supply=100000000 -addnode=78.47.196.146 &
|
||||
./komodod -pubkey=$pubkey -ac_name=OOT -ac_supply=216000000 -addnode=174.138.107.226 &
|
||||
./komodod -pubkey=$pubkey -ac_name=BNTN -ac_supply=500000000 -addnode=94.130.169.205 &
|
||||
./komodod -pubkey=$pubkey -ac_name=CHAIN -ac_supply=999999 -addnode=78.47.146.222 &
|
||||
./komodod -pubkey=$pubkey -ac_name=PRLPAY -ac_supply=500000000 -addnode=13.250.226.125 &
|
||||
#sleep $delay
|
||||
|
||||
#./komodod -pubkey=$pubkey -ac_name=USD -addnode=78.47.196.146 $1 &
|
||||
|
||||
@@ -275,6 +275,23 @@ CTxDestination CBitcoinAddress::Get() const
|
||||
return CNoDestination();
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const
|
||||
{
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
} else if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) {
|
||||
memcpy(&hashBytes, &vchData[0], 20);
|
||||
type = 1;
|
||||
return true;
|
||||
} else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) {
|
||||
memcpy(&hashBytes, &vchData[0], 20);
|
||||
type = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
|
||||
{
|
||||
if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
|
||||
|
||||
@@ -163,6 +163,7 @@ public:
|
||||
|
||||
CTxDestination Get() const;
|
||||
bool GetKeyID(CKeyID &keyID) const;
|
||||
bool GetIndexKey(uint160& hashBytes, int& type) const;
|
||||
bool IsScript() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -48,10 +48,11 @@ const std::string CLIENT_NAME("MagicBean");
|
||||
#include "build.h"
|
||||
#endif
|
||||
|
||||
//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
|
||||
//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives.
|
||||
#define GIT_ARCHIVE 1
|
||||
#ifdef GIT_ARCHIVE
|
||||
#define GIT_COMMIT_ID "$Format:%h$"
|
||||
#define GIT_COMMIT_DATE "$Format:%cD$"
|
||||
#define GIT_COMMIT_ID "a86845f3dc"
|
||||
#define GIT_COMMIT_DATE "Wed, 21 Feb 2018 16:15:11 +0200"
|
||||
#endif
|
||||
|
||||
#define RENDER_BETA_STRING(num) "-beta" DO_STRINGIZE(num)
|
||||
|
||||
@@ -25,4 +25,6 @@ echo beer; fiat/beer $1 $2 $3 $4
|
||||
echo vote2018; fiat/vote2018 $1 $2 $3 $4
|
||||
echo ninja; fiat/ninja $1 $2 $3 $4
|
||||
echo oot; fiat/oot $1 $2 $3 $4
|
||||
echo bntn: fiat/bntn $1 $2 $3 $4
|
||||
echo bntn; fiat/bntn $1 $2 $3 $4
|
||||
echo chain; fiat/chain $1 $2 $3 $4
|
||||
echo prlpay; fiat/prlpay $1 $2 $3 $4
|
||||
|
||||
2
src/fiat/chain
Executable file
2
src/fiat/chain
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=CHAIN $1 $2 $3 $4 $5 $6
|
||||
2
src/fiat/prlpay
Executable file
2
src/fiat/prlpay
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=PRLPAY $1 $2 $3 $4 $5 $6
|
||||
29
src/init.cpp
29
src/init.cpp
@@ -370,7 +370,9 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)"));
|
||||
#endif
|
||||
strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0));
|
||||
|
||||
strUsage += HelpMessageOpt("-addressindex", strprintf(_("Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses (default: %u)"), DEFAULT_ADDRESSINDEX));
|
||||
strUsage += HelpMessageOpt("-timestampindex", strprintf(_("Maintain a timestamp index for block hashes, used to query blocks hashes by a range of timestamps (default: %u)"), DEFAULT_TIMESTAMPINDEX));
|
||||
strUsage += HelpMessageOpt("-spentindex", strprintf(_("Maintain a full spent index, used to query the spending txid and input index for an outpoint (default: %u)"), DEFAULT_SPENTINDEX));
|
||||
strUsage += HelpMessageGroup(_("Connection options:"));
|
||||
strUsage += HelpMessageOpt("-addnode=<ip>", _("Add a node to connect to and attempt to keep the connection open"));
|
||||
strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100));
|
||||
@@ -627,7 +629,6 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
|
||||
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
|
||||
InitBlockIndex();
|
||||
KOMODO_LOADINGBLOCKS = 0;
|
||||
fprintf(stderr,"KOMODO_LOADINGBLOCKS finished\n");
|
||||
}
|
||||
|
||||
// hardcoded $DATADIR/bootstrap.dat
|
||||
@@ -1365,18 +1366,34 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
}
|
||||
}
|
||||
|
||||
// block tree db settings
|
||||
int dbMaxOpenFiles = GetArg("-dbmaxopenfiles", DEFAULT_DB_MAX_OPEN_FILES);
|
||||
bool dbCompression = GetBoolArg("-dbcompression", DEFAULT_DB_COMPRESSION);
|
||||
|
||||
LogPrintf("Block index database configuration:\n");
|
||||
LogPrintf("* Using %d max open files\n", dbMaxOpenFiles);
|
||||
LogPrintf("* Compression is %s\n", dbCompression ? "enabled" : "disabled");
|
||||
|
||||
// cache size calculations
|
||||
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
|
||||
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
|
||||
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
|
||||
int64_t nBlockTreeDBCache = nTotalCache / 8;
|
||||
if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", true))
|
||||
nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB
|
||||
|
||||
if (GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX) || GetBoolArg("-spentindex", DEFAULT_SPENTINDEX)) {
|
||||
// enable 3/4 of the cache if addressindex and/or spentindex is enabled
|
||||
nBlockTreeDBCache = nTotalCache * 3 / 4;
|
||||
} else {
|
||||
if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", false)) {
|
||||
nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB
|
||||
}
|
||||
}
|
||||
nTotalCache -= nBlockTreeDBCache;
|
||||
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
|
||||
nTotalCache -= nCoinDBCache;
|
||||
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
|
||||
LogPrintf("Cache configuration:\n");
|
||||
LogPrintf("* Max cache setting possible %.1fMiB\n", nMaxDbCache);
|
||||
LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
|
||||
LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
|
||||
LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024));
|
||||
@@ -1397,7 +1414,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
delete pcoinscatcher;
|
||||
delete pblocktree;
|
||||
|
||||
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
|
||||
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex, dbCompression, dbMaxOpenFiles);
|
||||
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
|
||||
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
|
||||
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
|
||||
@@ -1425,7 +1442,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
break;
|
||||
}
|
||||
KOMODO_LOADINGBLOCKS = 0;
|
||||
fprintf(stderr,"KOMODO_LOADINGBLOCKS finished\n");
|
||||
// Check for changed -txindex state
|
||||
if (fTxIndex != GetBoolArg("-txindex", true)) {
|
||||
strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
|
||||
@@ -1488,7 +1504,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
}
|
||||
}
|
||||
KOMODO_LOADINGBLOCKS = 0;
|
||||
fprintf(stderr,"KOMODO_LOADINGBLOCKS finished\n");
|
||||
|
||||
// As LoadBlockIndex can take several minutes, it's possible the user
|
||||
// requested to kill the GUI during the last operation. If so, exit.
|
||||
|
||||
@@ -170,13 +170,13 @@ try_again:
|
||||
init_string(&s);
|
||||
headers = curl_slist_append(0,"Expect:");
|
||||
|
||||
curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
|
||||
curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
|
||||
curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(curl_handle,CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function
|
||||
curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback
|
||||
curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash
|
||||
curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback
|
||||
curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback
|
||||
if ( strncmp(url,"https",5) == 0 )
|
||||
{
|
||||
curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0);
|
||||
@@ -291,22 +291,22 @@ char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *
|
||||
{
|
||||
struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0;
|
||||
if ( (cHandle= *cHandlep) == NULL )
|
||||
*cHandlep = cHandle = curl_easy_init();
|
||||
*cHandlep = cHandle = curl_easy_init();
|
||||
else curl_easy_reset(cHandle);
|
||||
//#ifdef DEBUG
|
||||
//curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
|
||||
//curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
|
||||
//#endif
|
||||
curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
|
||||
curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0);
|
||||
//curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
|
||||
curl_easy_setopt(cHandle,CURLOPT_URL,url);
|
||||
curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
|
||||
curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
|
||||
curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0);
|
||||
//curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
|
||||
curl_easy_setopt(cHandle,CURLOPT_URL,url);
|
||||
curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
|
||||
if ( userpass != 0 && userpass[0] != 0 )
|
||||
curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass);
|
||||
if ( postfields != 0 && postfields[0] != 0 )
|
||||
if ( postfields != 0 && postfields[0] != 0 )
|
||||
{
|
||||
curl_easy_setopt(cHandle,CURLOPT_POST,1);
|
||||
curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
|
||||
curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
|
||||
}
|
||||
if ( hdr0 != NULL && hdr0[0] != 0 )
|
||||
{
|
||||
@@ -426,10 +426,10 @@ int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t
|
||||
char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
|
||||
script = _script;
|
||||
/*params[0] = '[';
|
||||
params[1] = '"';
|
||||
for (i=0; i<32; i++)
|
||||
sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
|
||||
strcat(params,"\", 1]");*/
|
||||
params[1] = '"';
|
||||
for (i=0; i<32; i++)
|
||||
sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
|
||||
strcat(params,"\", 1]");*/
|
||||
sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
|
||||
if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 )
|
||||
return(0);
|
||||
@@ -442,7 +442,7 @@ int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t
|
||||
if ( ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
{
|
||||
jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,KMD_PORT);
|
||||
//printf("userpass.(%s) got (%s)\n",KMDUSERPASS,jsonstr);
|
||||
//printf("userpass.(%s) got (%s)\n",KMDUSERPASS,jsonstr);
|
||||
}
|
||||
}//else jsonstr = _dex_getrawtransaction();
|
||||
else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok
|
||||
@@ -500,54 +500,54 @@ int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t
|
||||
}
|
||||
|
||||
/*uint256 komodo_getblockhash(int32_t height)
|
||||
{
|
||||
uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32];
|
||||
memset(&hash,0,sizeof(hash));
|
||||
sprintf(params,"[%d]",height);
|
||||
if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_PORT)) != 0 )
|
||||
{
|
||||
if ( (result= cJSON_Parse(jsonstr)) != 0 )
|
||||
{
|
||||
if ( (hexstr= jstr(result,(char *)"result")) != 0 )
|
||||
{
|
||||
if ( is_hexstr(hexstr,0) == 64 )
|
||||
{
|
||||
decode_hex(revbuf,32,hexstr);
|
||||
for (i=0; i<32; i++)
|
||||
((uint8_t *)&hash)[i] = revbuf[31-i];
|
||||
}
|
||||
}
|
||||
free_json(result);
|
||||
}
|
||||
printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
|
||||
free(jsonstr);
|
||||
}
|
||||
return(hash);
|
||||
}
|
||||
{
|
||||
uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32];
|
||||
memset(&hash,0,sizeof(hash));
|
||||
sprintf(params,"[%d]",height);
|
||||
if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_PORT)) != 0 )
|
||||
{
|
||||
if ( (result= cJSON_Parse(jsonstr)) != 0 )
|
||||
{
|
||||
if ( (hexstr= jstr(result,(char *)"result")) != 0 )
|
||||
{
|
||||
if ( is_hexstr(hexstr,0) == 64 )
|
||||
{
|
||||
decode_hex(revbuf,32,hexstr);
|
||||
for (i=0; i<32; i++)
|
||||
((uint8_t *)&hash)[i] = revbuf[31-i];
|
||||
}
|
||||
}
|
||||
free_json(result);
|
||||
}
|
||||
printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
|
||||
free(jsonstr);
|
||||
}
|
||||
return(hash);
|
||||
}
|
||||
|
||||
uint256 _komodo_getblockhash(int32_t height);*/
|
||||
uint256 _komodo_getblockhash(int32_t height);*/
|
||||
|
||||
uint64_t komodo_seed(int32_t height)
|
||||
{
|
||||
uint64_t seed = 0;
|
||||
/*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
|
||||
{
|
||||
uint256 hash,zero; CBlockIndex *pindex;
|
||||
memset(&hash,0,sizeof(hash));
|
||||
memset(&zero,0,sizeof(zero));
|
||||
if ( height > 10 )
|
||||
height -= 10;
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
hash = _komodo_getblockhash(height);
|
||||
if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
|
||||
hash = komodo_getblockhash(height);
|
||||
int32_t i;
|
||||
for (i=0; i<32; i++)
|
||||
printf("%02x",((uint8_t *)&hash)[i]);
|
||||
printf(" seed.%d\n",height);
|
||||
seed = arith_uint256(hash.GetHex()).GetLow64();
|
||||
}
|
||||
else*/
|
||||
{
|
||||
uint256 hash,zero; CBlockIndex *pindex;
|
||||
memset(&hash,0,sizeof(hash));
|
||||
memset(&zero,0,sizeof(zero));
|
||||
if ( height > 10 )
|
||||
height -= 10;
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
hash = _komodo_getblockhash(height);
|
||||
if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
|
||||
hash = komodo_getblockhash(height);
|
||||
int32_t i;
|
||||
for (i=0; i<32; i++)
|
||||
printf("%02x",((uint8_t *)&hash)[i]);
|
||||
printf(" seed.%d\n",height);
|
||||
seed = arith_uint256(hash.GetHex()).GetLow64();
|
||||
}
|
||||
else*/
|
||||
{
|
||||
seed = (height << 13) ^ (height << 2);
|
||||
seed <<= 21;
|
||||
@@ -838,13 +838,13 @@ int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *non
|
||||
int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // deprecate
|
||||
{
|
||||
/*int32_t i,n=0;
|
||||
for (i=0; i<width; i++,n++)
|
||||
{
|
||||
if ( height-i <= 0 )
|
||||
break;
|
||||
minerids[i] = komodo_minerid(height - i,0);
|
||||
}
|
||||
return(n);*/
|
||||
for (i=0; i<width; i++,n++)
|
||||
{
|
||||
if ( height-i <= 0 )
|
||||
break;
|
||||
minerids[i] = komodo_minerid(height - i,0);
|
||||
}
|
||||
return(n);*/
|
||||
fprintf(stderr,"komodo_minerids is deprecated\n");
|
||||
return(-1);
|
||||
}
|
||||
@@ -861,12 +861,9 @@ int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t heigh
|
||||
{
|
||||
if ( mids[i] == notaryid )
|
||||
{
|
||||
if ( height > 700000 )
|
||||
{
|
||||
for (j=0; j<66; j++)
|
||||
fprintf(stderr,"%d ",mids[j]);
|
||||
fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
|
||||
}
|
||||
//for (j=0; j<66; j++)
|
||||
// fprintf(stderr,"%d ",mids[j]);
|
||||
//fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
|
||||
if ( height > 792000 )
|
||||
return(-1);
|
||||
else break;
|
||||
|
||||
@@ -85,7 +85,7 @@ void komodo_eventadd_pricefeed(struct komodo_state *sp,char *symbol,int32_t heig
|
||||
komodo_eventadd(sp,height,symbol,KOMODO_EVENT_PRICEFEED,(uint8_t *)&F,(int32_t)(sizeof(F.num) + sizeof(*F.prices) * num));
|
||||
if ( sp != 0 )
|
||||
komodo_pvals(height,prices,num);
|
||||
} else fprintf(stderr,"skip pricefeed[%d]\n",num);
|
||||
} //else fprintf(stderr,"skip pricefeed[%d]\n",num);
|
||||
}
|
||||
|
||||
void komodo_eventadd_opreturn(struct komodo_state *sp,char *symbol,int32_t height,uint256 txid,uint64_t value,uint16_t vout,uint8_t *buf,uint16_t opretlen)
|
||||
@@ -188,28 +188,28 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig
|
||||
|
||||
|
||||
/*void komodo_eventadd_deposit(int32_t actionflag,char *symbol,int32_t height,uint64_t komodoshis,char *fiat,uint64_t fiatoshis,uint8_t rmd160[20],bits256 kmdtxid,uint16_t kmdvout,uint64_t price)
|
||||
{
|
||||
uint8_t opret[512]; uint16_t opretlen;
|
||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_DEPOSIT,kmdtxid,komodoshis,kmdvout,opret,opretlen);
|
||||
}
|
||||
{
|
||||
uint8_t opret[512]; uint16_t opretlen;
|
||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_DEPOSIT,kmdtxid,komodoshis,kmdvout,opret,opretlen);
|
||||
}
|
||||
|
||||
void komodo_eventadd_issued(int32_t actionflag,char *symbol,int32_t height,int32_t fiatheight,bits256 fiattxid,uint16_t fiatvout,bits256 kmdtxid,uint16_t kmdvout,uint64_t fiatoshis)
|
||||
{
|
||||
uint8_t opret[512]; uint16_t opretlen;
|
||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_ISSUED,fiattxid,fiatoshis,fiatvout,opret,opretlen);
|
||||
}
|
||||
void komodo_eventadd_issued(int32_t actionflag,char *symbol,int32_t height,int32_t fiatheight,bits256 fiattxid,uint16_t fiatvout,bits256 kmdtxid,uint16_t kmdvout,uint64_t fiatoshis)
|
||||
{
|
||||
uint8_t opret[512]; uint16_t opretlen;
|
||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_ISSUED,fiattxid,fiatoshis,fiatvout,opret,opretlen);
|
||||
}
|
||||
|
||||
void komodo_eventadd_withdraw(int32_t actionflag,char *symbol,int32_t height,uint64_t komodoshis,char *fiat,uint64_t fiatoshis,uint8_t rmd160[20],bits256 fiattxid,int32_t fiatvout,uint64_t price)
|
||||
{
|
||||
uint8_t opret[512]; uint16_t opretlen;
|
||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_WITHDRAW,fiattxid,fiatoshis,fiatvout,opret,opretlen);
|
||||
}
|
||||
void komodo_eventadd_withdraw(int32_t actionflag,char *symbol,int32_t height,uint64_t komodoshis,char *fiat,uint64_t fiatoshis,uint8_t rmd160[20],bits256 fiattxid,int32_t fiatvout,uint64_t price)
|
||||
{
|
||||
uint8_t opret[512]; uint16_t opretlen;
|
||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_WITHDRAW,fiattxid,fiatoshis,fiatvout,opret,opretlen);
|
||||
}
|
||||
|
||||
void komodo_eventadd_redeemed(int32_t actionflag,char *symbol,int32_t height,bits256 kmdtxid,uint16_t kmdvout,int32_t fiatheight,bits256 fiattxid,uint16_t fiatvout,uint64_t komodoshis)
|
||||
{
|
||||
uint8_t opret[512]; uint16_t opretlen;
|
||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_REDEEMED,kmdtxid,komodoshis,kmdvout,opret,opretlen);
|
||||
}*/
|
||||
void komodo_eventadd_redeemed(int32_t actionflag,char *symbol,int32_t height,bits256 kmdtxid,uint16_t kmdvout,int32_t fiatheight,bits256 fiattxid,uint16_t fiatvout,uint64_t komodoshis)
|
||||
{
|
||||
uint8_t opret[512]; uint16_t opretlen;
|
||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_REDEEMED,kmdtxid,komodoshis,kmdvout,opret,opretlen);
|
||||
}*/
|
||||
|
||||
// process events
|
||||
//
|
||||
|
||||
@@ -436,6 +436,7 @@ int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,in
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *notarized_desttxidp)
|
||||
{
|
||||
struct notarized_checkpoint *np = 0; int32_t i=0,flag = 0; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
|
||||
|
||||
@@ -27,14 +27,14 @@ void HandleError(const leveldb::Status& status)
|
||||
throw leveldb_error("Unknown database error");
|
||||
}
|
||||
|
||||
static leveldb::Options GetOptions(size_t nCacheSize)
|
||||
static leveldb::Options GetOptions(size_t nCacheSize, bool compression, int maxOpenFiles)
|
||||
{
|
||||
leveldb::Options options;
|
||||
options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
|
||||
options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
|
||||
options.filter_policy = leveldb::NewBloomFilterPolicy(10);
|
||||
options.compression = leveldb::kNoCompression;
|
||||
options.max_open_files = 64;
|
||||
options.compression = compression ? leveldb::kSnappyCompression : leveldb::kNoCompression;
|
||||
options.max_open_files = maxOpenFiles;
|
||||
if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
|
||||
// LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
|
||||
// on corruption in later versions.
|
||||
@@ -43,14 +43,14 @@ static leveldb::Options GetOptions(size_t nCacheSize)
|
||||
return options;
|
||||
}
|
||||
|
||||
CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe)
|
||||
CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool compression, int maxOpenFiles)
|
||||
{
|
||||
penv = NULL;
|
||||
readoptions.verify_checksums = true;
|
||||
iteroptions.verify_checksums = true;
|
||||
iteroptions.fill_cache = false;
|
||||
syncoptions.sync = true;
|
||||
options = GetOptions(nCacheSize);
|
||||
options = GetOptions(nCacheSize, compression, maxOpenFiles);
|
||||
options.create_if_missing = true;
|
||||
if (fMemory) {
|
||||
penv = leveldb::NewMemEnv(leveldb::Env::Default());
|
||||
|
||||
@@ -86,7 +86,7 @@ private:
|
||||
leveldb::DB* pdb;
|
||||
|
||||
public:
|
||||
CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
|
||||
CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool compression = false, int maxOpenFiles = 64);
|
||||
~CLevelDBWrapper();
|
||||
|
||||
template <typename K, typename V>
|
||||
|
||||
306
src/main.cpp
306
src/main.cpp
@@ -68,6 +68,9 @@ bool fExperimentalMode = false;
|
||||
bool fImporting = false;
|
||||
bool fReindex = false;
|
||||
bool fTxIndex = false;
|
||||
bool fAddressIndex = false;
|
||||
bool fTimestampIndex = false;
|
||||
bool fSpentIndex = false;
|
||||
bool fHavePruned = false;
|
||||
bool fPruneMode = false;
|
||||
bool fIsBareMultisigStd = true;
|
||||
@@ -1484,6 +1487,16 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
if ( komodo_is_notarytx(tx) == 0 )
|
||||
KOMODO_ON_DEMAND++;
|
||||
pool.addUnchecked(hash, entry, !IsInitialBlockDownload());
|
||||
|
||||
// Add memory address index
|
||||
if (fAddressIndex) {
|
||||
pool.addAddressIndex(entry, view);
|
||||
}
|
||||
|
||||
// Add memory spent index
|
||||
if (fSpentIndex) {
|
||||
pool.addSpentIndex(entry, view);
|
||||
}
|
||||
}
|
||||
|
||||
SyncWithWallets(tx, NULL);
|
||||
@@ -1491,6 +1504,55 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes)
|
||||
{
|
||||
if (!fTimestampIndex)
|
||||
return error("Timestamp index not enabled");
|
||||
|
||||
if (!pblocktree->ReadTimestampIndex(high, low, fActiveOnly, hashes))
|
||||
return error("Unable to get hashes for timestamps");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
|
||||
{
|
||||
if (!fSpentIndex)
|
||||
return false;
|
||||
|
||||
if (mempool.getSpentIndex(key, value))
|
||||
return true;
|
||||
|
||||
if (!pblocktree->ReadSpentIndex(key, value))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetAddressIndex(uint160 addressHash, int type,
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex, int start, int end)
|
||||
{
|
||||
if (!fAddressIndex)
|
||||
return error("address index not enabled");
|
||||
|
||||
if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex, start, end))
|
||||
return error("unable to get txids for address");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetAddressUnspent(uint160 addressHash, int type,
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs)
|
||||
{
|
||||
if (!fAddressIndex)
|
||||
return error("address index not enabled");
|
||||
|
||||
if (!pblocktree->ReadAddressUnspentIndex(addressHash, type, unspentOutputs))
|
||||
return error("unable to get txids for address");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
|
||||
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
|
||||
{
|
||||
@@ -2187,7 +2249,6 @@ namespace {
|
||||
catch (const std::exception& e) {
|
||||
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
||||
}
|
||||
|
||||
// Verify checksum
|
||||
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
|
||||
hasher << hashBlock;
|
||||
@@ -2269,11 +2330,44 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
|
||||
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
|
||||
return error("DisconnectBlock(): block and undo data inconsistent");
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressUnspentIndex;
|
||||
std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> > spentIndex;
|
||||
|
||||
// undo transactions in reverse order
|
||||
for (int i = block.vtx.size() - 1; i >= 0; i--) {
|
||||
const CTransaction &tx = block.vtx[i];
|
||||
uint256 hash = tx.GetHash();
|
||||
if (fAddressIndex) {
|
||||
|
||||
for (unsigned int k = tx.vout.size(); k-- > 0;) {
|
||||
const CTxOut &out = tx.vout[k];
|
||||
|
||||
if (out.scriptPubKey.IsPayToScriptHash()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
|
||||
|
||||
// undo receiving activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue));
|
||||
|
||||
// undo unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), hash, k), CAddressUnspentValue()));
|
||||
|
||||
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
|
||||
|
||||
// undo receiving activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue));
|
||||
|
||||
// undo unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), hash, k), CAddressUnspentValue()));
|
||||
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check that all outputs are available and match the outputs in the block itself
|
||||
// exactly.
|
||||
@@ -2311,6 +2405,39 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
const CTxInUndo &undo = txundo.vprevout[j];
|
||||
if (!ApplyTxInUndo(undo, view, out))
|
||||
fClean = false;
|
||||
|
||||
const CTxIn input = tx.vin[j];
|
||||
|
||||
if (fSpentIndex) {
|
||||
// undo and delete the spent index
|
||||
spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue()));
|
||||
}
|
||||
|
||||
if (fAddressIndex) {
|
||||
const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
|
||||
if (prevout.scriptPubKey.IsPayToScriptHash()) {
|
||||
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);
|
||||
|
||||
// undo spending activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
|
||||
|
||||
// restore unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight)));
|
||||
|
||||
|
||||
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);
|
||||
|
||||
// undo spending activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
|
||||
|
||||
// restore unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight)));
|
||||
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2326,6 +2453,14 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fAddressIndex) {
|
||||
if (!pblocktree->EraseAddressIndex(addressIndex)) {
|
||||
return AbortNode(state, "Failed to delete address index");
|
||||
}
|
||||
if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) {
|
||||
return AbortNode(state, "Failed to write address unspent index");
|
||||
}
|
||||
}
|
||||
return fClean;
|
||||
}
|
||||
|
||||
@@ -2429,7 +2564,7 @@ static int64_t nTimeIndex = 0;
|
||||
static int64_t nTimeCallbacks = 0;
|
||||
static int64_t nTimeTotal = 0;
|
||||
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck)
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck,bool fCheckPOW)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
|
||||
@@ -2447,7 +2582,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
auto disabledVerifier = libzcash::ProofVerifier::Disabled();
|
||||
|
||||
// Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in
|
||||
if (!CheckBlock(pindex->nHeight,pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, 1, !fJustCheck)) //!fJustCheck, !fJustCheck))
|
||||
if (!CheckBlock(pindex->nHeight,pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, fCheckPOW, !fJustCheck)) //!fJustCheck, !fJustCheck))
|
||||
return false;
|
||||
|
||||
// verify that the view's current state corresponds to the previous block
|
||||
@@ -2497,7 +2632,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
|
||||
vPos.reserve(block.vtx.size());
|
||||
blockundo.vtxundo.reserve(block.vtx.size() - 1);
|
||||
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressUnspentIndex;
|
||||
std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> > spentIndex;
|
||||
// Construct the incremental merkle tree at the current
|
||||
// block position,
|
||||
auto old_tree_root = view.GetBestAnchor();
|
||||
@@ -2524,6 +2661,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||
{
|
||||
const CTransaction &tx = block.vtx[i];
|
||||
const uint256 txhash = tx.GetHash();
|
||||
nInputs += tx.vin.size();
|
||||
nSigOps += GetLegacySigOpCount(tx);
|
||||
if (nSigOps > MAX_BLOCK_SIGOPS)
|
||||
@@ -2540,7 +2678,42 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
if (!view.HaveJoinSplitRequirements(tx))
|
||||
return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"),
|
||||
REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met");
|
||||
if (fAddressIndex || fSpentIndex)
|
||||
{
|
||||
for (size_t j = 0; j < tx.vin.size(); j++) {
|
||||
|
||||
const CTxIn input = tx.vin[j];
|
||||
const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
|
||||
uint160 hashBytes;
|
||||
int addressType;
|
||||
|
||||
if (prevout.scriptPubKey.IsPayToScriptHash()) {
|
||||
hashBytes = uint160(vector <unsigned char>(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
|
||||
addressType = 2;
|
||||
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||
hashBytes = uint160(vector <unsigned char>(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
|
||||
addressType = 1;
|
||||
} else {
|
||||
hashBytes.SetNull();
|
||||
addressType = 0;
|
||||
}
|
||||
|
||||
if (fAddressIndex && addressType > 0) {
|
||||
// record spending activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
|
||||
|
||||
// remove address from unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue()));
|
||||
}
|
||||
|
||||
if (fSpentIndex) {
|
||||
// add the spent index to determine the txid and input that spent an output
|
||||
// and to find the amount and address from an input
|
||||
spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Add in sigops done by pay-to-script-hash inputs;
|
||||
// this is to prevent a "rogue miner" from creating
|
||||
// an incredibly-expensive-to-validate block.
|
||||
@@ -2562,6 +2735,36 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
return false;
|
||||
control.Add(vChecks);
|
||||
}
|
||||
|
||||
if (fAddressIndex) {
|
||||
for (unsigned int k = 0; k < tx.vout.size(); k++) {
|
||||
const CTxOut &out = tx.vout[k];
|
||||
|
||||
if (out.scriptPubKey.IsPayToScriptHash()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
|
||||
|
||||
// record receiving activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
|
||||
|
||||
// record unspent output
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
|
||||
|
||||
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
|
||||
|
||||
// record receiving activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
|
||||
|
||||
// record unspent output
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
|
||||
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
// komodo_earned_interest(pindex->nHeight,sum);
|
||||
CTxUndo undoDummy;
|
||||
@@ -2654,6 +2857,40 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
if (fTxIndex)
|
||||
if (!pblocktree->WriteTxIndex(vPos))
|
||||
return AbortNode(state, "Failed to write transaction index");
|
||||
if (fAddressIndex) {
|
||||
if (!pblocktree->WriteAddressIndex(addressIndex)) {
|
||||
return AbortNode(state, "Failed to write address index");
|
||||
}
|
||||
|
||||
if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) {
|
||||
return AbortNode(state, "Failed to write address unspent index");
|
||||
}
|
||||
}
|
||||
|
||||
if (fSpentIndex)
|
||||
if (!pblocktree->UpdateSpentIndex(spentIndex))
|
||||
return AbortNode(state, "Failed to write transaction index");
|
||||
|
||||
if (fTimestampIndex) {
|
||||
unsigned int logicalTS = pindex->nTime;
|
||||
unsigned int prevLogicalTS = 0;
|
||||
|
||||
// retrieve logical timestamp of the previous block
|
||||
if (pindex->pprev)
|
||||
if (!pblocktree->ReadTimestampBlockIndex(pindex->pprev->GetBlockHash(), prevLogicalTS))
|
||||
LogPrintf("%s: Failed to read previous block's logical timestamp\n", __func__);
|
||||
|
||||
if (logicalTS <= prevLogicalTS) {
|
||||
logicalTS = prevLogicalTS + 1;
|
||||
LogPrintf("%s: Previous logical timestamp is newer Actual[%d] prevLogical[%d] Logical[%d]\n", __func__, pindex->nTime, prevLogicalTS, logicalTS);
|
||||
}
|
||||
|
||||
if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(logicalTS, pindex->GetBlockHash())))
|
||||
return AbortNode(state, "Failed to write timestamp index");
|
||||
|
||||
if (!pblocktree->WriteTimestampBlockIndex(CTimestampBlockIndexKey(pindex->GetBlockHash()), CTimestampBlockIndexValue(logicalTS)))
|
||||
return AbortNode(state, "Failed to write blockhash index");
|
||||
}
|
||||
|
||||
// add this block to the view's block chain
|
||||
view.SetBestBlock(pindex->GetBlockHash());
|
||||
@@ -2923,7 +3160,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
|
||||
LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
|
||||
{
|
||||
CCoinsViewCache view(pcoinsTip);
|
||||
bool rv = ConnectBlock(*pblock, state, pindexNew, view);
|
||||
bool rv = ConnectBlock(*pblock, state, pindexNew, view, false, true);
|
||||
GetMainSignals().BlockChecked(*pblock, state);
|
||||
if (!rv) {
|
||||
if (state.IsInvalid())
|
||||
@@ -3536,18 +3773,18 @@ int32_t komodo_reverify_blockcheck(CValidationState& state,int32_t height,CBlock
|
||||
{
|
||||
fprintf(stderr,"possible fork: tip.%d longest.%d newblock.%d lag.%d blocktime.%u\n",tipindex->nHeight,KOMODO_LONGESTCHAIN,height,(int32_t)(GetAdjustedTime() - tipindex->nTime),tipindex->nTime);
|
||||
/*KOMODO_REWIND = tipindex->nHeight - 11;
|
||||
rewindtarget = tipindex->nHeight - 11;
|
||||
fprintf(stderr,"rewindtarget <- %d\n",rewindtarget);
|
||||
oneshot = 1;
|
||||
while ( rewindtarget > 0 && (tipindex= chainActive.Tip()) != 0 && tipindex->nHeight > rewindtarget )
|
||||
{
|
||||
fprintf(stderr,"%d ",(int32_t)tipindex->nHeight);
|
||||
InvalidateBlock(state,tipindex);
|
||||
if ( !DisconnectTip(state) )
|
||||
break;
|
||||
}
|
||||
tipindex = chainActive.Tip();
|
||||
fprintf(stderr,"rewind done to %d\n",tipindex!=0?tipindex->nHeight:-1);*/
|
||||
rewindtarget = tipindex->nHeight - 11;
|
||||
fprintf(stderr,"rewindtarget <- %d\n",rewindtarget);
|
||||
oneshot = 1;
|
||||
while ( rewindtarget > 0 && (tipindex= chainActive.Tip()) != 0 && tipindex->nHeight > rewindtarget )
|
||||
{
|
||||
fprintf(stderr,"%d ",(int32_t)tipindex->nHeight);
|
||||
InvalidateBlock(state,tipindex);
|
||||
if ( !DisconnectTip(state) )
|
||||
break;
|
||||
}
|
||||
tipindex = chainActive.Tip();
|
||||
fprintf(stderr,"rewind done to %d\n",tipindex!=0?tipindex->nHeight:-1);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3564,15 +3801,15 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat
|
||||
// Check that the header is valid (particularly PoW). This is mostly
|
||||
// redundant with the call in AcceptBlockHeader.
|
||||
if (!CheckBlockHeader(height,pindex,block,state,fCheckPOW))
|
||||
{
|
||||
fprintf(stderr,"checkblockheader error PoW.%d\n",fCheckPOW);
|
||||
return false;
|
||||
}
|
||||
if ( fCheckPOW && !CheckEquihashSolution(&block, Params()) )
|
||||
return state.DoS(100, error("CheckBlock(): Equihash solution invalid"),REJECT_INVALID, "invalid-solution");
|
||||
komodo_block2pubkey33(pubkey33,(CBlock *)&block);
|
||||
if ( fCheckPOW && !CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus()) )
|
||||
{
|
||||
//komodo_reverify_blockcheck(state,height,pindex);
|
||||
return state.DoS(1, error("CheckBlock(): proof of work failed"),REJECT_INVALID, "high-hash");
|
||||
}
|
||||
// Check the merkle root.
|
||||
if (fCheckMerkleRoot) {
|
||||
bool mutated;
|
||||
@@ -3627,7 +3864,7 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat
|
||||
//if ( komodo_check_deposit(ASSETCHAINS_SYMBOL[0] == 0 ? height : pindex != 0 ? (int32_t)pindex->nHeight : chainActive.Tip()->nHeight+1,block,pindex==0||pindex->pprev==0?0:pindex->pprev->nTime) < 0 )
|
||||
{
|
||||
static uint32_t counter;
|
||||
if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
||||
//if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
||||
fprintf(stderr,"check deposit rejection\n");
|
||||
return(false);
|
||||
}
|
||||
@@ -3969,7 +4206,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
|
||||
}
|
||||
if (!CheckBlock(indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot))
|
||||
{
|
||||
//fprintf(stderr,"TestBlockValidity failure B\n");
|
||||
fprintf(stderr,"TestBlockValidity failure B\n");
|
||||
return false;
|
||||
}
|
||||
if (!ContextualCheckBlock(block, state, pindexPrev))
|
||||
@@ -3977,7 +4214,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
|
||||
fprintf(stderr,"TestBlockValidity failure C\n");
|
||||
return false;
|
||||
}
|
||||
if (!ConnectBlock(block, state, &indexDummy, viewNew, true))
|
||||
if (!ConnectBlock(block, state, &indexDummy, viewNew, true,fCheckPOW))
|
||||
{
|
||||
//fprintf(stderr,"TestBlockValidity failure D\n");
|
||||
return false;
|
||||
@@ -4299,6 +4536,17 @@ bool static LoadBlockIndexDB()
|
||||
// Check whether we have a transaction index
|
||||
pblocktree->ReadFlag("txindex", fTxIndex);
|
||||
LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled");
|
||||
// Check whether we have an address index
|
||||
pblocktree->ReadFlag("addressindex", fAddressIndex);
|
||||
LogPrintf("%s: address index %s\n", __func__, fAddressIndex ? "enabled" : "disabled");
|
||||
|
||||
// Check whether we have a timestamp index
|
||||
pblocktree->ReadFlag("timestampindex", fTimestampIndex);
|
||||
LogPrintf("%s: timestamp index %s\n", __func__, fTimestampIndex ? "enabled" : "disabled");
|
||||
|
||||
// Check whether we have a spent index
|
||||
pblocktree->ReadFlag("spentindex", fSpentIndex);
|
||||
LogPrintf("%s: spent index %s\n", __func__, fSpentIndex ? "enabled" : "disabled");
|
||||
|
||||
// Fill in-memory data
|
||||
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
|
||||
@@ -4415,7 +4663,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
|
||||
CBlock block;
|
||||
if (!ReadBlockFromDisk(block, pindex))
|
||||
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||
if (!ConnectBlock(block, state, pindex, coins))
|
||||
if (!ConnectBlock(block, state, pindex, coins,false, true))
|
||||
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||
}
|
||||
}
|
||||
@@ -4619,6 +4867,16 @@ bool InitBlockIndex() {
|
||||
// Use the provided setting for -txindex in the new database
|
||||
fTxIndex = GetBoolArg("-txindex", true);
|
||||
pblocktree->WriteFlag("txindex", fTxIndex);
|
||||
// Use the provided setting for -addressindex in the new database
|
||||
fAddressIndex = GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX);
|
||||
pblocktree->WriteFlag("addressindex", fAddressIndex);
|
||||
|
||||
// Use the provided setting for -timestampindex in the new database
|
||||
fTimestampIndex = GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX);
|
||||
pblocktree->WriteFlag("timestampindex", fTimestampIndex);
|
||||
|
||||
fSpentIndex = GetBoolArg("-spentindex", DEFAULT_SPENTINDEX);
|
||||
pblocktree->WriteFlag("spentindex", fSpentIndex);
|
||||
LogPrintf("Initializing databases...\n");
|
||||
|
||||
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
|
||||
|
||||
348
src/main.h
348
src/main.h
@@ -22,6 +22,7 @@
|
||||
#include "script/script.h"
|
||||
#include "script/serverchecker.h"
|
||||
#include "script/standard.h"
|
||||
#include "spentindex.h"
|
||||
#include "sync.h"
|
||||
#include "tinyformat.h"
|
||||
#include "txmempool.h"
|
||||
@@ -101,6 +102,12 @@ static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
|
||||
/** Maximum length of reject messages. */
|
||||
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
|
||||
|
||||
static const bool DEFAULT_ADDRESSINDEX = false;
|
||||
static const bool DEFAULT_TIMESTAMPINDEX = false;
|
||||
static const bool DEFAULT_SPENTINDEX = false;
|
||||
static const unsigned int DEFAULT_DB_MAX_OPEN_FILES = 1000;
|
||||
static const bool DEFAULT_DB_COMPRESSION = true;
|
||||
|
||||
// Sanity check the magic numbers when we change them
|
||||
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE);
|
||||
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_PRIORITY_SIZE <= DEFAULT_BLOCK_MAX_SIZE);
|
||||
@@ -268,6 +275,338 @@ struct CNodeStateStats {
|
||||
std::vector<int> vHeightInFlight;
|
||||
};
|
||||
|
||||
struct CTimestampIndexIteratorKey {
|
||||
unsigned int timestamp;
|
||||
|
||||
size_t GetSerializeSize(int nType, int nVersion) const {
|
||||
return 4;
|
||||
}
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s, int nType, int nVersion) const {
|
||||
ser_writedata32be(s, timestamp);
|
||||
}
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, int nType, int nVersion) {
|
||||
timestamp = ser_readdata32be(s);
|
||||
}
|
||||
|
||||
CTimestampIndexIteratorKey(unsigned int time) {
|
||||
timestamp = time;
|
||||
}
|
||||
|
||||
CTimestampIndexIteratorKey() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
timestamp = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct CTimestampIndexKey {
|
||||
unsigned int timestamp;
|
||||
uint256 blockHash;
|
||||
|
||||
size_t GetSerializeSize(int nType, int nVersion) const {
|
||||
return 36;
|
||||
}
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s, int nType, int nVersion) const {
|
||||
ser_writedata32be(s, timestamp);
|
||||
blockHash.Serialize(s, nType, nVersion);
|
||||
}
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, int nType, int nVersion) {
|
||||
timestamp = ser_readdata32be(s);
|
||||
blockHash.Unserialize(s, nType, nVersion);
|
||||
}
|
||||
|
||||
CTimestampIndexKey(unsigned int time, uint256 hash) {
|
||||
timestamp = time;
|
||||
blockHash = hash;
|
||||
}
|
||||
|
||||
CTimestampIndexKey() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
timestamp = 0;
|
||||
blockHash.SetNull();
|
||||
}
|
||||
};
|
||||
|
||||
struct CTimestampBlockIndexKey {
|
||||
uint256 blockHash;
|
||||
|
||||
size_t GetSerializeSize(int nType, int nVersion) const {
|
||||
return 32;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s, int nType, int nVersion) const {
|
||||
blockHash.Serialize(s, nType, nVersion);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, int nType, int nVersion) {
|
||||
blockHash.Unserialize(s, nType, nVersion);
|
||||
}
|
||||
|
||||
CTimestampBlockIndexKey(uint256 hash) {
|
||||
blockHash = hash;
|
||||
}
|
||||
|
||||
CTimestampBlockIndexKey() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
blockHash.SetNull();
|
||||
}
|
||||
};
|
||||
|
||||
struct CTimestampBlockIndexValue {
|
||||
unsigned int ltimestamp;
|
||||
size_t GetSerializeSize(int nType, int nVersion) const {
|
||||
return 4;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s, int nType, int nVersion) const {
|
||||
ser_writedata32be(s, ltimestamp);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, int nType, int nVersion) {
|
||||
ltimestamp = ser_readdata32be(s);
|
||||
}
|
||||
|
||||
CTimestampBlockIndexValue (unsigned int time) {
|
||||
ltimestamp = time;
|
||||
}
|
||||
|
||||
CTimestampBlockIndexValue() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
ltimestamp = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct CAddressUnspentKey {
|
||||
unsigned int type;
|
||||
uint160 hashBytes;
|
||||
uint256 txhash;
|
||||
size_t index;
|
||||
|
||||
size_t GetSerializeSize(int nType, int nVersion) const {
|
||||
return 57;
|
||||
}
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s, int nType, int nVersion) const {
|
||||
ser_writedata8(s, type);
|
||||
hashBytes.Serialize(s, nType, nVersion);
|
||||
txhash.Serialize(s, nType, nVersion);
|
||||
ser_writedata32(s, index);
|
||||
}
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, int nType, int nVersion) {
|
||||
type = ser_readdata8(s);
|
||||
hashBytes.Unserialize(s, nType, nVersion);
|
||||
txhash.Unserialize(s, nType, nVersion);
|
||||
index = ser_readdata32(s);
|
||||
}
|
||||
|
||||
CAddressUnspentKey(unsigned int addressType, uint160 addressHash, uint256 txid, size_t indexValue) {
|
||||
type = addressType;
|
||||
hashBytes = addressHash;
|
||||
txhash = txid;
|
||||
index = indexValue;
|
||||
}
|
||||
|
||||
CAddressUnspentKey() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
type = 0;
|
||||
hashBytes.SetNull();
|
||||
txhash.SetNull();
|
||||
index = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct CAddressUnspentValue {
|
||||
CAmount satoshis;
|
||||
CScript script;
|
||||
int blockHeight;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(satoshis);
|
||||
READWRITE(script);
|
||||
READWRITE(blockHeight);
|
||||
}
|
||||
|
||||
CAddressUnspentValue(CAmount sats, CScript scriptPubKey, int height) {
|
||||
satoshis = sats;
|
||||
script = scriptPubKey;
|
||||
blockHeight = height;
|
||||
}
|
||||
|
||||
CAddressUnspentValue() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
satoshis = -1;
|
||||
script.clear();
|
||||
blockHeight = 0;
|
||||
}
|
||||
|
||||
bool IsNull() const {
|
||||
return (satoshis == -1);
|
||||
}
|
||||
};
|
||||
|
||||
struct CAddressIndexKey {
|
||||
unsigned int type;
|
||||
uint160 hashBytes;
|
||||
int blockHeight;
|
||||
unsigned int txindex;
|
||||
uint256 txhash;
|
||||
size_t index;
|
||||
bool spending;
|
||||
|
||||
size_t GetSerializeSize(int nType, int nVersion) const {
|
||||
return 66;
|
||||
}
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s, int nType, int nVersion) const {
|
||||
ser_writedata8(s, type);
|
||||
hashBytes.Serialize(s, nType, nVersion);
|
||||
// Heights are stored big-endian for key sorting in LevelDB
|
||||
ser_writedata32be(s, blockHeight);
|
||||
ser_writedata32be(s, txindex);
|
||||
txhash.Serialize(s, nType, nVersion);
|
||||
ser_writedata32(s, index);
|
||||
char f = spending;
|
||||
ser_writedata8(s, f);
|
||||
}
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, int nType, int nVersion) {
|
||||
type = ser_readdata8(s);
|
||||
hashBytes.Unserialize(s, nType, nVersion);
|
||||
blockHeight = ser_readdata32be(s);
|
||||
txindex = ser_readdata32be(s);
|
||||
txhash.Unserialize(s, nType, nVersion);
|
||||
index = ser_readdata32(s);
|
||||
char f = ser_readdata8(s);
|
||||
spending = f;
|
||||
}
|
||||
|
||||
CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex,
|
||||
uint256 txid, size_t indexValue, bool isSpending) {
|
||||
type = addressType;
|
||||
hashBytes = addressHash;
|
||||
blockHeight = height;
|
||||
txindex = blockindex;
|
||||
txhash = txid;
|
||||
index = indexValue;
|
||||
spending = isSpending;
|
||||
}
|
||||
|
||||
CAddressIndexKey() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
type = 0;
|
||||
hashBytes.SetNull();
|
||||
blockHeight = 0;
|
||||
txindex = 0;
|
||||
txhash.SetNull();
|
||||
index = 0;
|
||||
spending = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct CAddressIndexIteratorKey {
|
||||
unsigned int type;
|
||||
uint160 hashBytes;
|
||||
|
||||
size_t GetSerializeSize(int nType, int nVersion) const {
|
||||
return 21;
|
||||
}
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s, int nType, int nVersion) const {
|
||||
ser_writedata8(s, type);
|
||||
hashBytes.Serialize(s, nType, nVersion);
|
||||
}
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, int nType, int nVersion) {
|
||||
type = ser_readdata8(s);
|
||||
hashBytes.Unserialize(s, nType, nVersion);
|
||||
}
|
||||
|
||||
CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash) {
|
||||
type = addressType;
|
||||
hashBytes = addressHash;
|
||||
}
|
||||
|
||||
CAddressIndexIteratorKey() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
type = 0;
|
||||
hashBytes.SetNull();
|
||||
}
|
||||
};
|
||||
|
||||
struct CAddressIndexIteratorHeightKey {
|
||||
unsigned int type;
|
||||
uint160 hashBytes;
|
||||
int blockHeight;
|
||||
|
||||
size_t GetSerializeSize(int nType, int nVersion) const {
|
||||
return 25;
|
||||
}
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s, int nType, int nVersion) const {
|
||||
ser_writedata8(s, type);
|
||||
hashBytes.Serialize(s, nType, nVersion);
|
||||
ser_writedata32be(s, blockHeight);
|
||||
}
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, int nType, int nVersion) {
|
||||
type = ser_readdata8(s);
|
||||
hashBytes.Unserialize(s, nType, nVersion);
|
||||
blockHeight = ser_readdata32be(s);
|
||||
}
|
||||
|
||||
CAddressIndexIteratorHeightKey(unsigned int addressType, uint160 addressHash, int height) {
|
||||
type = addressType;
|
||||
hashBytes = addressHash;
|
||||
blockHeight = height;
|
||||
}
|
||||
|
||||
CAddressIndexIteratorHeightKey() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
type = 0;
|
||||
hashBytes.SetNull();
|
||||
blockHeight = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct CDiskTxPos : public CDiskBlockPos
|
||||
{
|
||||
unsigned int nTxOffset; // after header
|
||||
@@ -431,6 +770,13 @@ public:
|
||||
ScriptError GetScriptError() const { return error; }
|
||||
};
|
||||
|
||||
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes);
|
||||
bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
|
||||
bool GetAddressIndex(uint160 addressHash, int type,
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
|
||||
int start = 0, int end = 0);
|
||||
bool GetAddressUnspent(uint160 addressHash, int type,
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs);
|
||||
|
||||
/** Functions for disk access for blocks */
|
||||
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
|
||||
@@ -447,7 +793,7 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
|
||||
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
|
||||
|
||||
/** Apply the effects of this block (with given index) on the UTXO set represented by coins */
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false,bool fCheckPOW = false);
|
||||
|
||||
/** Context-independent validity checks */
|
||||
bool CheckBlockHeader(int32_t height,CBlockIndex *pindex,const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
|
||||
|
||||
@@ -385,7 +385,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
nLastBlockTx = nBlockTx;
|
||||
nLastBlockSize = nBlockSize;
|
||||
blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
||||
pblock->nTime = blocktime + 1;
|
||||
//pblock->nTime = blocktime + 1;
|
||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||
//LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits);
|
||||
if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 )
|
||||
@@ -479,8 +479,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
// Fill in header
|
||||
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
|
||||
pblock->hashReserved = uint256();
|
||||
//UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
|
||||
//pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED == 0 || NOTARY_PUBKEY33[0] == 0 )
|
||||
{
|
||||
UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
|
||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||
}
|
||||
pblock->nSolution.clear();
|
||||
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
|
||||
|
||||
@@ -488,8 +491,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false))
|
||||
{
|
||||
static uint32_t counter;
|
||||
if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
||||
fprintf(stderr,"warning: testblockvalidity failed\n");
|
||||
//if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
||||
fprintf(stderr,"warning: miner testblockvalidity failed\n");
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in
|
||||
{
|
||||
if ( KOMODO_LOADINGBLOCKS != 0 )
|
||||
return true;
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
/* if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
{
|
||||
if ( 1 && height > 792000 )
|
||||
{
|
||||
@@ -211,7 +211,9 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in
|
||||
}
|
||||
if ( height > 792000 )
|
||||
return false;
|
||||
} else return false;
|
||||
} else return false;*/
|
||||
if ( ASSETCHAINS_SYMBOL[0] != 0 || height > 792000 )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "chain.h"
|
||||
#include "chainparams.h"
|
||||
#include "checkpoints.h"
|
||||
#include "base58.h"
|
||||
#include "consensus/validation.h"
|
||||
#include "cc/betprotocol.h"
|
||||
#include "main.h"
|
||||
@@ -14,6 +15,10 @@
|
||||
#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 <stdint.h>
|
||||
|
||||
@@ -124,6 +129,112 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
|
||||
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", 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()));
|
||||
|
||||
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<unsigned char> 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<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
|
||||
delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).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);
|
||||
@@ -310,6 +421,102 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
|
||||
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))
|
||||
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<std::pair<uint256, unsigned int> > 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<std::pair<uint256, unsigned int> >::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)
|
||||
|
||||
@@ -96,6 +96,15 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "prioritisetransaction", 2 },
|
||||
{ "setban", 2 },
|
||||
{ "setban", 3 },
|
||||
{ "getblockhashes", 0 },
|
||||
{ "getblockhashes", 1 },
|
||||
{ "getblockhashes", 2 },
|
||||
{ "getspentinfo", 0},
|
||||
{ "getaddresstxids", 0},
|
||||
{ "getaddressbalance", 0},
|
||||
{ "getaddressdeltas", 0},
|
||||
{ "getaddressutxos", 0},
|
||||
{ "getaddressmempool", 0},
|
||||
{ "zcrawjoinsplit", 1 },
|
||||
{ "zcrawjoinsplit", 2 },
|
||||
{ "zcrawjoinsplit", 3 },
|
||||
|
||||
528
src/rpcmisc.cpp
528
src/rpcmisc.cpp
@@ -11,6 +11,7 @@
|
||||
#include "netbase.h"
|
||||
#include "rpcserver.h"
|
||||
#include "timedata.h"
|
||||
#include "txmempool.h"
|
||||
#include "util.h"
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet/wallet.h"
|
||||
@@ -557,3 +558,530 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address)
|
||||
{
|
||||
if (type == 2) {
|
||||
address = CBitcoinAddress(CScriptID(hash)).ToString();
|
||||
} else if (type == 1) {
|
||||
address = CBitcoinAddress(CKeyID(hash)).ToString();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getAddressesFromParams(const UniValue& params, std::vector<std::pair<uint160, int> > &addresses)
|
||||
{
|
||||
if (params[0].isStr()) {
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
uint160 hashBytes;
|
||||
int type = 0;
|
||||
if (!address.GetIndexKey(hashBytes, type)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
addresses.push_back(std::make_pair(hashBytes, type));
|
||||
} else if (params[0].isObject()) {
|
||||
|
||||
UniValue addressValues = find_value(params[0].get_obj(), "addresses");
|
||||
if (!addressValues.isArray()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Addresses is expected to be an array");
|
||||
}
|
||||
|
||||
std::vector<UniValue> values = addressValues.getValues();
|
||||
|
||||
for (std::vector<UniValue>::iterator it = values.begin(); it != values.end(); ++it) {
|
||||
|
||||
CBitcoinAddress address(it->get_str());
|
||||
uint160 hashBytes;
|
||||
int type = 0;
|
||||
if (!address.GetIndexKey(hashBytes, type)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
addresses.push_back(std::make_pair(hashBytes, type));
|
||||
}
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool heightSort(std::pair<CAddressUnspentKey, CAddressUnspentValue> a,
|
||||
std::pair<CAddressUnspentKey, CAddressUnspentValue> b) {
|
||||
return a.second.blockHeight < b.second.blockHeight;
|
||||
}
|
||||
|
||||
bool timestampSort(std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> a,
|
||||
std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> b) {
|
||||
return a.second.time < b.second.time;
|
||||
}
|
||||
|
||||
UniValue getaddressmempool(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"getaddressmempool\n"
|
||||
"\nReturns all mempool deltas for an address (requires addressindex to be enabled).\n"
|
||||
"\nArguments:\n"
|
||||
"{\n"
|
||||
" \"addresses\"\n"
|
||||
" [\n"
|
||||
" \"address\" (string) The base58check encoded address\n"
|
||||
" ,...\n"
|
||||
" ]\n"
|
||||
"}\n"
|
||||
"\nResult:\n"
|
||||
"[\n"
|
||||
" {\n"
|
||||
" \"address\" (string) The base58check encoded address\n"
|
||||
" \"txid\" (string) The related txid\n"
|
||||
" \"index\" (number) The related input or output index\n"
|
||||
" \"satoshis\" (number) The difference of satoshis\n"
|
||||
" \"timestamp\" (number) The time the transaction entered the mempool (seconds)\n"
|
||||
" \"prevtxid\" (string) The previous txid (if spending)\n"
|
||||
" \"prevout\" (string) The previous transaction output index (if spending)\n"
|
||||
" }\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddressmempool", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
|
||||
+ HelpExampleRpc("getaddressmempool", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
|
||||
);
|
||||
|
||||
std::vector<std::pair<uint160, int> > addresses;
|
||||
|
||||
if (!getAddressesFromParams(params, addresses)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
|
||||
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > indexes;
|
||||
|
||||
if (!mempool.getAddressIndex(addresses, indexes)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
|
||||
}
|
||||
|
||||
std::sort(indexes.begin(), indexes.end(), timestampSort);
|
||||
|
||||
UniValue result(UniValue::VARR);
|
||||
|
||||
for (std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> >::iterator it = indexes.begin();
|
||||
it != indexes.end(); it++) {
|
||||
|
||||
std::string address;
|
||||
if (!getAddressFromIndex(it->first.type, it->first.addressBytes, address)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type");
|
||||
}
|
||||
|
||||
UniValue delta(UniValue::VOBJ);
|
||||
delta.push_back(Pair("address", address));
|
||||
delta.push_back(Pair("txid", it->first.txhash.GetHex()));
|
||||
delta.push_back(Pair("index", (int)it->first.index));
|
||||
delta.push_back(Pair("satoshis", it->second.amount));
|
||||
delta.push_back(Pair("timestamp", it->second.time));
|
||||
if (it->second.amount < 0) {
|
||||
delta.push_back(Pair("prevtxid", it->second.prevhash.GetHex()));
|
||||
delta.push_back(Pair("prevout", (int)it->second.prevout));
|
||||
}
|
||||
result.push_back(delta);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue getaddressutxos(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"getaddressutxos\n"
|
||||
"\nReturns all unspent outputs for an address (requires addressindex to be enabled).\n"
|
||||
"\nArguments:\n"
|
||||
"{\n"
|
||||
" \"addresses\"\n"
|
||||
" [\n"
|
||||
" \"address\" (string) The base58check encoded address\n"
|
||||
" ,...\n"
|
||||
" ],\n"
|
||||
" \"chainInfo\" (boolean) Include chain info with results\n"
|
||||
"}\n"
|
||||
"\nResult\n"
|
||||
"[\n"
|
||||
" {\n"
|
||||
" \"address\" (string) The address base58check encoded\n"
|
||||
" \"txid\" (string) The output txid\n"
|
||||
" \"height\" (number) The block height\n"
|
||||
" \"outputIndex\" (number) The output index\n"
|
||||
" \"script\" (strin) The script hex encoded\n"
|
||||
" \"satoshis\" (number) The number of satoshis of the output\n"
|
||||
" }\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddressutxos", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
|
||||
+ HelpExampleRpc("getaddressutxos", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
|
||||
);
|
||||
|
||||
bool includeChainInfo = false;
|
||||
if (params[0].isObject()) {
|
||||
UniValue chainInfo = find_value(params[0].get_obj(), "chainInfo");
|
||||
if (chainInfo.isBool()) {
|
||||
includeChainInfo = chainInfo.get_bool();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint160, int> > addresses;
|
||||
|
||||
if (!getAddressesFromParams(params, addresses)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
|
||||
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
|
||||
if (!GetAddressUnspent((*it).first, (*it).second, unspentOutputs)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(unspentOutputs.begin(), unspentOutputs.end(), heightSort);
|
||||
|
||||
UniValue utxos(UniValue::VARR);
|
||||
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) {
|
||||
UniValue output(UniValue::VOBJ);
|
||||
std::string address;
|
||||
if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type");
|
||||
}
|
||||
|
||||
output.push_back(Pair("address", address));
|
||||
output.push_back(Pair("txid", it->first.txhash.GetHex()));
|
||||
output.push_back(Pair("outputIndex", (int)it->first.index));
|
||||
output.push_back(Pair("script", HexStr(it->second.script.begin(), it->second.script.end())));
|
||||
output.push_back(Pair("satoshis", it->second.satoshis));
|
||||
output.push_back(Pair("height", it->second.blockHeight));
|
||||
utxos.push_back(output);
|
||||
}
|
||||
|
||||
if (includeChainInfo) {
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("utxos", utxos));
|
||||
|
||||
LOCK(cs_main);
|
||||
result.push_back(Pair("hash", chainActive.Tip()->GetBlockHash().GetHex()));
|
||||
result.push_back(Pair("height", (int)chainActive.Height()));
|
||||
return result;
|
||||
} else {
|
||||
return utxos;
|
||||
}
|
||||
}
|
||||
|
||||
UniValue getaddressdeltas(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1 || !params[0].isObject())
|
||||
throw runtime_error(
|
||||
"getaddressdeltas\n"
|
||||
"\nReturns all changes for an address (requires addressindex to be enabled).\n"
|
||||
"\nArguments:\n"
|
||||
"{\n"
|
||||
" \"addresses\"\n"
|
||||
" [\n"
|
||||
" \"address\" (string) The base58check encoded address\n"
|
||||
" ,...\n"
|
||||
" ]\n"
|
||||
" \"start\" (number) The start block height\n"
|
||||
" \"end\" (number) The end block height\n"
|
||||
" \"chainInfo\" (boolean) Include chain info in results, only applies if start and end specified\n"
|
||||
"}\n"
|
||||
"\nResult:\n"
|
||||
"[\n"
|
||||
" {\n"
|
||||
" \"satoshis\" (number) The difference of satoshis\n"
|
||||
" \"txid\" (string) The related txid\n"
|
||||
" \"index\" (number) The related input or output index\n"
|
||||
" \"height\" (number) The block height\n"
|
||||
" \"address\" (string) The base58check encoded address\n"
|
||||
" }\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddressdeltas", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
|
||||
+ HelpExampleRpc("getaddressdeltas", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
|
||||
);
|
||||
|
||||
|
||||
UniValue startValue = find_value(params[0].get_obj(), "start");
|
||||
UniValue endValue = find_value(params[0].get_obj(), "end");
|
||||
|
||||
UniValue chainInfo = find_value(params[0].get_obj(), "chainInfo");
|
||||
bool includeChainInfo = false;
|
||||
if (chainInfo.isBool()) {
|
||||
includeChainInfo = chainInfo.get_bool();
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
|
||||
if (startValue.isNum() && endValue.isNum()) {
|
||||
start = startValue.get_int();
|
||||
end = endValue.get_int();
|
||||
if (start <= 0 || end <= 0) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Start and end is expected to be greater than zero");
|
||||
}
|
||||
if (end < start) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "End value is expected to be greater than start");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint160, int> > addresses;
|
||||
|
||||
if (!getAddressesFromParams(params, addresses)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||
|
||||
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
|
||||
if (start > 0 && end > 0) {
|
||||
if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
|
||||
}
|
||||
} else {
|
||||
if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UniValue deltas(UniValue::VARR);
|
||||
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) {
|
||||
std::string address;
|
||||
if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type");
|
||||
}
|
||||
|
||||
UniValue delta(UniValue::VOBJ);
|
||||
delta.push_back(Pair("satoshis", it->second));
|
||||
delta.push_back(Pair("txid", it->first.txhash.GetHex()));
|
||||
delta.push_back(Pair("index", (int)it->first.index));
|
||||
delta.push_back(Pair("blockindex", (int)it->first.txindex));
|
||||
delta.push_back(Pair("height", it->first.blockHeight));
|
||||
delta.push_back(Pair("address", address));
|
||||
deltas.push_back(delta);
|
||||
}
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
|
||||
if (includeChainInfo && start > 0 && end > 0) {
|
||||
LOCK(cs_main);
|
||||
|
||||
if (start > chainActive.Height() || end > chainActive.Height()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Start or end is outside chain range");
|
||||
}
|
||||
|
||||
CBlockIndex* startIndex = chainActive[start];
|
||||
CBlockIndex* endIndex = chainActive[end];
|
||||
|
||||
UniValue startInfo(UniValue::VOBJ);
|
||||
UniValue endInfo(UniValue::VOBJ);
|
||||
|
||||
startInfo.push_back(Pair("hash", startIndex->GetBlockHash().GetHex()));
|
||||
startInfo.push_back(Pair("height", start));
|
||||
|
||||
endInfo.push_back(Pair("hash", endIndex->GetBlockHash().GetHex()));
|
||||
endInfo.push_back(Pair("height", end));
|
||||
|
||||
result.push_back(Pair("deltas", deltas));
|
||||
result.push_back(Pair("start", startInfo));
|
||||
result.push_back(Pair("end", endInfo));
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return deltas;
|
||||
}
|
||||
}
|
||||
|
||||
UniValue getaddressbalance(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"getaddressbalance\n"
|
||||
"\nReturns the balance for an address(es) (requires addressindex to be enabled).\n"
|
||||
"\nArguments:\n"
|
||||
"{\n"
|
||||
" \"addresses\"\n"
|
||||
" [\n"
|
||||
" \"address\" (string) The base58check encoded address\n"
|
||||
" ,...\n"
|
||||
" ]\n"
|
||||
"}\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"balance\" (string) The current balance in satoshis\n"
|
||||
" \"received\" (string) The total number of satoshis received (including change)\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddressbalance", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
|
||||
+ HelpExampleRpc("getaddressbalance", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
|
||||
);
|
||||
|
||||
std::vector<std::pair<uint160, int> > addresses;
|
||||
|
||||
if (!getAddressesFromParams(params, addresses)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||
|
||||
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
|
||||
if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
|
||||
}
|
||||
}
|
||||
|
||||
CAmount balance = 0;
|
||||
CAmount received = 0;
|
||||
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) {
|
||||
if (it->second > 0) {
|
||||
received += it->second;
|
||||
}
|
||||
balance += it->second;
|
||||
}
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("balance", balance));
|
||||
result.push_back(Pair("received", received));
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
UniValue getaddresstxids(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"getaddresstxids\n"
|
||||
"\nReturns the txids for an address(es) (requires addressindex to be enabled).\n"
|
||||
"\nArguments:\n"
|
||||
"{\n"
|
||||
" \"addresses\"\n"
|
||||
" [\n"
|
||||
" \"address\" (string) The base58check encoded address\n"
|
||||
" ,...\n"
|
||||
" ]\n"
|
||||
" \"start\" (number) The start block height\n"
|
||||
" \"end\" (number) The end block height\n"
|
||||
"}\n"
|
||||
"\nResult:\n"
|
||||
"[\n"
|
||||
" \"transactionid\" (string) The transaction id\n"
|
||||
" ,...\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddresstxids", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
|
||||
+ HelpExampleRpc("getaddresstxids", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
|
||||
);
|
||||
|
||||
std::vector<std::pair<uint160, int> > addresses;
|
||||
|
||||
if (!getAddressesFromParams(params, addresses)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
if (params[0].isObject()) {
|
||||
UniValue startValue = find_value(params[0].get_obj(), "start");
|
||||
UniValue endValue = find_value(params[0].get_obj(), "end");
|
||||
if (startValue.isNum() && endValue.isNum()) {
|
||||
start = startValue.get_int();
|
||||
end = endValue.get_int();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||
|
||||
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
|
||||
if (start > 0 && end > 0) {
|
||||
if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
|
||||
}
|
||||
} else {
|
||||
if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::pair<int, std::string> > txids;
|
||||
UniValue result(UniValue::VARR);
|
||||
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) {
|
||||
int height = it->first.blockHeight;
|
||||
std::string txid = it->first.txhash.GetHex();
|
||||
|
||||
if (addresses.size() > 1) {
|
||||
txids.insert(std::make_pair(height, txid));
|
||||
} else {
|
||||
if (txids.insert(std::make_pair(height, txid)).second) {
|
||||
result.push_back(txid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addresses.size() > 1) {
|
||||
for (std::set<std::pair<int, std::string> >::const_iterator it=txids.begin(); it!=txids.end(); it++) {
|
||||
result.push_back(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
UniValue getspentinfo(const UniValue& params, bool fHelp)
|
||||
{
|
||||
|
||||
if (fHelp || params.size() != 1 || !params[0].isObject())
|
||||
throw runtime_error(
|
||||
"getspentinfo\n"
|
||||
"\nReturns the txid and index where an output is spent.\n"
|
||||
"\nArguments:\n"
|
||||
"{\n"
|
||||
" \"txid\" (string) The hex string of the txid\n"
|
||||
" \"index\" (number) The start block height\n"
|
||||
"}\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"txid\" (string) The transaction id\n"
|
||||
" \"index\" (number) The spending input index\n"
|
||||
" ,...\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getspentinfo", "'{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}'")
|
||||
+ HelpExampleRpc("getspentinfo", "{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}")
|
||||
);
|
||||
|
||||
UniValue txidValue = find_value(params[0].get_obj(), "txid");
|
||||
UniValue indexValue = find_value(params[0].get_obj(), "index");
|
||||
|
||||
if (!txidValue.isStr() || !indexValue.isNum()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid txid or index");
|
||||
}
|
||||
|
||||
uint256 txid = ParseHashV(txidValue, "txid");
|
||||
int outputIndex = indexValue.get_int();
|
||||
|
||||
CSpentIndexKey key(txid, outputIndex);
|
||||
CSpentIndexValue value;
|
||||
|
||||
if (!GetSpentIndex(key, value)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to get spent info");
|
||||
}
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("txid", value.txid.GetHex()));
|
||||
obj.push_back(Pair("index", (int)value.inputIndex));
|
||||
obj.push_back(Pair("height", value.blockHeight));
|
||||
|
||||
return obj;
|
||||
}
|
||||
@@ -65,7 +65,9 @@ UniValue TxJoinSplitToJSON(const CTransaction& tx) {
|
||||
UniValue joinsplit(UniValue::VOBJ);
|
||||
|
||||
joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old)));
|
||||
joinsplit.push_back(Pair("vpub_oldZat", jsdescription.vpub_old));
|
||||
joinsplit.push_back(Pair("vpub_new", ValueFromAmount(jsdescription.vpub_new)));
|
||||
joinsplit.push_back(Pair("vpub_newZat", jsdescription.vpub_new));
|
||||
|
||||
joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex()));
|
||||
|
||||
@@ -115,9 +117,10 @@ UniValue TxJoinSplitToJSON(const CTransaction& tx) {
|
||||
|
||||
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
|
||||
|
||||
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
||||
void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, int nHeight = 0, int nConfirmations = 0, int nBlockTime = 0)
|
||||
{
|
||||
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
|
||||
uint256 txid = tx.GetHash();
|
||||
entry.push_back(Pair("txid", txid.GetHex()));
|
||||
entry.push_back(Pair("overwintered", tx.fOverwintered));
|
||||
entry.push_back(Pair("version", tx.nVersion));
|
||||
if (tx.fOverwintered) {
|
||||
@@ -139,6 +142,19 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
||||
o.push_back(Pair("asm", txin.scriptSig.ToString()));
|
||||
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
||||
in.push_back(Pair("scriptSig", o));
|
||||
|
||||
// Add address and value info if spentindex enabled
|
||||
CSpentIndexValue spentInfo;
|
||||
CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n);
|
||||
if (GetSpentIndex(spentKey, spentInfo)) {
|
||||
in.push_back(Pair("value", ValueFromAmount(spentInfo.satoshis)));
|
||||
in.push_back(Pair("valueSat", spentInfo.satoshis));
|
||||
if (spentInfo.addressType == 1) {
|
||||
in.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString()));
|
||||
} else if (spentInfo.addressType == 2) {
|
||||
in.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
|
||||
vin.push_back(in);
|
||||
@@ -162,6 +178,16 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
||||
UniValue o(UniValue::VOBJ);
|
||||
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
|
||||
out.push_back(Pair("scriptPubKey", o));
|
||||
|
||||
// Add spent information if spentindex is enabled
|
||||
CSpentIndexValue spentInfo;
|
||||
CSpentIndexKey spentKey(txid, i);
|
||||
if (GetSpentIndex(spentKey, spentInfo)) {
|
||||
out.push_back(Pair("spentTxId", spentInfo.txid.GetHex()));
|
||||
out.push_back(Pair("spentIndex", (int)spentInfo.inputIndex));
|
||||
out.push_back(Pair("spentHeight", spentInfo.blockHeight));
|
||||
}
|
||||
|
||||
vout.push_back(out);
|
||||
}
|
||||
entry.push_back(Pair("vout", vout));
|
||||
@@ -169,18 +195,76 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
||||
UniValue vjoinsplit = TxJoinSplitToJSON(tx);
|
||||
entry.push_back(Pair("vjoinsplit", vjoinsplit));
|
||||
|
||||
if (!hashBlock.IsNull()) {
|
||||
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
|
||||
|
||||
if (nConfirmations > 0) {
|
||||
entry.push_back(Pair("height", nHeight));
|
||||
entry.push_back(Pair("confirmations", nConfirmations));
|
||||
entry.push_back(Pair("time", nBlockTime));
|
||||
entry.push_back(Pair("blocktime", nBlockTime));
|
||||
} else {
|
||||
entry.push_back(Pair("height", -1));
|
||||
entry.push_back(Pair("confirmations", 0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
||||
{
|
||||
uint256 txid = tx.GetHash();
|
||||
entry.push_back(Pair("txid", txid.GetHex()));
|
||||
entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
|
||||
entry.push_back(Pair("version", tx.nVersion));
|
||||
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
|
||||
|
||||
UniValue vin(UniValue::VARR);
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
||||
UniValue in(UniValue::VOBJ);
|
||||
if (tx.IsCoinBase())
|
||||
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
||||
else {
|
||||
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
|
||||
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
|
||||
UniValue o(UniValue::VOBJ);
|
||||
o.push_back(Pair("asm", txin.scriptSig.ToString()));
|
||||
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
||||
in.push_back(Pair("scriptSig", o));
|
||||
}
|
||||
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
|
||||
vin.push_back(in);
|
||||
}
|
||||
entry.push_back(Pair("vin", vin));
|
||||
|
||||
UniValue vout(UniValue::VARR);
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
const CTxOut& txout = tx.vout[i];
|
||||
UniValue out(UniValue::VOBJ);
|
||||
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
|
||||
out.push_back(Pair("valueSat", txout.nValue));
|
||||
out.push_back(Pair("n", (int64_t)i));
|
||||
UniValue o(UniValue::VOBJ);
|
||||
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
|
||||
out.push_back(Pair("scriptPubKey", o));
|
||||
vout.push_back(out);
|
||||
}
|
||||
entry.push_back(Pair("vout", vout));
|
||||
|
||||
if (!hashBlock.IsNull()) {
|
||||
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
|
||||
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
|
||||
if (mi != mapBlockIndex.end() && (*mi).second) {
|
||||
CBlockIndex* pindex = (*mi).second;
|
||||
if (chainActive.Contains(pindex)) {
|
||||
entry.push_back(Pair("height", pindex->nHeight));
|
||||
entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
|
||||
entry.push_back(Pair("time", pindex->GetBlockTime()));
|
||||
entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
|
||||
}
|
||||
else
|
||||
} else {
|
||||
entry.push_back(Pair("height", -1));
|
||||
entry.push_back(Pair("confirmations", 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,7 +363,6 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
|
||||
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
uint256 hash = ParseHashV(params[0], "parameter 1");
|
||||
|
||||
@@ -289,8 +372,29 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
|
||||
|
||||
CTransaction tx;
|
||||
uint256 hashBlock;
|
||||
if (!GetTransaction(hash, tx, hashBlock, true))
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
|
||||
int nHeight = 0;
|
||||
int nConfirmations = 0;
|
||||
int nBlockTime = 0;
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if (!GetTransaction(hash, tx, hashBlock, true))
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
|
||||
|
||||
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
|
||||
if (mi != mapBlockIndex.end() && (*mi).second) {
|
||||
CBlockIndex* pindex = (*mi).second;
|
||||
if (chainActive.Contains(pindex)) {
|
||||
nHeight = pindex->nHeight;
|
||||
nConfirmations = 1 + chainActive.Height() - pindex->nHeight;
|
||||
nBlockTime = pindex->GetBlockTime();
|
||||
} else {
|
||||
nHeight = -1;
|
||||
nConfirmations = 0;
|
||||
nBlockTime = pindex->GetBlockTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string strHex = EncodeHexTx(tx);
|
||||
|
||||
@@ -299,7 +403,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("hex", strHex));
|
||||
TxToJSON(tx, hashBlock, result);
|
||||
TxToJSONExpanded(tx, hashBlock, result, nHeight, nConfirmations, nBlockTime);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,6 +281,8 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "blockchain", "getbestblockhash", &getbestblockhash, true },
|
||||
{ "blockchain", "getblockcount", &getblockcount, true },
|
||||
{ "blockchain", "getblock", &getblock, true },
|
||||
{ "blockchain", "getblockdeltas", &getblockdeltas, false },
|
||||
{ "blockchain", "getblockhashes", &getblockhashes, true },
|
||||
{ "blockchain", "getblockhash", &getblockhash, true },
|
||||
{ "blockchain", "getblockheader", &getblockheader, true },
|
||||
{ "blockchain", "getchaintips", &getchaintips, true },
|
||||
@@ -292,6 +294,7 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "blockchain", "verifytxoutproof", &verifytxoutproof, true },
|
||||
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
|
||||
{ "blockchain", "verifychain", &verifychain, true },
|
||||
{ "blockchain", "getspentinfo", &getspentinfo, false },
|
||||
{ "blockchain", "paxprice", &paxprice, true },
|
||||
{ "blockchain", "paxpending", &paxpending, true },
|
||||
{ "blockchain", "paxprices", &paxprices, true },
|
||||
@@ -332,6 +335,13 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
|
||||
#endif
|
||||
|
||||
/* Address index */
|
||||
{ "addressindex", "getaddressmempool", &getaddressmempool, true },
|
||||
{ "addressindex", "getaddressutxos", &getaddressutxos, false },
|
||||
{ "addressindex", "getaddressdeltas", &getaddressdeltas, false },
|
||||
{ "addressindex", "getaddresstxids", &getaddresstxids, false },
|
||||
{ "addressindex", "getaddressbalance", &getaddressbalance, false },
|
||||
|
||||
/* Utility functions */
|
||||
{ "util", "createmultisig", &createmultisig, true },
|
||||
{ "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */
|
||||
|
||||
@@ -173,6 +173,11 @@ extern std::string HelpExampleRpc(const std::string& methodname, const std::stri
|
||||
extern void EnsureWalletIsUnlocked();
|
||||
|
||||
extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp
|
||||
extern UniValue getaddressmempool(const UniValue& params, bool fHelp);
|
||||
extern UniValue getaddressutxos(const UniValue& params, bool fHelp);
|
||||
extern UniValue getaddressdeltas(const UniValue& params, bool fHelp);
|
||||
extern UniValue getaddresstxids(const UniValue& params, bool fHelp);
|
||||
extern UniValue getaddressbalance(const UniValue& params, bool fHelp);
|
||||
extern UniValue getpeerinfo(const UniValue& params, bool fHelp);
|
||||
extern UniValue ping(const UniValue& params, bool fHelp);
|
||||
extern UniValue addnode(const UniValue& params, bool fHelp);
|
||||
@@ -271,6 +276,8 @@ extern UniValue getdifficulty(const UniValue& params, bool fHelp);
|
||||
extern UniValue settxfee(const UniValue& params, bool fHelp);
|
||||
extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
|
||||
extern UniValue getrawmempool(const UniValue& params, bool fHelp);
|
||||
extern UniValue getblockhashes(const UniValue& params, bool fHelp);
|
||||
extern UniValue getblockdeltas(const UniValue& params, bool fHelp);
|
||||
extern UniValue getblockhash(const UniValue& params, bool fHelp);
|
||||
extern UniValue getblockheader(const UniValue& params, bool fHelp);
|
||||
extern UniValue getblock(const UniValue& params, bool fHelp);
|
||||
@@ -280,6 +287,7 @@ extern UniValue verifychain(const UniValue& params, bool fHelp);
|
||||
extern UniValue getchaintips(const UniValue& params, bool fHelp);
|
||||
extern UniValue invalidateblock(const UniValue& params, bool fHelp);
|
||||
extern UniValue reconsiderblock(const UniValue& params, bool fHelp);
|
||||
extern UniValue getspentinfo(const UniValue& params, bool fHelp);
|
||||
|
||||
extern UniValue getblocksubsidy(const UniValue& params, bool fHelp);
|
||||
|
||||
|
||||
@@ -216,6 +216,17 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
|
||||
return subscript.GetSigOpCount(true);
|
||||
}
|
||||
|
||||
bool CScript::IsPayToPublicKeyHash() const
|
||||
{
|
||||
// Extra-fast test for pay-to-pubkey-hash CScripts:
|
||||
return (this->size() == 25 &&
|
||||
(*this)[0] == OP_DUP &&
|
||||
(*this)[1] == OP_HASH160 &&
|
||||
(*this)[2] == 0x14 &&
|
||||
(*this)[23] == OP_EQUALVERIFY &&
|
||||
(*this)[24] == OP_CHECKSIG);
|
||||
}
|
||||
|
||||
bool CScript::IsPayToScriptHash() const
|
||||
{
|
||||
// Extra-fast test for pay-to-script-hash CScripts:
|
||||
|
||||
@@ -566,6 +566,8 @@ public:
|
||||
*/
|
||||
unsigned int GetSigOpCount(const CScript& scriptSig) const;
|
||||
|
||||
bool IsPayToPublicKeyHash() const;
|
||||
|
||||
bool IsPayToScriptHash() const;
|
||||
bool IsPayToCryptoCondition() const;
|
||||
bool MayAcceptCryptoCondition() const;
|
||||
|
||||
@@ -95,6 +95,11 @@ template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
|
||||
obj = htole32(obj);
|
||||
s.write((char*)&obj, 4);
|
||||
}
|
||||
template<typename Stream> inline void ser_writedata32be(Stream &s, uint32_t obj)
|
||||
{
|
||||
obj = htobe32(obj);
|
||||
s.write((char*)&obj, 4);
|
||||
}
|
||||
template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj)
|
||||
{
|
||||
obj = htole64(obj);
|
||||
@@ -118,6 +123,12 @@ template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
|
||||
s.read((char*)&obj, 4);
|
||||
return le32toh(obj);
|
||||
}
|
||||
template<typename Stream> inline uint32_t ser_readdata32be(Stream &s)
|
||||
{
|
||||
uint32_t obj;
|
||||
s.read((char*)&obj, 4);
|
||||
return be32toh(obj);
|
||||
}
|
||||
template<typename Stream> inline uint64_t ser_readdata64(Stream &s)
|
||||
{
|
||||
uint64_t obj;
|
||||
|
||||
98
src/spentindex.h
Normal file
98
src/spentindex.h
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SPENTINDEX_H
|
||||
#define BITCOIN_SPENTINDEX_H
|
||||
|
||||
#include "uint256.h"
|
||||
#include "amount.h"
|
||||
|
||||
struct CSpentIndexKey {
|
||||
uint256 txid;
|
||||
unsigned int outputIndex;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(txid);
|
||||
READWRITE(outputIndex);
|
||||
}
|
||||
|
||||
CSpentIndexKey(uint256 t, unsigned int i) {
|
||||
txid = t;
|
||||
outputIndex = i;
|
||||
}
|
||||
|
||||
CSpentIndexKey() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
txid.SetNull();
|
||||
outputIndex = 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct CSpentIndexValue {
|
||||
uint256 txid;
|
||||
unsigned int inputIndex;
|
||||
int blockHeight;
|
||||
CAmount satoshis;
|
||||
int addressType;
|
||||
uint160 addressHash;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(txid);
|
||||
READWRITE(inputIndex);
|
||||
READWRITE(blockHeight);
|
||||
READWRITE(satoshis);
|
||||
READWRITE(addressType);
|
||||
READWRITE(addressHash);
|
||||
}
|
||||
|
||||
CSpentIndexValue(uint256 t, unsigned int i, int h, CAmount s, int type, uint160 a) {
|
||||
txid = t;
|
||||
inputIndex = i;
|
||||
blockHeight = h;
|
||||
satoshis = s;
|
||||
addressType = type;
|
||||
addressHash = a;
|
||||
}
|
||||
|
||||
CSpentIndexValue() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
txid.SetNull();
|
||||
inputIndex = 0;
|
||||
blockHeight = 0;
|
||||
satoshis = 0;
|
||||
addressType = 0;
|
||||
addressHash.SetNull();
|
||||
}
|
||||
|
||||
bool IsNull() const {
|
||||
return txid.IsNull();
|
||||
}
|
||||
};
|
||||
|
||||
struct CSpentIndexKeyCompare
|
||||
{
|
||||
bool operator()(const CSpentIndexKey& a, const CSpentIndexKey& b) const {
|
||||
if (a.txid == b.txid) {
|
||||
return a.outputIndex < b.outputIndex;
|
||||
} else {
|
||||
return a.txid < b.txid;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SPENTINDEX_H
|
||||
59
src/test/script_P2PKH_tests.cpp
Normal file
59
src/test/script_P2PKH_tests.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2012-2015 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 "script/script.h"
|
||||
#include "test/test_bitcoin.h"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(script_P2PKH_tests, BasicTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(IsPayToPublicKeyHash)
|
||||
{
|
||||
// Test CScript::IsPayToPublicKeyHash()
|
||||
uint160 dummy;
|
||||
CScript p2pkh;
|
||||
p2pkh << OP_DUP << OP_HASH160 << ToByteVector(dummy) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
BOOST_CHECK(p2pkh.IsPayToPublicKeyHash());
|
||||
|
||||
static const unsigned char direct[] = {
|
||||
OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG
|
||||
};
|
||||
BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToPublicKeyHash());
|
||||
|
||||
static const unsigned char notp2pkh1[] = {
|
||||
OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG, OP_CHECKSIG
|
||||
};
|
||||
BOOST_CHECK(!CScript(notp2pkh1, notp2pkh1+sizeof(notp2pkh1)).IsPayToPublicKeyHash());
|
||||
|
||||
static const unsigned char p2sh[] = {
|
||||
OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL
|
||||
};
|
||||
BOOST_CHECK(!CScript(p2sh, p2sh+sizeof(p2sh)).IsPayToPublicKeyHash());
|
||||
|
||||
static const unsigned char extra[] = {
|
||||
OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG, OP_CHECKSIG
|
||||
};
|
||||
BOOST_CHECK(!CScript(extra, extra+sizeof(extra)).IsPayToPublicKeyHash());
|
||||
|
||||
static const unsigned char missing[] = {
|
||||
OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG, OP_RETURN
|
||||
};
|
||||
BOOST_CHECK(!CScript(missing, missing+sizeof(missing)).IsPayToPublicKeyHash());
|
||||
|
||||
static const unsigned char missing2[] = {
|
||||
OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
BOOST_CHECK(!CScript(missing2, missing2+sizeof(missing)).IsPayToPublicKeyHash());
|
||||
|
||||
static const unsigned char tooshort[] = {
|
||||
OP_DUP, OP_HASH160, 2, 0,0, OP_EQUALVERIFY, OP_CHECKSIG
|
||||
};
|
||||
BOOST_CHECK(!CScript(tooshort, tooshort+sizeof(direct)).IsPayToPublicKeyHash());
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "key.h"
|
||||
#include "main.h"
|
||||
#include "random.h"
|
||||
#include "chainparamsbase.h"
|
||||
#include "txdb.h"
|
||||
#include "txmempool.h"
|
||||
#include "ui_interface.h"
|
||||
|
||||
61
src/test/wallet-utility.py
Normal file
61
src/test/wallet-utility.py
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright 2014 BitPay, Inc.
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import buildenv
|
||||
import shutil
|
||||
|
||||
def assert_equal(thing1, thing2):
|
||||
if thing1 != thing2:
|
||||
raise AssertionError("%s != %s"%(str(thing1),str(thing2)))
|
||||
|
||||
if __name__ == '__main__':
|
||||
datadir = os.environ["srcdir"] + "/test/data"
|
||||
execprog = './wallet-utility' + buildenv.exeext
|
||||
execargs = '-datadir=' + datadir
|
||||
execrun = execprog + ' ' + execargs
|
||||
|
||||
proc = subprocess.Popen(execrun, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
|
||||
try:
|
||||
outs = proc.communicate()
|
||||
except OSError:
|
||||
print("OSError, Failed to execute " + execprog)
|
||||
sys.exit(1)
|
||||
|
||||
output = json.loads(outs[0])
|
||||
|
||||
assert_equal(output[0], "13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av")
|
||||
assert_equal(output[1], "1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8")
|
||||
assert_equal(output[2], "13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F")
|
||||
|
||||
execargs = '-datadir=' + datadir + ' -dumppass'
|
||||
execrun = execprog + ' ' + execargs
|
||||
|
||||
proc = subprocess.Popen(execrun, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
|
||||
try:
|
||||
outs = proc.communicate()
|
||||
except OSError:
|
||||
print("OSError, Failed to execute " + execprog)
|
||||
sys.exit(1)
|
||||
|
||||
output = json.loads(outs[0])
|
||||
|
||||
assert_equal(output[0]['addr'], "13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av")
|
||||
assert_equal(output[0]['pkey'], "5Jz5BWE2WQxp1hGqDZeisQFV1mRFR2AVBAgiXCbNcZyXNjD9aUd")
|
||||
assert_equal(output[1]['addr'], "1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8")
|
||||
assert_equal(output[1]['pkey'], "5HsX2b3v2GjngYQ5ZM4mLp2b2apw6aMNVaPELV1YmpiYR1S4jzc")
|
||||
assert_equal(output[2]['addr'], "13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F")
|
||||
assert_equal(output[2]['pkey'], "5KCWAs1wX2ESiL4PfDR8XYVSSETHFd2jaRGxt1QdanBFTit4XcH")
|
||||
|
||||
if os.path.exists(datadir + '/database'):
|
||||
if os.path.isdir(datadir + '/database'):
|
||||
shutil.rmtree(datadir + '/database')
|
||||
|
||||
if os.path.exists(datadir + '/db.log'):
|
||||
os.remove(datadir + '/db.log')
|
||||
sys.exit(0)
|
||||
210
src/txdb.cpp
210
src/txdb.cpp
@@ -22,6 +22,11 @@ static const char DB_NULLIFIER = 's';
|
||||
static const char DB_COINS = 'c';
|
||||
static const char DB_BLOCK_FILES = 'f';
|
||||
static const char DB_TXINDEX = 't';
|
||||
static const char DB_ADDRESSINDEX = 'd';
|
||||
static const char DB_ADDRESSUNSPENTINDEX = 'u';
|
||||
static const char DB_TIMESTAMPINDEX = 'S';
|
||||
static const char DB_BLOCKHASHINDEX = 'z';
|
||||
static const char DB_SPENTINDEX = 'p';
|
||||
static const char DB_BLOCK_INDEX = 'b';
|
||||
|
||||
static const char DB_BEST_BLOCK = 'B';
|
||||
@@ -68,7 +73,7 @@ void static BatchWriteHashBestAnchor(CLevelDBBatch &batch, const uint256 &hash)
|
||||
CCoinsViewDB::CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe) {
|
||||
}
|
||||
|
||||
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
|
||||
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, false, 64) {
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +163,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
|
||||
return db.WriteBatch(batch);
|
||||
}
|
||||
|
||||
CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
|
||||
CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe, bool compression, int maxOpenFiles) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe, compression, maxOpenFiles) {
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
|
||||
@@ -260,6 +265,197 @@ bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos>
|
||||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) {
|
||||
return Read(make_pair(DB_SPENTINDEX, key), value);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::UpdateSpentIndex(const std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> >&vect) {
|
||||
CLevelDBBatch batch;
|
||||
for (std::vector<std::pair<CSpentIndexKey,CSpentIndexValue> >::const_iterator it=vect.begin(); it!=vect.end(); it++) {
|
||||
if (it->second.IsNull()) {
|
||||
batch.Erase(make_pair(DB_SPENTINDEX, it->first));
|
||||
} else {
|
||||
batch.Write(make_pair(DB_SPENTINDEX, it->first), it->second);
|
||||
}
|
||||
}
|
||||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::UpdateAddressUnspentIndex(const std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue > >&vect) {
|
||||
CLevelDBBatch batch;
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=vect.begin(); it!=vect.end(); it++) {
|
||||
if (it->second.IsNull()) {
|
||||
batch.Erase(make_pair(DB_ADDRESSUNSPENTINDEX, it->first));
|
||||
} else {
|
||||
batch.Write(make_pair(DB_ADDRESSUNSPENTINDEX, it->first), it->second);
|
||||
}
|
||||
}
|
||||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadAddressUnspentIndex(uint160 addressHash, int type,
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs) {
|
||||
|
||||
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
||||
|
||||
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
|
||||
ssKeySet << make_pair(DB_ADDRESSUNSPENTINDEX, CAddressIndexIteratorKey(type, addressHash));
|
||||
pcursor->Seek(ssKeySet.str());
|
||||
|
||||
while (pcursor->Valid()) {
|
||||
boost::this_thread::interruption_point();
|
||||
try {
|
||||
leveldb::Slice slKey = pcursor->key();
|
||||
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
||||
char chType;
|
||||
CAddressUnspentKey indexKey;
|
||||
ssKey >> chType;
|
||||
ssKey >> indexKey;
|
||||
if (chType == DB_ADDRESSUNSPENTINDEX && indexKey.hashBytes == addressHash) {
|
||||
try {
|
||||
leveldb::Slice slValue = pcursor->value();
|
||||
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
CAddressUnspentValue nValue;
|
||||
ssValue >> nValue;
|
||||
unspentOutputs.push_back(make_pair(indexKey, nValue));
|
||||
pcursor->Next();
|
||||
} catch (const std::exception& e) {
|
||||
return error("failed to get address unspent value");
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount > >&vect) {
|
||||
CLevelDBBatch batch;
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
|
||||
batch.Write(make_pair(DB_ADDRESSINDEX, it->first), it->second);
|
||||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::EraseAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount > >&vect) {
|
||||
CLevelDBBatch batch;
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
|
||||
batch.Erase(make_pair(DB_ADDRESSINDEX, it->first));
|
||||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type,
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
|
||||
int start, int end) {
|
||||
|
||||
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
||||
|
||||
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
|
||||
if (start > 0 && end > 0) {
|
||||
ssKeySet << make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorHeightKey(type, addressHash, start));
|
||||
} else {
|
||||
ssKeySet << make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorKey(type, addressHash));
|
||||
}
|
||||
pcursor->Seek(ssKeySet.str());
|
||||
|
||||
while (pcursor->Valid()) {
|
||||
boost::this_thread::interruption_point();
|
||||
try {
|
||||
leveldb::Slice slKey = pcursor->key();
|
||||
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
||||
char chType;
|
||||
CAddressIndexKey indexKey;
|
||||
ssKey >> chType;
|
||||
ssKey >> indexKey;
|
||||
if (chType == DB_ADDRESSINDEX && indexKey.hashBytes == addressHash) {
|
||||
if (end > 0 && indexKey.blockHeight > end) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
leveldb::Slice slValue = pcursor->value();
|
||||
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
CAmount nValue;
|
||||
ssValue >> nValue;
|
||||
|
||||
addressIndex.push_back(make_pair(indexKey, nValue));
|
||||
pcursor->Next();
|
||||
} catch (const std::exception& e) {
|
||||
return error("failed to get address index value");
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteTimestampIndex(const CTimestampIndexKey ×tampIndex) {
|
||||
CLevelDBBatch batch;
|
||||
batch.Write(make_pair(DB_TIMESTAMPINDEX, timestampIndex), 0);
|
||||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes) {
|
||||
|
||||
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
||||
|
||||
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
|
||||
ssKeySet << make_pair(DB_TIMESTAMPINDEX, CTimestampIndexIteratorKey(low));
|
||||
pcursor->Seek(ssKeySet.str());
|
||||
|
||||
while (pcursor->Valid()) {
|
||||
boost::this_thread::interruption_point();
|
||||
try {
|
||||
leveldb::Slice slKey = pcursor->key();
|
||||
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
||||
char chType;
|
||||
CTimestampIndexKey indexKey;
|
||||
ssKey >> chType;
|
||||
ssKey >> indexKey;
|
||||
if (chType == DB_TIMESTAMPINDEX && indexKey.timestamp < high) {
|
||||
if (fActiveOnly) {
|
||||
if (blockOnchainActive(indexKey.blockHash)) {
|
||||
hashes.push_back(std::make_pair(indexKey.blockHash, indexKey.timestamp));
|
||||
}
|
||||
} else {
|
||||
hashes.push_back(std::make_pair(indexKey.blockHash, indexKey.timestamp));
|
||||
}
|
||||
|
||||
pcursor->Next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, const CTimestampBlockIndexValue &logicalts) {
|
||||
CLevelDBBatch batch;
|
||||
batch.Write(make_pair(DB_BLOCKHASHINDEX, blockhashIndex), logicalts);
|
||||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadTimestampBlockIndex(const uint256 &hash, unsigned int <imestamp) {
|
||||
|
||||
CTimestampBlockIndexValue(lts);
|
||||
if (!Read(std::make_pair(DB_BLOCKHASHINDEX, hash), lts))
|
||||
return false;
|
||||
|
||||
ltimestamp = lts.ltimestamp;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
|
||||
return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
|
||||
}
|
||||
@@ -274,6 +470,16 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
|
||||
|
||||
void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height);
|
||||
|
||||
bool CBlockTreeDB::blockOnchainActive(const uint256 &hash) {
|
||||
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
||||
|
||||
if (!chainActive.Contains(pblockindex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||
{
|
||||
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
||||
|
||||
28
src/txdb.h
28
src/txdb.h
@@ -17,6 +17,17 @@
|
||||
class CBlockFileInfo;
|
||||
class CBlockIndex;
|
||||
struct CDiskTxPos;
|
||||
struct CAddressUnspentKey;
|
||||
struct CAddressUnspentValue;
|
||||
struct CAddressIndexKey;
|
||||
struct CAddressIndexIteratorKey;
|
||||
struct CAddressIndexIteratorHeightKey;
|
||||
struct CTimestampIndexKey;
|
||||
struct CTimestampIndexIteratorKey;
|
||||
struct CTimestampBlockIndexKey;
|
||||
struct CTimestampBlockIndexValue;
|
||||
struct CSpentIndexKey;
|
||||
struct CSpentIndexValue;
|
||||
class uint256;
|
||||
|
||||
//! -dbcache default (MiB)
|
||||
@@ -53,7 +64,7 @@ public:
|
||||
class CBlockTreeDB : public CLevelDBWrapper
|
||||
{
|
||||
public:
|
||||
CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
|
||||
CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool compression = true, int maxOpenFiles = 1000);
|
||||
private:
|
||||
CBlockTreeDB(const CBlockTreeDB&);
|
||||
void operator=(const CBlockTreeDB&);
|
||||
@@ -65,9 +76,24 @@ public:
|
||||
bool ReadReindexing(bool &fReindex);
|
||||
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
|
||||
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
|
||||
bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
|
||||
bool UpdateSpentIndex(const std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> >&vect);
|
||||
bool UpdateAddressUnspentIndex(const std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue > >&vect);
|
||||
bool ReadAddressUnspentIndex(uint160 addressHash, int type,
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &vect);
|
||||
bool WriteAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount> > &vect);
|
||||
bool EraseAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount> > &vect);
|
||||
bool ReadAddressIndex(uint160 addressHash, int type,
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
|
||||
int start = 0, int end = 0);
|
||||
bool WriteTimestampIndex(const CTimestampIndexKey ×tampIndex);
|
||||
bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &vect);
|
||||
bool WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, const CTimestampBlockIndexValue &logicalts);
|
||||
bool ReadTimestampBlockIndex(const uint256 &hash, unsigned int &logicalTS);
|
||||
bool WriteFlag(const std::string &name, bool fValue);
|
||||
bool ReadFlag(const std::string &name, bool &fValue);
|
||||
bool LoadBlockIndexGuts();
|
||||
bool blockOnchainActive(const uint256 &hash);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_TXDB_H
|
||||
|
||||
@@ -119,6 +119,144 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view)
|
||||
{
|
||||
LOCK(cs);
|
||||
const CTransaction& tx = entry.GetTx();
|
||||
std::vector<CMempoolAddressDeltaKey> inserted;
|
||||
|
||||
uint256 txhash = tx.GetHash();
|
||||
for (unsigned int j = 0; j < tx.vin.size(); j++) {
|
||||
const CTxIn input = tx.vin[j];
|
||||
const CTxOut &prevout = view.GetOutputFor(input);
|
||||
if (prevout.scriptPubKey.IsPayToScriptHash()) {
|
||||
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);
|
||||
CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, j, 1);
|
||||
CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n);
|
||||
mapAddress.insert(make_pair(key, delta));
|
||||
inserted.push_back(key);
|
||||
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);
|
||||
CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, j, 1);
|
||||
CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n);
|
||||
mapAddress.insert(make_pair(key, delta));
|
||||
inserted.push_back(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int k = 0; k < tx.vout.size(); k++) {
|
||||
const CTxOut &out = tx.vout[k];
|
||||
if (out.scriptPubKey.IsPayToScriptHash()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
|
||||
CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, k, 0);
|
||||
mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
|
||||
inserted.push_back(key);
|
||||
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
|
||||
std::pair<addressDeltaMap::iterator,bool> ret;
|
||||
CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, k, 0);
|
||||
mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
|
||||
inserted.push_back(key);
|
||||
}
|
||||
}
|
||||
|
||||
mapAddressInserted.insert(make_pair(txhash, inserted));
|
||||
}
|
||||
|
||||
bool CTxMemPool::getAddressIndex(std::vector<std::pair<uint160, int> > &addresses,
|
||||
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results)
|
||||
{
|
||||
LOCK(cs);
|
||||
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
|
||||
addressDeltaMap::iterator ait = mapAddress.lower_bound(CMempoolAddressDeltaKey((*it).second, (*it).first));
|
||||
while (ait != mapAddress.end() && (*ait).first.addressBytes == (*it).first && (*ait).first.type == (*it).second) {
|
||||
results.push_back(*ait);
|
||||
ait++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTxMemPool::removeAddressIndex(const uint256 txhash)
|
||||
{
|
||||
LOCK(cs);
|
||||
addressDeltaMapInserted::iterator it = mapAddressInserted.find(txhash);
|
||||
|
||||
if (it != mapAddressInserted.end()) {
|
||||
std::vector<CMempoolAddressDeltaKey> keys = (*it).second;
|
||||
for (std::vector<CMempoolAddressDeltaKey>::iterator mit = keys.begin(); mit != keys.end(); mit++) {
|
||||
mapAddress.erase(*mit);
|
||||
}
|
||||
mapAddressInserted.erase(it);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view)
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
const CTransaction& tx = entry.GetTx();
|
||||
std::vector<CSpentIndexKey> inserted;
|
||||
|
||||
uint256 txhash = tx.GetHash();
|
||||
for (unsigned int j = 0; j < tx.vin.size(); j++) {
|
||||
const CTxIn input = tx.vin[j];
|
||||
const CTxOut &prevout = view.GetOutputFor(input);
|
||||
uint160 addressHash;
|
||||
int addressType;
|
||||
|
||||
if (prevout.scriptPubKey.IsPayToScriptHash()) {
|
||||
addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
|
||||
addressType = 2;
|
||||
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||
addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
|
||||
addressType = 1;
|
||||
} else {
|
||||
addressHash.SetNull();
|
||||
addressType = 0;
|
||||
}
|
||||
|
||||
CSpentIndexKey key = CSpentIndexKey(input.prevout.hash, input.prevout.n);
|
||||
CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, addressType, addressHash);
|
||||
|
||||
mapSpent.insert(make_pair(key, value));
|
||||
inserted.push_back(key);
|
||||
|
||||
}
|
||||
|
||||
mapSpentInserted.insert(make_pair(txhash, inserted));
|
||||
}
|
||||
|
||||
bool CTxMemPool::getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
|
||||
{
|
||||
LOCK(cs);
|
||||
mapSpentIndex::iterator it;
|
||||
|
||||
it = mapSpent.find(key);
|
||||
if (it != mapSpent.end()) {
|
||||
value = it->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CTxMemPool::removeSpentIndex(const uint256 txhash)
|
||||
{
|
||||
LOCK(cs);
|
||||
mapSpentIndexInserted::iterator it = mapSpentInserted.find(txhash);
|
||||
|
||||
if (it != mapSpentInserted.end()) {
|
||||
std::vector<CSpentIndexKey> keys = (*it).second;
|
||||
for (std::vector<CSpentIndexKey>::iterator mit = keys.begin(); mit != keys.end(); mit++) {
|
||||
mapSpent.erase(*mit);
|
||||
}
|
||||
mapSpentInserted.erase(it);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& removed, bool fRecursive)
|
||||
{
|
||||
@@ -168,6 +306,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
|
||||
mapTx.erase(hash);
|
||||
nTransactionsUpdated++;
|
||||
minerPolicyEstimator->removeTx(hash);
|
||||
removeAddressIndex(hash);
|
||||
removeSpentIndex(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "addressindex.h"
|
||||
#include "spentindex.h"
|
||||
#include "amount.h"
|
||||
#include "coins.h"
|
||||
#include "primitives/transaction.h"
|
||||
@@ -147,6 +149,21 @@ public:
|
||||
|
||||
mutable CCriticalSection cs;
|
||||
indexed_transaction_set mapTx;
|
||||
|
||||
private:
|
||||
typedef std::map<CMempoolAddressDeltaKey, CMempoolAddressDelta, CMempoolAddressDeltaKeyCompare> addressDeltaMap;
|
||||
addressDeltaMap mapAddress;
|
||||
|
||||
typedef std::map<uint256, std::vector<CMempoolAddressDeltaKey> > addressDeltaMapInserted;
|
||||
addressDeltaMapInserted mapAddressInserted;
|
||||
|
||||
typedef std::map<CSpentIndexKey, CSpentIndexValue, CSpentIndexKeyCompare> mapSpentIndex;
|
||||
mapSpentIndex mapSpent;
|
||||
|
||||
typedef std::map<uint256, std::vector<CSpentIndexKey> > mapSpentIndexInserted;
|
||||
mapSpentIndexInserted mapSpentInserted;
|
||||
|
||||
public:
|
||||
std::map<COutPoint, CInPoint> mapNextTx;
|
||||
std::map<uint256, const CTransaction*> mapNullifiers;
|
||||
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
|
||||
@@ -164,6 +181,14 @@ public:
|
||||
void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967296.0; }
|
||||
|
||||
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true);
|
||||
void addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
|
||||
bool getAddressIndex(std::vector<std::pair<uint160, int> > &addresses,
|
||||
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results);
|
||||
bool removeAddressIndex(const uint256 txhash);
|
||||
|
||||
void addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
|
||||
bool getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
|
||||
bool removeSpentIndex(const uint256 txhash);
|
||||
void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
|
||||
void removeWithAnchor(const uint256 &invalidRoot);
|
||||
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
|
||||
|
||||
339
src/wallet-utility.cpp
Normal file
339
src/wallet-utility.cpp
Normal file
@@ -0,0 +1,339 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
// Include local headers
|
||||
#include "wallet/walletdb.h"
|
||||
#include "util.h"
|
||||
#include "base58.h"
|
||||
#include "wallet/crypter.h"
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
|
||||
void show_help()
|
||||
{
|
||||
std::cout <<
|
||||
"This program outputs Bitcoin addresses and private keys from a wallet.dat file" << std::endl
|
||||
<< std::endl
|
||||
<< "Usage and options: "
|
||||
<< std::endl
|
||||
<< " -datadir=<directory> to tell the program where your wallet is"
|
||||
<< std::endl
|
||||
<< " -wallet=<name> (Optional) if your wallet is not named wallet.dat"
|
||||
<< std::endl
|
||||
<< " -regtest or -testnet (Optional) dumps addresses from regtest/testnet"
|
||||
<< std::endl
|
||||
<< " -dumppass (Optional)if you want to extract private keys associated with addresses"
|
||||
<< std::endl
|
||||
<< " -pass=<walletpassphrase> if you have encrypted private keys stored in your wallet"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
class WalletUtilityDB : public CDB
|
||||
{
|
||||
private:
|
||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||
MasterKeyMap mapMasterKeys;
|
||||
unsigned int nMasterKeyMaxID;
|
||||
SecureString mPass;
|
||||
std::vector<CKeyingMaterial> vMKeys;
|
||||
|
||||
public:
|
||||
WalletUtilityDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose)
|
||||
{
|
||||
nMasterKeyMaxID = 0;
|
||||
mPass.reserve(100);
|
||||
}
|
||||
|
||||
std::string getAddress(CDataStream ssKey);
|
||||
std::string getKey(CDataStream ssKey, CDataStream ssValue);
|
||||
std::string getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass);
|
||||
bool updateMasterKeys(CDataStream ssKey, CDataStream ssValue);
|
||||
bool parseKeys(bool dumppriv, std::string masterPass);
|
||||
|
||||
bool DecryptSecret(const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
|
||||
bool Unlock();
|
||||
bool DecryptKey(const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Address from a public key in base58
|
||||
*/
|
||||
std::string WalletUtilityDB::getAddress(CDataStream ssKey)
|
||||
{
|
||||
CPubKey vchPubKey;
|
||||
ssKey >> vchPubKey;
|
||||
CKeyID id = vchPubKey.GetID();
|
||||
std::string strAddr = CBitcoinAddress(id).ToString();
|
||||
|
||||
return strAddr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Non encrypted private key in WIF
|
||||
*/
|
||||
std::string WalletUtilityDB::getKey(CDataStream ssKey, CDataStream ssValue)
|
||||
{
|
||||
std::string strKey;
|
||||
CPubKey vchPubKey;
|
||||
ssKey >> vchPubKey;
|
||||
CPrivKey pkey;
|
||||
CKey key;
|
||||
|
||||
ssValue >> pkey;
|
||||
if (key.Load(pkey, vchPubKey, true))
|
||||
strKey = CBitcoinSecret(key).ToString();
|
||||
|
||||
return strKey;
|
||||
}
|
||||
|
||||
|
||||
bool WalletUtilityDB::DecryptSecret(const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
|
||||
{
|
||||
CCrypter cKeyCrypter;
|
||||
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
|
||||
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
|
||||
|
||||
BOOST_FOREACH(const CKeyingMaterial vMKey, vMKeys)
|
||||
{
|
||||
if(!cKeyCrypter.SetKey(vMKey, chIV))
|
||||
continue;
|
||||
if (cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool WalletUtilityDB::Unlock()
|
||||
{
|
||||
CCrypter crypter;
|
||||
CKeyingMaterial vMasterKey;
|
||||
|
||||
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
|
||||
{
|
||||
if(!crypter.SetKeyFromPassphrase(mPass, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
|
||||
return false;
|
||||
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
|
||||
continue; // try another master key
|
||||
vMKeys.push_back(vMasterKey);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool WalletUtilityDB::DecryptKey(const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
|
||||
{
|
||||
CKeyingMaterial vchSecret;
|
||||
if(!DecryptSecret(vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
|
||||
return false;
|
||||
|
||||
if (vchSecret.size() != 32)
|
||||
return false;
|
||||
|
||||
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encrypted private key in WIF format
|
||||
*/
|
||||
std::string WalletUtilityDB::getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass)
|
||||
{
|
||||
mPass = masterPass.c_str();
|
||||
CPubKey vchPubKey;
|
||||
ssKey >> vchPubKey;
|
||||
CKey key;
|
||||
|
||||
std::vector<unsigned char> vKey;
|
||||
ssValue >> vKey;
|
||||
|
||||
if (!Unlock())
|
||||
return "";
|
||||
|
||||
if(!DecryptKey(vKey, vchPubKey, key))
|
||||
return "";
|
||||
|
||||
std::string strKey = CBitcoinSecret(key).ToString();
|
||||
return strKey;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Master key derivation
|
||||
*/
|
||||
bool WalletUtilityDB::updateMasterKeys(CDataStream ssKey, CDataStream ssValue)
|
||||
{
|
||||
unsigned int nID;
|
||||
ssKey >> nID;
|
||||
CMasterKey kMasterKey;
|
||||
ssValue >> kMasterKey;
|
||||
if (mapMasterKeys.count(nID) != 0)
|
||||
{
|
||||
std::cout << "Error reading wallet database: duplicate CMasterKey id " << nID << std::endl;
|
||||
return false;
|
||||
}
|
||||
mapMasterKeys[nID] = kMasterKey;
|
||||
|
||||
if (nMasterKeyMaxID < nID)
|
||||
nMasterKeyMaxID = nID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Look at all the records and parse keys for addresses and private keys
|
||||
*/
|
||||
bool WalletUtilityDB::parseKeys(bool dumppriv, std::string masterPass)
|
||||
{
|
||||
DBErrors result = DB_LOAD_OK;
|
||||
std::string strType;
|
||||
bool first = true;
|
||||
|
||||
try {
|
||||
Dbc* pcursor = GetCursor();
|
||||
if (!pcursor)
|
||||
{
|
||||
LogPrintf("Error getting wallet database cursor\n");
|
||||
result = DB_CORRUPT;
|
||||
}
|
||||
|
||||
if (dumppriv)
|
||||
{
|
||||
while (result == DB_LOAD_OK && true)
|
||||
{
|
||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
||||
int result = ReadAtCursor(pcursor, ssKey, ssValue);
|
||||
|
||||
if (result == DB_NOTFOUND) {
|
||||
break;
|
||||
}
|
||||
else if (result != 0)
|
||||
{
|
||||
LogPrintf("Error reading next record from wallet database\n");
|
||||
result = DB_CORRUPT;
|
||||
break;
|
||||
}
|
||||
|
||||
ssKey >> strType;
|
||||
if (strType == "mkey")
|
||||
{
|
||||
updateMasterKeys(ssKey, ssValue);
|
||||
}
|
||||
}
|
||||
pcursor->close();
|
||||
pcursor = GetCursor();
|
||||
}
|
||||
|
||||
while (result == DB_LOAD_OK && true)
|
||||
{
|
||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
||||
int ret = ReadAtCursor(pcursor, ssKey, ssValue);
|
||||
|
||||
if (ret == DB_NOTFOUND)
|
||||
{
|
||||
std::cout << " ]" << std::endl;
|
||||
first = true;
|
||||
break;
|
||||
}
|
||||
else if (ret != DB_LOAD_OK)
|
||||
{
|
||||
LogPrintf("Error reading next record from wallet database\n");
|
||||
result = DB_CORRUPT;
|
||||
break;
|
||||
}
|
||||
|
||||
ssKey >> strType;
|
||||
|
||||
if (strType == "key" || strType == "ckey")
|
||||
{
|
||||
std::string strAddr = getAddress(ssKey);
|
||||
std::string strKey = "";
|
||||
|
||||
|
||||
if (dumppriv && strType == "key")
|
||||
strKey = getKey(ssKey, ssValue);
|
||||
if (dumppriv && strType == "ckey")
|
||||
{
|
||||
if (masterPass == "")
|
||||
{
|
||||
std::cout << "Encrypted wallet, please provide a password. See help below" << std::endl;
|
||||
show_help();
|
||||
result = DB_LOAD_FAIL;
|
||||
break;
|
||||
}
|
||||
strKey = getCryptedKey(ssKey, ssValue, masterPass);
|
||||
}
|
||||
|
||||
if (strAddr != "")
|
||||
{
|
||||
if (first)
|
||||
std::cout << "[ ";
|
||||
else
|
||||
std::cout << ", ";
|
||||
}
|
||||
|
||||
if (dumppriv)
|
||||
{
|
||||
std::cout << "{\"addr\" : \"" + strAddr + "\", "
|
||||
<< "\"pkey\" : \"" + strKey + "\"}"
|
||||
<< std::flush;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "\"" + strAddr + "\"";
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
pcursor->close();
|
||||
} catch (DbException &e) {
|
||||
std::cout << "DBException caught " << e.get_errno() << std::endl;
|
||||
} catch (std::exception &e) {
|
||||
std::cout << "Exception caught " << std::endl;
|
||||
}
|
||||
|
||||
if (result == DB_LOAD_OK)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
ParseParameters(argc, argv);
|
||||
std::string walletFile = GetArg("-wallet", "wallet.dat");
|
||||
std::string masterPass = GetArg("-pass", "");
|
||||
bool fDumpPass = GetBoolArg("-dumppass", false);
|
||||
bool help = GetBoolArg("-h", false);
|
||||
bool result = false;
|
||||
|
||||
if (help)
|
||||
{
|
||||
show_help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
SelectParamsFromCommandLine();
|
||||
result = WalletUtilityDB(walletFile, "r").parseKeys(fDumpPass, masterPass);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cout << "Error opening wallet file " << walletFile << std::endl;
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
if (result)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
Reference in New Issue
Block a user