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 upgrade && \
|
||||||
apt-get -y install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev \
|
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 \
|
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 && \
|
apt-get clean && \
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
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)
|
BITCOIND_BIN=$(top_builddir)/src/zcashd$(EXEEXT)
|
||||||
BITCOIN_CLI_BIN=$(top_builddir)/src/zcash-cli$(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)
|
BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT)
|
||||||
|
|
||||||
if TARGET_DARWIN
|
if TARGET_DARWIN
|
||||||
@@ -32,26 +33,26 @@ endif
|
|||||||
DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md)
|
DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md)
|
||||||
|
|
||||||
BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \
|
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 \
|
WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \
|
||||||
$(top_srcdir)/share/pixmaps/nsis-header.bmp \
|
$(top_srcdir)/share/pixmaps/nsis-header.bmp \
|
||||||
$(top_srcdir)/share/pixmaps/nsis-wizard.bmp
|
$(top_srcdir)/share/pixmaps/nsis-wizard.bmp
|
||||||
|
|
||||||
if TARGET_DARWIN
|
if TARGET_DARWIN
|
||||||
OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) $(OSX_BASE_LPROJ_DIR) \
|
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/$(OSX_BACKGROUND_IMAGE) \
|
||||||
$(top_srcdir)/contrib/macdeploy/DS_Store \
|
$(top_srcdir)/contrib/macdeploy/DS_Store \
|
||||||
$(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \
|
$(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \
|
||||||
$(top_srcdir)/contrib/macdeploy/detached-sig-create.sh
|
$(top_srcdir)/contrib/macdeploy/detached-sig-create.sh
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if TARGET_DARWIN
|
if TARGET_DARWIN
|
||||||
COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \
|
COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \
|
||||||
leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \
|
leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \
|
||||||
baseline_filtered.info block_test_filtered.info \
|
baseline_filtered.info block_test_filtered.info \
|
||||||
leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info
|
leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info
|
||||||
# zcash-gtest.info zcash-gtest_filtered.info zcash-gtest_coverage.info
|
# zcash-gtest.info zcash-gtest_filtered.info zcash-gtest_coverage.info
|
||||||
else
|
else
|
||||||
COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \
|
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) $< $@
|
$(INSTALL_DATA) $< $@
|
||||||
|
|
||||||
OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \
|
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/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/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -155,6 +156,9 @@ $(BITCOIND_BIN): FORCE
|
|||||||
$(BITCOIN_CLI_BIN): FORCE
|
$(BITCOIN_CLI_BIN): FORCE
|
||||||
$(MAKE) -C src $(@F)
|
$(MAKE) -C src $(@F)
|
||||||
|
|
||||||
|
$(WALLET_UTILITY_BIN): FORCE
|
||||||
|
$(MAKE) -C src $(@F)
|
||||||
|
|
||||||
if USE_LCOV
|
if USE_LCOV
|
||||||
|
|
||||||
baseline.info:
|
baseline.info:
|
||||||
@@ -163,27 +167,27 @@ baseline.info:
|
|||||||
if BUILD_DARWIN
|
if BUILD_DARWIN
|
||||||
baseline_filtered.info: baseline.info
|
baseline_filtered.info: baseline.info
|
||||||
$(LCOV) -r $< "/usr/include/*" \
|
$(LCOV) -r $< "/usr/include/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||||
"$(abs_builddir)/src/gtest/*" \
|
"$(abs_builddir)/src/gtest/*" \
|
||||||
"$(abs_builddir)/src/test/*" \
|
"$(abs_builddir)/src/test/*" \
|
||||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||||
"$(abs_builddir)/src/wallet/test/*" \
|
"$(abs_builddir)/src/wallet/test/*" \
|
||||||
-o $@
|
-o $@
|
||||||
else
|
else
|
||||||
baseline_filtered.info: baseline.info
|
baseline_filtered.info: baseline.info
|
||||||
$(LCOV) -r $< "/usr/include/*" \
|
$(LCOV) -r $< "/usr/include/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
"$(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/boost/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||||
"$(abs_builddir)/src/gtest/*" \
|
"$(abs_builddir)/src/gtest/*" \
|
||||||
"$(abs_builddir)/src/test/*" \
|
"$(abs_builddir)/src/test/*" \
|
||||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||||
"$(abs_builddir)/src/wallet/test/*" \
|
"$(abs_builddir)/src/wallet/test/*" \
|
||||||
-o $@
|
-o $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
leveldb_baseline.info: baseline_filtered.info
|
leveldb_baseline.info: baseline_filtered.info
|
||||||
@@ -192,27 +196,27 @@ leveldb_baseline.info: baseline_filtered.info
|
|||||||
if BUILD_DARWIN
|
if BUILD_DARWIN
|
||||||
leveldb_baseline_filtered.info: leveldb_baseline.info
|
leveldb_baseline_filtered.info: leveldb_baseline.info
|
||||||
$(LCOV) -r $< "/usr/include/*" \
|
$(LCOV) -r $< "/usr/include/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||||
"$(abs_builddir)/src/gtest/*" \
|
"$(abs_builddir)/src/gtest/*" \
|
||||||
"$(abs_builddir)/src/test/*" \
|
"$(abs_builddir)/src/test/*" \
|
||||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||||
"$(abs_builddir)/src/wallet/test/*" \
|
"$(abs_builddir)/src/wallet/test/*" \
|
||||||
-o $@
|
-o $@
|
||||||
else
|
else
|
||||||
leveldb_baseline_filtered.info: leveldb_baseline.info
|
leveldb_baseline_filtered.info: leveldb_baseline.info
|
||||||
$(LCOV) -r $< "/usr/include/*" \
|
$(LCOV) -r $< "/usr/include/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
"$(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/boost/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||||
"$(abs_builddir)/src/gtest/*" \
|
"$(abs_builddir)/src/gtest/*" \
|
||||||
"$(abs_builddir)/src/test/*" \
|
"$(abs_builddir)/src/test/*" \
|
||||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||||
"$(abs_builddir)/src/wallet/test/*" \
|
"$(abs_builddir)/src/wallet/test/*" \
|
||||||
-o $@
|
-o $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
baseline_filtered_combined.info: leveldb_baseline_filtered.info baseline_filtered.info
|
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
|
if BUILD_DARWIN
|
||||||
test_bitcoin_filtered.info: test_bitcoin.info
|
test_bitcoin_filtered.info: test_bitcoin.info
|
||||||
$(LCOV) -r $< "/usr/include/*" \
|
$(LCOV) -r $< "/usr/include/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||||
"$(abs_builddir)/src/gtest/*" \
|
"$(abs_builddir)/src/gtest/*" \
|
||||||
"$(abs_builddir)/src/test/*" \
|
"$(abs_builddir)/src/test/*" \
|
||||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||||
"$(abs_builddir)/src/wallet/test/*" \
|
"$(abs_builddir)/src/wallet/test/*" \
|
||||||
-o $@
|
-o $@
|
||||||
else
|
else
|
||||||
test_bitcoin_filtered.info: test_bitcoin.info
|
test_bitcoin_filtered.info: test_bitcoin.info
|
||||||
$(LCOV) -r $< "/usr/include/*" \
|
$(LCOV) -r $< "/usr/include/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
"$(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/boost/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||||
"$(abs_builddir)/src/gtest/*" \
|
"$(abs_builddir)/src/gtest/*" \
|
||||||
"$(abs_builddir)/src/test/*" \
|
"$(abs_builddir)/src/test/*" \
|
||||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||||
"$(abs_builddir)/src/wallet/test/*" \
|
"$(abs_builddir)/src/wallet/test/*" \
|
||||||
-o $@
|
-o $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
@@ -261,32 +265,32 @@ block_test.info: test_bitcoin_filtered.info
|
|||||||
if BUILD_DARWIN
|
if BUILD_DARWIN
|
||||||
block_test_filtered.info: block_test.info
|
block_test_filtered.info: block_test.info
|
||||||
$(LCOV) -r $< "/usr/include/*" \
|
$(LCOV) -r $< "/usr/include/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
"$(abs_builddir)/depends/$(BUILD)/include/*.h" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/boost/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \
|
||||||
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
"$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \
|
||||||
"$(abs_builddir)/src/gtest/*" \
|
"$(abs_builddir)/src/gtest/*" \
|
||||||
"$(abs_builddir)/src/test/*" \
|
"$(abs_builddir)/src/test/*" \
|
||||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||||
"$(abs_builddir)/src/wallet/test/*" \
|
"$(abs_builddir)/src/wallet/test/*" \
|
||||||
-o $@
|
-o $@
|
||||||
else
|
else
|
||||||
block_test_filtered.info: block_test.info
|
block_test_filtered.info: block_test.info
|
||||||
$(LCOV) -r $< "/usr/include/*" \
|
$(LCOV) -r $< "/usr/include/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
"$(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/boost/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||||
"$(abs_builddir)/src/gtest/*" \
|
"$(abs_builddir)/src/gtest/*" \
|
||||||
"$(abs_builddir)/src/test/*" \
|
"$(abs_builddir)/src/test/*" \
|
||||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||||
"$(abs_builddir)/src/wallet/test/*" \
|
"$(abs_builddir)/src/wallet/test/*" \
|
||||||
-o $@
|
-o $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info
|
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
|
if ! BUILD_DARWIN
|
||||||
zcash-gtest_coverage.info: baseline_filtered_combined.info zcash-gtest_filtered.info
|
zcash-gtest_coverage.info: baseline_filtered_combined.info zcash-gtest_filtered.info
|
||||||
@@ -295,7 +299,7 @@ endif
|
|||||||
|
|
||||||
if BUILD_DARWIN
|
if BUILD_DARWIN
|
||||||
total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info zcash-gtest_filtered.info block_test_filtered.info
|
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
|
else
|
||||||
total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info zcash-gtest_filtered.info block_test_filtered.info
|
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
|
||||||
@@ -303,19 +307,19 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info
|
test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info
|
||||||
$(GENHTML) -s $< -o $(@D)
|
$(GENHTML) -s $< -o $(@D)
|
||||||
@touch $@
|
@touch $@
|
||||||
|
|
||||||
if TARGET_DARWIN
|
if TARGET_DARWIN
|
||||||
zcash-gtest.coverage/.dirstamp: zcash-gtest_coverage.info
|
zcash-gtest.coverage/.dirstamp: zcash-gtest_coverage.info
|
||||||
$(GENHTML) -s $< -o $(@D)
|
$(GENHTML) -s $< -o $(@D)
|
||||||
@touch $@
|
@touch $@
|
||||||
cov-zcash: zcash-gtest.coverage/.dirstamp
|
cov-zcash: zcash-gtest.coverage/.dirstamp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
total.coverage/.dirstamp: total_coverage.info
|
total.coverage/.dirstamp: total_coverage.info
|
||||||
$(GENHTML) -s $< -o $(@D)
|
$(GENHTML) -s $< -o $(@D)
|
||||||
@touch $@
|
@touch $@
|
||||||
|
|
||||||
if BUILD_DARWIN
|
if BUILD_DARWIN
|
||||||
cov: test_bitcoin.coverage/.dirstamp cov-zcash total.coverage/.dirstamp
|
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
|
## Komodod
|
||||||
This software is Komodo client, generally you will use this if you want to mine KMD or setup a full node.
|
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.
|
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:
|
#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
|
Komodo
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS"
|
|||||||
|
|
||||||
AC_ARG_WITH([utils],
|
AC_ARG_WITH([utils],
|
||||||
[AS_HELP_STRING([--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=$withval],
|
||||||
[build_bitcoin_utils=yes])
|
[build_bitcoin_utils=yes])
|
||||||
|
|
||||||
@@ -805,7 +805,7 @@ AC_MSG_CHECKING([whether to build bitcoind])
|
|||||||
AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes])
|
AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes])
|
||||||
AC_MSG_RESULT($build_bitcoind)
|
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])
|
AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes])
|
||||||
AC_MSG_RESULT($build_bitcoin_utils)
|
AC_MSG_RESULT($build_bitcoin_utils)
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ testScripts=(
|
|||||||
'key_import_export.py'
|
'key_import_export.py'
|
||||||
'nodehandling.py'
|
'nodehandling.py'
|
||||||
'reindex.py'
|
'reindex.py'
|
||||||
|
'addressindex.py'
|
||||||
|
'timestampindex.py'
|
||||||
|
'spentindex.py'
|
||||||
'decodescript.py'
|
'decodescript.py'
|
||||||
'disablewallet.py'
|
'disablewallet.py'
|
||||||
'zcjoinsplit.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
|
# 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:
|
# But to build the less dependent modules first, we manually select their order here:
|
||||||
EXTRA_LIBRARIES = \
|
EXTRA_LIBRARIES = \
|
||||||
crypto/libbitcoin_crypto.a \
|
crypto/libbitcoin_crypto.a \
|
||||||
libbitcoin_util.a \
|
libbitcoin_util.a \
|
||||||
libbitcoin_common.a \
|
libbitcoin_common.a \
|
||||||
libbitcoin_server.a \
|
libbitcoin_server.a \
|
||||||
libbitcoin_cli.a \
|
libbitcoin_cli.a \
|
||||||
libzcash.a
|
libzcash.a
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
|
BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
|
||||||
EXTRA_LIBRARIES += libbitcoin_wallet.a
|
EXTRA_LIBRARIES += libbitcoin_wallet.a
|
||||||
@@ -105,7 +105,10 @@ if BUILD_BITCOIND
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_BITCOIN_UTILS
|
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
|
endif
|
||||||
|
|
||||||
LIBZCASH_H = \
|
LIBZCASH_H = \
|
||||||
@@ -122,6 +125,8 @@ LIBZCASH_H = \
|
|||||||
.PHONY: FORCE collate-libsnark check-symbols check-security
|
.PHONY: FORCE collate-libsnark check-symbols check-security
|
||||||
# bitcoin core #
|
# bitcoin core #
|
||||||
BITCOIN_CORE_H = \
|
BITCOIN_CORE_H = \
|
||||||
|
addressindex.h \
|
||||||
|
spentindex.h \
|
||||||
addrman.h \
|
addrman.h \
|
||||||
alert.h \
|
alert.h \
|
||||||
amount.h \
|
amount.h \
|
||||||
@@ -235,7 +240,7 @@ BITCOIN_CORE_H = \
|
|||||||
obj/build.h: FORCE
|
obj/build.h: FORCE
|
||||||
@$(MKDIR_P) $(builddir)/obj
|
@$(MKDIR_P) $(builddir)/obj
|
||||||
@$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \
|
@$(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
|
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
|
||||||
|
|
||||||
# server: zcashd
|
# server: zcashd
|
||||||
@@ -292,9 +297,9 @@ LIBBITCOIN_ZMQ=libbitcoin_zmq.a
|
|||||||
libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
|
libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
|
||||||
libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
libbitcoin_zmq_a_SOURCES = \
|
libbitcoin_zmq_a_SOURCES = \
|
||||||
zmq/zmqabstractnotifier.cpp \
|
zmq/zmqabstractnotifier.cpp \
|
||||||
zmq/zmqnotificationinterface.cpp \
|
zmq/zmqnotificationinterface.cpp \
|
||||||
zmq/zmqpublishnotifier.cpp
|
zmq/zmqpublishnotifier.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ENABLE_PROTON
|
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_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES)
|
||||||
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
crypto_libbitcoin_crypto_a_SOURCES = \
|
crypto_libbitcoin_crypto_a_SOURCES = \
|
||||||
crypto/common.h \
|
crypto/common.h \
|
||||||
crypto/equihash.cpp \
|
crypto/equihash.cpp \
|
||||||
crypto/equihash.h \
|
crypto/equihash.h \
|
||||||
crypto/equihash.tcc \
|
crypto/equihash.tcc \
|
||||||
crypto/hmac_sha256.cpp \
|
crypto/hmac_sha256.cpp \
|
||||||
crypto/hmac_sha256.h \
|
crypto/hmac_sha256.h \
|
||||||
crypto/hmac_sha512.cpp \
|
crypto/hmac_sha512.cpp \
|
||||||
crypto/hmac_sha512.h \
|
crypto/hmac_sha512.h \
|
||||||
crypto/ripemd160.cpp \
|
crypto/ripemd160.cpp \
|
||||||
crypto/ripemd160.h \
|
crypto/ripemd160.h \
|
||||||
crypto/sha1.cpp \
|
crypto/sha1.cpp \
|
||||||
crypto/sha1.h \
|
crypto/sha1.h \
|
||||||
crypto/sha256.cpp \
|
crypto/sha256.cpp \
|
||||||
crypto/sha256.h \
|
crypto/sha256.h \
|
||||||
crypto/sha512.cpp \
|
crypto/sha512.cpp \
|
||||||
crypto/sha512.h
|
crypto/sha512.h
|
||||||
|
|
||||||
if ENABLE_MINING
|
if ENABLE_MINING
|
||||||
EQUIHASH_TROMP_SOURCES = \
|
EQUIHASH_TROMP_SOURCES = \
|
||||||
pow/tromp/equi_miner.h \
|
pow/tromp/equi_miner.h \
|
||||||
pow/tromp/equi.h \
|
pow/tromp/equi.h \
|
||||||
pow/tromp/osx_barrier.h
|
pow/tromp/osx_barrier.h
|
||||||
|
|
||||||
crypto_libbitcoin_crypto_a_CPPFLAGS += \
|
crypto_libbitcoin_crypto_a_CPPFLAGS += \
|
||||||
-DEQUIHASH_TROMP_ATOMIC
|
-DEQUIHASH_TROMP_ATOMIC
|
||||||
crypto_libbitcoin_crypto_a_SOURCES += \
|
crypto_libbitcoin_crypto_a_SOURCES += \
|
||||||
${EQUIHASH_TROMP_SOURCES}
|
${EQUIHASH_TROMP_SOURCES}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# common: shared between zcashd and non-server tools
|
# 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_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
||||||
libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
libbitcoin_util_a_SOURCES = \
|
libbitcoin_util_a_SOURCES = \
|
||||||
support/pagelocker.cpp \
|
support/pagelocker.cpp \
|
||||||
chainparamsbase.cpp \
|
chainparamsbase.cpp \
|
||||||
clientversion.cpp \
|
clientversion.cpp \
|
||||||
compat/glibc_sanity.cpp \
|
compat/glibc_sanity.cpp \
|
||||||
compat/glibcxx_sanity.cpp \
|
compat/glibcxx_sanity.cpp \
|
||||||
compat/strnlen.cpp \
|
compat/strnlen.cpp \
|
||||||
random.cpp \
|
random.cpp \
|
||||||
rpcprotocol.cpp \
|
rpcprotocol.cpp \
|
||||||
support/cleanse.cpp \
|
support/cleanse.cpp \
|
||||||
sync.cpp \
|
sync.cpp \
|
||||||
uint256.cpp \
|
uint256.cpp \
|
||||||
util.cpp \
|
util.cpp \
|
||||||
utilmoneystr.cpp \
|
utilmoneystr.cpp \
|
||||||
utilstrencodings.cpp \
|
utilstrencodings.cpp \
|
||||||
utiltime.cpp \
|
utiltime.cpp \
|
||||||
$(BITCOIN_CORE_H) \
|
$(BITCOIN_CORE_H) \
|
||||||
$(LIBZCASH_H)
|
$(LIBZCASH_H)
|
||||||
|
|
||||||
if GLIBC_BACK_COMPAT
|
if GLIBC_BACK_COMPAT
|
||||||
libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp
|
libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp
|
||||||
@@ -428,9 +433,9 @@ endif
|
|||||||
libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
||||||
libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
libbitcoin_cli_a_SOURCES = \
|
libbitcoin_cli_a_SOURCES = \
|
||||||
rpcclient.cpp \
|
rpcclient.cpp \
|
||||||
$(BITCOIN_CORE_H) \
|
$(BITCOIN_CORE_H) \
|
||||||
$(LIBZCASH_H)
|
$(LIBZCASH_H)
|
||||||
|
|
||||||
nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.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_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
komodo_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
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
|
if TARGET_WINDOWS
|
||||||
komodo_cli_SOURCES += bitcoin-cli-res.rc
|
komodo_cli_SOURCES += bitcoin-cli-res.rc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
komodo_cli_LDADD = \
|
komodo_cli_LDADD = \
|
||||||
$(LIBBITCOIN_CLI) \
|
$(LIBBITCOIN_CLI) \
|
||||||
$(LIBUNIVALUE) \
|
$(LIBUNIVALUE) \
|
||||||
$(LIBBITCOIN_UTIL) \
|
$(LIBBITCOIN_UTIL) \
|
||||||
$(BOOST_LIBS) \
|
$(BOOST_LIBS) \
|
||||||
$(SSL_LIBS) \
|
$(SSL_LIBS) \
|
||||||
$(CRYPTO_LIBS) \
|
$(CRYPTO_LIBS) \
|
||||||
$(EVENT_LIBS) \
|
$(EVENT_LIBS) \
|
||||||
$(LIBZCASH) \
|
$(LIBZCASH) \
|
||||||
$(LIBSNARK) \
|
$(LIBBITCOIN_CRYPTO) \
|
||||||
$(LIBBITCOIN_CRYPTO) \
|
$(LIBZCASH_LIBS)
|
||||||
$(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 #
|
# zcash-tx binary #
|
||||||
komodo_tx_SOURCES = komodo-tx.cpp
|
komodo_tx_SOURCES = komodo-tx.cpp
|
||||||
@@ -531,20 +557,20 @@ komodo_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
|
|||||||
|
|
||||||
# zcash protocol primitives #
|
# zcash protocol primitives #
|
||||||
libzcash_a_SOURCES = \
|
libzcash_a_SOURCES = \
|
||||||
zcash/IncrementalMerkleTree.cpp \
|
zcash/IncrementalMerkleTree.cpp \
|
||||||
zcash/NoteEncryption.cpp \
|
zcash/NoteEncryption.cpp \
|
||||||
zcash/Address.cpp \
|
zcash/Address.cpp \
|
||||||
zcash/JoinSplit.cpp \
|
zcash/JoinSplit.cpp \
|
||||||
zcash/Proof.cpp \
|
zcash/Proof.cpp \
|
||||||
zcash/Note.cpp \
|
zcash/Note.cpp \
|
||||||
zcash/prf.cpp \
|
zcash/prf.cpp \
|
||||||
zcash/util.cpp \
|
zcash/util.cpp \
|
||||||
zcash/circuit/commitment.tcc \
|
zcash/circuit/commitment.tcc \
|
||||||
zcash/circuit/gadget.tcc \
|
zcash/circuit/gadget.tcc \
|
||||||
zcash/circuit/merkle.tcc \
|
zcash/circuit/merkle.tcc \
|
||||||
zcash/circuit/note.tcc \
|
zcash/circuit/note.tcc \
|
||||||
zcash/circuit/prfs.tcc \
|
zcash/circuit/prfs.tcc \
|
||||||
zcash/circuit/utils.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)
|
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
|
utilstrencodings.cpp
|
||||||
|
|
||||||
if GLIBC_BACK_COMPAT
|
if GLIBC_BACK_COMPAT
|
||||||
libzcashconsensus_la_SOURCES += compat/glibc_compat.cpp
|
libzcashconsensus_la_SOURCES += compat/glibc_compat.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libzcashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
|
libzcashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
|
||||||
|
|||||||
@@ -15,87 +15,90 @@ EXTRA_DIST += \
|
|||||||
test/data/tx394b54bb.hex \
|
test/data/tx394b54bb.hex \
|
||||||
test/data/txcreate1.hex \
|
test/data/txcreate1.hex \
|
||||||
test/data/txcreate2.hex \
|
test/data/txcreate2.hex \
|
||||||
test/data/txcreatesign.hex
|
test/data/txcreatesign.hex \
|
||||||
|
test/wallet-utility.py \
|
||||||
|
test/data/wallet.dat
|
||||||
|
|
||||||
JSON_TEST_FILES = \
|
JSON_TEST_FILES = \
|
||||||
test/data/script_valid.json \
|
test/data/script_valid.json \
|
||||||
test/data/base58_keys_valid.json \
|
test/data/base58_keys_valid.json \
|
||||||
test/data/base58_encode_decode.json \
|
test/data/base58_encode_decode.json \
|
||||||
test/data/base58_keys_invalid.json \
|
test/data/base58_keys_invalid.json \
|
||||||
test/data/script_invalid.json \
|
test/data/script_invalid.json \
|
||||||
test/data/tx_invalid.json \
|
test/data/tx_invalid.json \
|
||||||
test/data/tx_valid.json \
|
test/data/tx_valid.json \
|
||||||
test/data/sighash.json \
|
test/data/sighash.json \
|
||||||
test/data/merkle_roots.json \
|
test/data/merkle_roots.json \
|
||||||
test/data/merkle_roots_empty.json \
|
test/data/merkle_roots_empty.json \
|
||||||
test/data/merkle_serialization.json \
|
test/data/merkle_serialization.json \
|
||||||
test/data/merkle_witness_serialization.json \
|
test/data/merkle_witness_serialization.json \
|
||||||
test/data/merkle_path.json \
|
test/data/merkle_path.json \
|
||||||
test/data/merkle_commitments.json \
|
test/data/merkle_commitments.json \
|
||||||
test/data/g1_compressed.json \
|
test/data/g1_compressed.json \
|
||||||
test/data/g2_compressed.json
|
test/data/g2_compressed.json
|
||||||
|
|
||||||
RAW_TEST_FILES = test/data/alertTests.raw
|
RAW_TEST_FILES = test/data/alertTests.raw
|
||||||
|
|
||||||
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
|
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
|
||||||
|
|
||||||
BITCOIN_TESTS =\
|
BITCOIN_TESTS =\
|
||||||
test/arith_uint256_tests.cpp \
|
test/arith_uint256_tests.cpp \
|
||||||
test/bignum.h \
|
test/bignum.h \
|
||||||
test/addrman_tests.cpp \
|
test/addrman_tests.cpp \
|
||||||
test/alert_tests.cpp \
|
test/alert_tests.cpp \
|
||||||
test/allocator_tests.cpp \
|
test/allocator_tests.cpp \
|
||||||
test/base32_tests.cpp \
|
test/base32_tests.cpp \
|
||||||
test/base58_tests.cpp \
|
test/base58_tests.cpp \
|
||||||
test/base64_tests.cpp \
|
test/base64_tests.cpp \
|
||||||
test/bip32_tests.cpp \
|
test/bip32_tests.cpp \
|
||||||
test/bloom_tests.cpp \
|
test/bloom_tests.cpp \
|
||||||
test/checkblock_tests.cpp \
|
test/checkblock_tests.cpp \
|
||||||
test/Checkpoints_tests.cpp \
|
test/Checkpoints_tests.cpp \
|
||||||
test/coins_tests.cpp \
|
test/coins_tests.cpp \
|
||||||
test/compress_tests.cpp \
|
test/compress_tests.cpp \
|
||||||
test/crypto_tests.cpp \
|
test/crypto_tests.cpp \
|
||||||
test/DoS_tests.cpp \
|
test/DoS_tests.cpp \
|
||||||
test/equihash_tests.cpp \
|
test/equihash_tests.cpp \
|
||||||
test/getarg_tests.cpp \
|
test/getarg_tests.cpp \
|
||||||
test/hash_tests.cpp \
|
test/hash_tests.cpp \
|
||||||
test/key_tests.cpp \
|
test/key_tests.cpp \
|
||||||
test/main_tests.cpp \
|
test/main_tests.cpp \
|
||||||
test/mempool_tests.cpp \
|
test/mempool_tests.cpp \
|
||||||
test/miner_tests.cpp \
|
test/miner_tests.cpp \
|
||||||
test/mruset_tests.cpp \
|
test/mruset_tests.cpp \
|
||||||
test/multisig_tests.cpp \
|
test/multisig_tests.cpp \
|
||||||
test/netbase_tests.cpp \
|
test/netbase_tests.cpp \
|
||||||
test/pmt_tests.cpp \
|
test/pmt_tests.cpp \
|
||||||
test/policyestimator_tests.cpp \
|
test/policyestimator_tests.cpp \
|
||||||
test/pow_tests.cpp \
|
test/pow_tests.cpp \
|
||||||
test/raii_event_tests.cpp \
|
test/raii_event_tests.cpp \
|
||||||
test/reverselock_tests.cpp \
|
test/reverselock_tests.cpp \
|
||||||
test/rpc_tests.cpp \
|
test/rpc_tests.cpp \
|
||||||
test/sanity_tests.cpp \
|
test/sanity_tests.cpp \
|
||||||
test/scheduler_tests.cpp \
|
test/scheduler_tests.cpp \
|
||||||
test/script_P2SH_tests.cpp \
|
test/script_P2SH_tests.cpp \
|
||||||
test/script_tests.cpp \
|
test/script_P2PKH_tests.cpp \
|
||||||
test/scriptnum_tests.cpp \
|
test/script_tests.cpp \
|
||||||
test/serialize_tests.cpp \
|
test/scriptnum_tests.cpp \
|
||||||
test/sighash_tests.cpp \
|
test/serialize_tests.cpp \
|
||||||
test/sigopcount_tests.cpp \
|
test/sighash_tests.cpp \
|
||||||
test/skiplist_tests.cpp \
|
test/sigopcount_tests.cpp \
|
||||||
test/test_bitcoin.cpp \
|
test/skiplist_tests.cpp \
|
||||||
test/test_bitcoin.h \
|
test/test_bitcoin.cpp \
|
||||||
test/timedata_tests.cpp \
|
test/test_bitcoin.h \
|
||||||
test/torcontrol_tests.cpp \
|
test/timedata_tests.cpp \
|
||||||
test/transaction_tests.cpp \
|
test/torcontrol_tests.cpp \
|
||||||
test/uint256_tests.cpp \
|
test/transaction_tests.cpp \
|
||||||
test/univalue_tests.cpp \
|
test/uint256_tests.cpp \
|
||||||
test/util_tests.cpp \
|
test/univalue_tests.cpp \
|
||||||
test/sha256compress_tests.cpp
|
test/util_tests.cpp \
|
||||||
|
test/sha256compress_tests.cpp
|
||||||
|
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
BITCOIN_TESTS += \
|
BITCOIN_TESTS += \
|
||||||
test/accounting_tests.cpp \
|
test/accounting_tests.cpp \
|
||||||
wallet/test/wallet_tests.cpp \
|
wallet/test/wallet_tests.cpp \
|
||||||
test/rpc_wallet_tests.cpp
|
test/rpc_wallet_tests.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
|
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
|
||||||
@@ -137,6 +140,10 @@ bitcoin_test_clean : FORCE
|
|||||||
check-local:
|
check-local:
|
||||||
@echo "Running test/bitcoin-util-test.py..."
|
@echo "Running test/bitcoin-util-test.py..."
|
||||||
$(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/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 secp256k1 check
|
||||||
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue 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 NINJA 100000000
|
||||||
komodo_asset OOT 216000000
|
komodo_asset OOT 216000000
|
||||||
komodo_asset BNTN 500000000
|
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=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=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=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
|
#sleep $delay
|
||||||
|
|
||||||
#./komodod -pubkey=$pubkey -ac_name=USD -addnode=78.47.196.146 $1 &
|
#./komodod -pubkey=$pubkey -ac_name=USD -addnode=78.47.196.146 $1 &
|
||||||
|
|||||||
@@ -275,6 +275,23 @@ CTxDestination CBitcoinAddress::Get() const
|
|||||||
return CNoDestination();
|
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
|
bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
|
||||||
{
|
{
|
||||||
if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
|
if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ public:
|
|||||||
|
|
||||||
CTxDestination Get() const;
|
CTxDestination Get() const;
|
||||||
bool GetKeyID(CKeyID &keyID) const;
|
bool GetKeyID(CKeyID &keyID) const;
|
||||||
|
bool GetIndexKey(uint160& hashBytes, int& type) const;
|
||||||
bool IsScript() const;
|
bool IsScript() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -48,10 +48,11 @@ const std::string CLIENT_NAME("MagicBean");
|
|||||||
#include "build.h"
|
#include "build.h"
|
||||||
#endif
|
#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
|
#ifdef GIT_ARCHIVE
|
||||||
#define GIT_COMMIT_ID "$Format:%h$"
|
#define GIT_COMMIT_ID "a86845f3dc"
|
||||||
#define GIT_COMMIT_DATE "$Format:%cD$"
|
#define GIT_COMMIT_DATE "Wed, 21 Feb 2018 16:15:11 +0200"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RENDER_BETA_STRING(num) "-beta" DO_STRINGIZE(num)
|
#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 vote2018; fiat/vote2018 $1 $2 $3 $4
|
||||||
echo ninja; fiat/ninja $1 $2 $3 $4
|
echo ninja; fiat/ninja $1 $2 $3 $4
|
||||||
echo oot; fiat/oot $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)"));
|
strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)"));
|
||||||
#endif
|
#endif
|
||||||
strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0));
|
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 += HelpMessageGroup(_("Connection options:"));
|
||||||
strUsage += HelpMessageOpt("-addnode=<ip>", _("Add a node to connect to and attempt to keep the connection open"));
|
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));
|
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):
|
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
|
||||||
InitBlockIndex();
|
InitBlockIndex();
|
||||||
KOMODO_LOADINGBLOCKS = 0;
|
KOMODO_LOADINGBLOCKS = 0;
|
||||||
fprintf(stderr,"KOMODO_LOADINGBLOCKS finished\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hardcoded $DATADIR/bootstrap.dat
|
// 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
|
// cache size calculations
|
||||||
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
|
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
|
||||||
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
|
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
|
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
|
||||||
int64_t nBlockTreeDBCache = nTotalCache / 8;
|
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;
|
nTotalCache -= nBlockTreeDBCache;
|
||||||
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
|
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
|
||||||
nTotalCache -= nCoinDBCache;
|
nTotalCache -= nCoinDBCache;
|
||||||
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
|
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
|
||||||
LogPrintf("Cache configuration:\n");
|
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 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 chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
|
||||||
LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (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 pcoinscatcher;
|
||||||
delete pblocktree;
|
delete pblocktree;
|
||||||
|
|
||||||
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
|
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex, dbCompression, dbMaxOpenFiles);
|
||||||
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
|
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
|
||||||
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
|
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
|
||||||
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
|
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
|
||||||
@@ -1425,7 +1442,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
KOMODO_LOADINGBLOCKS = 0;
|
KOMODO_LOADINGBLOCKS = 0;
|
||||||
fprintf(stderr,"KOMODO_LOADINGBLOCKS finished\n");
|
|
||||||
// Check for changed -txindex state
|
// Check for changed -txindex state
|
||||||
if (fTxIndex != GetBoolArg("-txindex", true)) {
|
if (fTxIndex != GetBoolArg("-txindex", true)) {
|
||||||
strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
|
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;
|
KOMODO_LOADINGBLOCKS = 0;
|
||||||
fprintf(stderr,"KOMODO_LOADINGBLOCKS finished\n");
|
|
||||||
|
|
||||||
// As LoadBlockIndex can take several minutes, it's possible the user
|
// As LoadBlockIndex can take several minutes, it's possible the user
|
||||||
// requested to kill the GUI during the last operation. If so, exit.
|
// requested to kill the GUI during the last operation. If so, exit.
|
||||||
|
|||||||
@@ -170,13 +170,13 @@ try_again:
|
|||||||
init_string(&s);
|
init_string(&s);
|
||||||
headers = curl_slist_append(0,"Expect:");
|
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_HTTPHEADER, headers);
|
||||||
curl_easy_setopt(curl_handle,CURLOPT_URL, url);
|
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_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_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_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 )
|
if ( strncmp(url,"https",5) == 0 )
|
||||||
{
|
{
|
||||||
curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,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;
|
struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0;
|
||||||
if ( (cHandle= *cHandlep) == NULL )
|
if ( (cHandle= *cHandlep) == NULL )
|
||||||
*cHandlep = cHandle = curl_easy_init();
|
*cHandlep = cHandle = curl_easy_init();
|
||||||
else curl_easy_reset(cHandle);
|
else curl_easy_reset(cHandle);
|
||||||
//#ifdef DEBUG
|
//#ifdef DEBUG
|
||||||
//curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
|
//curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
|
||||||
//#endif
|
//#endif
|
||||||
curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
|
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_SSL_VERIFYPEER,0);
|
||||||
//curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
|
//curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
|
||||||
curl_easy_setopt(cHandle,CURLOPT_URL,url);
|
curl_easy_setopt(cHandle,CURLOPT_URL,url);
|
||||||
curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
|
curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
|
||||||
if ( userpass != 0 && userpass[0] != 0 )
|
if ( userpass != 0 && userpass[0] != 0 )
|
||||||
curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass);
|
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_POST,1);
|
||||||
curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
|
curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
|
||||||
}
|
}
|
||||||
if ( hdr0 != NULL && hdr0[0] != 0 )
|
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;
|
char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
|
||||||
script = _script;
|
script = _script;
|
||||||
/*params[0] = '[';
|
/*params[0] = '[';
|
||||||
params[1] = '"';
|
params[1] = '"';
|
||||||
for (i=0; i<32; i++)
|
for (i=0; i<32; i++)
|
||||||
sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
|
sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
|
||||||
strcat(params,"\", 1]");*/
|
strcat(params,"\", 1]");*/
|
||||||
sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
|
sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
|
||||||
if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 )
|
if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 )
|
||||||
return(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 )
|
if ( ASSETCHAINS_SYMBOL[0] != 0 )
|
||||||
{
|
{
|
||||||
jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,KMD_PORT);
|
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 jsonstr = _dex_getrawtransaction();
|
||||||
else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok
|
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 komodo_getblockhash(int32_t height)
|
||||||
{
|
{
|
||||||
uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32];
|
uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32];
|
||||||
memset(&hash,0,sizeof(hash));
|
memset(&hash,0,sizeof(hash));
|
||||||
sprintf(params,"[%d]",height);
|
sprintf(params,"[%d]",height);
|
||||||
if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_PORT)) != 0 )
|
if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_PORT)) != 0 )
|
||||||
{
|
{
|
||||||
if ( (result= cJSON_Parse(jsonstr)) != 0 )
|
if ( (result= cJSON_Parse(jsonstr)) != 0 )
|
||||||
{
|
{
|
||||||
if ( (hexstr= jstr(result,(char *)"result")) != 0 )
|
if ( (hexstr= jstr(result,(char *)"result")) != 0 )
|
||||||
{
|
{
|
||||||
if ( is_hexstr(hexstr,0) == 64 )
|
if ( is_hexstr(hexstr,0) == 64 )
|
||||||
{
|
{
|
||||||
decode_hex(revbuf,32,hexstr);
|
decode_hex(revbuf,32,hexstr);
|
||||||
for (i=0; i<32; i++)
|
for (i=0; i<32; i++)
|
||||||
((uint8_t *)&hash)[i] = revbuf[31-i];
|
((uint8_t *)&hash)[i] = revbuf[31-i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_json(result);
|
free_json(result);
|
||||||
}
|
}
|
||||||
printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
|
printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
|
||||||
free(jsonstr);
|
free(jsonstr);
|
||||||
}
|
}
|
||||||
return(hash);
|
return(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 _komodo_getblockhash(int32_t height);*/
|
uint256 _komodo_getblockhash(int32_t height);*/
|
||||||
|
|
||||||
uint64_t komodo_seed(int32_t height)
|
uint64_t komodo_seed(int32_t height)
|
||||||
{
|
{
|
||||||
uint64_t seed = 0;
|
uint64_t seed = 0;
|
||||||
/*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
|
/*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
|
||||||
{
|
{
|
||||||
uint256 hash,zero; CBlockIndex *pindex;
|
uint256 hash,zero; CBlockIndex *pindex;
|
||||||
memset(&hash,0,sizeof(hash));
|
memset(&hash,0,sizeof(hash));
|
||||||
memset(&zero,0,sizeof(zero));
|
memset(&zero,0,sizeof(zero));
|
||||||
if ( height > 10 )
|
if ( height > 10 )
|
||||||
height -= 10;
|
height -= 10;
|
||||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||||
hash = _komodo_getblockhash(height);
|
hash = _komodo_getblockhash(height);
|
||||||
if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
|
if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
|
||||||
hash = komodo_getblockhash(height);
|
hash = komodo_getblockhash(height);
|
||||||
int32_t i;
|
int32_t i;
|
||||||
for (i=0; i<32; i++)
|
for (i=0; i<32; i++)
|
||||||
printf("%02x",((uint8_t *)&hash)[i]);
|
printf("%02x",((uint8_t *)&hash)[i]);
|
||||||
printf(" seed.%d\n",height);
|
printf(" seed.%d\n",height);
|
||||||
seed = arith_uint256(hash.GetHex()).GetLow64();
|
seed = arith_uint256(hash.GetHex()).GetLow64();
|
||||||
}
|
}
|
||||||
else*/
|
else*/
|
||||||
{
|
{
|
||||||
seed = (height << 13) ^ (height << 2);
|
seed = (height << 13) ^ (height << 2);
|
||||||
seed <<= 21;
|
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 komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // deprecate
|
||||||
{
|
{
|
||||||
/*int32_t i,n=0;
|
/*int32_t i,n=0;
|
||||||
for (i=0; i<width; i++,n++)
|
for (i=0; i<width; i++,n++)
|
||||||
{
|
{
|
||||||
if ( height-i <= 0 )
|
if ( height-i <= 0 )
|
||||||
break;
|
break;
|
||||||
minerids[i] = komodo_minerid(height - i,0);
|
minerids[i] = komodo_minerid(height - i,0);
|
||||||
}
|
}
|
||||||
return(n);*/
|
return(n);*/
|
||||||
fprintf(stderr,"komodo_minerids is deprecated\n");
|
fprintf(stderr,"komodo_minerids is deprecated\n");
|
||||||
return(-1);
|
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 ( mids[i] == notaryid )
|
||||||
{
|
{
|
||||||
if ( height > 700000 )
|
//for (j=0; j<66; j++)
|
||||||
{
|
// fprintf(stderr,"%d ",mids[j]);
|
||||||
for (j=0; j<66; j++)
|
//fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
|
||||||
fprintf(stderr,"%d ",mids[j]);
|
|
||||||
fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
|
|
||||||
}
|
|
||||||
if ( height > 792000 )
|
if ( height > 792000 )
|
||||||
return(-1);
|
return(-1);
|
||||||
else break;
|
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));
|
komodo_eventadd(sp,height,symbol,KOMODO_EVENT_PRICEFEED,(uint8_t *)&F,(int32_t)(sizeof(F.num) + sizeof(*F.prices) * num));
|
||||||
if ( sp != 0 )
|
if ( sp != 0 )
|
||||||
komodo_pvals(height,prices,num);
|
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)
|
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)
|
/*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;
|
uint8_t opret[512]; uint16_t opretlen;
|
||||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_DEPOSIT,kmdtxid,komodoshis,kmdvout,opret,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)
|
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;
|
uint8_t opret[512]; uint16_t opretlen;
|
||||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_ISSUED,fiattxid,fiatoshis,fiatvout,opret,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)
|
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;
|
uint8_t opret[512]; uint16_t opretlen;
|
||||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_WITHDRAW,fiattxid,fiatoshis,fiatvout,opret,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)
|
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;
|
uint8_t opret[512]; uint16_t opretlen;
|
||||||
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_REDEEMED,kmdtxid,komodoshis,kmdvout,opret,opretlen);
|
komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_REDEEMED,kmdtxid,komodoshis,kmdvout,opret,opretlen);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
// process events
|
// process events
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -436,6 +436,7 @@ int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,in
|
|||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *notarized_desttxidp)
|
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;
|
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");
|
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;
|
leveldb::Options options;
|
||||||
options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
|
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.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
|
||||||
options.filter_policy = leveldb::NewBloomFilterPolicy(10);
|
options.filter_policy = leveldb::NewBloomFilterPolicy(10);
|
||||||
options.compression = leveldb::kNoCompression;
|
options.compression = compression ? leveldb::kSnappyCompression : leveldb::kNoCompression;
|
||||||
options.max_open_files = 64;
|
options.max_open_files = maxOpenFiles;
|
||||||
if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
|
if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
|
||||||
// LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
|
// LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
|
||||||
// on corruption in later versions.
|
// on corruption in later versions.
|
||||||
@@ -43,14 +43,14 @@ static leveldb::Options GetOptions(size_t nCacheSize)
|
|||||||
return options;
|
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;
|
penv = NULL;
|
||||||
readoptions.verify_checksums = true;
|
readoptions.verify_checksums = true;
|
||||||
iteroptions.verify_checksums = true;
|
iteroptions.verify_checksums = true;
|
||||||
iteroptions.fill_cache = false;
|
iteroptions.fill_cache = false;
|
||||||
syncoptions.sync = true;
|
syncoptions.sync = true;
|
||||||
options = GetOptions(nCacheSize);
|
options = GetOptions(nCacheSize, compression, maxOpenFiles);
|
||||||
options.create_if_missing = true;
|
options.create_if_missing = true;
|
||||||
if (fMemory) {
|
if (fMemory) {
|
||||||
penv = leveldb::NewMemEnv(leveldb::Env::Default());
|
penv = leveldb::NewMemEnv(leveldb::Env::Default());
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ private:
|
|||||||
leveldb::DB* pdb;
|
leveldb::DB* pdb;
|
||||||
|
|
||||||
public:
|
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();
|
~CLevelDBWrapper();
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
|
|||||||
306
src/main.cpp
306
src/main.cpp
@@ -68,6 +68,9 @@ bool fExperimentalMode = false;
|
|||||||
bool fImporting = false;
|
bool fImporting = false;
|
||||||
bool fReindex = false;
|
bool fReindex = false;
|
||||||
bool fTxIndex = false;
|
bool fTxIndex = false;
|
||||||
|
bool fAddressIndex = false;
|
||||||
|
bool fTimestampIndex = false;
|
||||||
|
bool fSpentIndex = false;
|
||||||
bool fHavePruned = false;
|
bool fHavePruned = false;
|
||||||
bool fPruneMode = false;
|
bool fPruneMode = false;
|
||||||
bool fIsBareMultisigStd = true;
|
bool fIsBareMultisigStd = true;
|
||||||
@@ -1484,6 +1487,16 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||||||
if ( komodo_is_notarytx(tx) == 0 )
|
if ( komodo_is_notarytx(tx) == 0 )
|
||||||
KOMODO_ON_DEMAND++;
|
KOMODO_ON_DEMAND++;
|
||||||
pool.addUnchecked(hash, entry, !IsInitialBlockDownload());
|
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);
|
SyncWithWallets(tx, NULL);
|
||||||
@@ -1491,6 +1504,55 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||||||
return true;
|
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 */
|
/** 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)
|
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
|
||||||
{
|
{
|
||||||
@@ -2187,7 +2249,6 @@ namespace {
|
|||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify checksum
|
// Verify checksum
|
||||||
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
|
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
|
||||||
hasher << hashBlock;
|
hasher << hashBlock;
|
||||||
@@ -2269,11 +2330,44 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||||||
|
|
||||||
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
|
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
|
||||||
return error("DisconnectBlock(): block and undo data inconsistent");
|
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
|
// undo transactions in reverse order
|
||||||
for (int i = block.vtx.size() - 1; i >= 0; i--) {
|
for (int i = block.vtx.size() - 1; i >= 0; i--) {
|
||||||
const CTransaction &tx = block.vtx[i];
|
const CTransaction &tx = block.vtx[i];
|
||||||
uint256 hash = tx.GetHash();
|
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
|
// Check that all outputs are available and match the outputs in the block itself
|
||||||
// exactly.
|
// exactly.
|
||||||
@@ -2311,6 +2405,39 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||||||
const CTxInUndo &undo = txundo.vprevout[j];
|
const CTxInUndo &undo = txundo.vprevout[j];
|
||||||
if (!ApplyTxInUndo(undo, view, out))
|
if (!ApplyTxInUndo(undo, view, out))
|
||||||
fClean = false;
|
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;
|
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;
|
return fClean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2429,7 +2564,7 @@ static int64_t nTimeIndex = 0;
|
|||||||
static int64_t nTimeCallbacks = 0;
|
static int64_t nTimeCallbacks = 0;
|
||||||
static int64_t nTimeTotal = 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();
|
const CChainParams& chainparams = Params();
|
||||||
|
|
||||||
@@ -2447,7 +2582,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||||||
auto disabledVerifier = libzcash::ProofVerifier::Disabled();
|
auto disabledVerifier = libzcash::ProofVerifier::Disabled();
|
||||||
|
|
||||||
// Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in
|
// 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;
|
return false;
|
||||||
|
|
||||||
// verify that the view's current state corresponds to the previous block
|
// 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;
|
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
|
||||||
vPos.reserve(block.vtx.size());
|
vPos.reserve(block.vtx.size());
|
||||||
blockundo.vtxundo.reserve(block.vtx.size() - 1);
|
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
|
// Construct the incremental merkle tree at the current
|
||||||
// block position,
|
// block position,
|
||||||
auto old_tree_root = view.GetBestAnchor();
|
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++)
|
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||||
{
|
{
|
||||||
const CTransaction &tx = block.vtx[i];
|
const CTransaction &tx = block.vtx[i];
|
||||||
|
const uint256 txhash = tx.GetHash();
|
||||||
nInputs += tx.vin.size();
|
nInputs += tx.vin.size();
|
||||||
nSigOps += GetLegacySigOpCount(tx);
|
nSigOps += GetLegacySigOpCount(tx);
|
||||||
if (nSigOps > MAX_BLOCK_SIGOPS)
|
if (nSigOps > MAX_BLOCK_SIGOPS)
|
||||||
@@ -2540,7 +2678,42 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||||||
if (!view.HaveJoinSplitRequirements(tx))
|
if (!view.HaveJoinSplitRequirements(tx))
|
||||||
return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"),
|
return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"),
|
||||||
REJECT_INVALID, "bad-txns-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;
|
// Add in sigops done by pay-to-script-hash inputs;
|
||||||
// this is to prevent a "rogue miner" from creating
|
// this is to prevent a "rogue miner" from creating
|
||||||
// an incredibly-expensive-to-validate block.
|
// an incredibly-expensive-to-validate block.
|
||||||
@@ -2562,6 +2735,36 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||||||
return false;
|
return false;
|
||||||
control.Add(vChecks);
|
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 )
|
//if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||||
// komodo_earned_interest(pindex->nHeight,sum);
|
// komodo_earned_interest(pindex->nHeight,sum);
|
||||||
CTxUndo undoDummy;
|
CTxUndo undoDummy;
|
||||||
@@ -2654,6 +2857,40 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||||||
if (fTxIndex)
|
if (fTxIndex)
|
||||||
if (!pblocktree->WriteTxIndex(vPos))
|
if (!pblocktree->WriteTxIndex(vPos))
|
||||||
return AbortNode(state, "Failed to write transaction index");
|
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
|
// add this block to the view's block chain
|
||||||
view.SetBestBlock(pindex->GetBlockHash());
|
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);
|
LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
|
||||||
{
|
{
|
||||||
CCoinsViewCache view(pcoinsTip);
|
CCoinsViewCache view(pcoinsTip);
|
||||||
bool rv = ConnectBlock(*pblock, state, pindexNew, view);
|
bool rv = ConnectBlock(*pblock, state, pindexNew, view, false, true);
|
||||||
GetMainSignals().BlockChecked(*pblock, state);
|
GetMainSignals().BlockChecked(*pblock, state);
|
||||||
if (!rv) {
|
if (!rv) {
|
||||||
if (state.IsInvalid())
|
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);
|
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;
|
/*KOMODO_REWIND = tipindex->nHeight - 11;
|
||||||
rewindtarget = tipindex->nHeight - 11;
|
rewindtarget = tipindex->nHeight - 11;
|
||||||
fprintf(stderr,"rewindtarget <- %d\n",rewindtarget);
|
fprintf(stderr,"rewindtarget <- %d\n",rewindtarget);
|
||||||
oneshot = 1;
|
oneshot = 1;
|
||||||
while ( rewindtarget > 0 && (tipindex= chainActive.Tip()) != 0 && tipindex->nHeight > rewindtarget )
|
while ( rewindtarget > 0 && (tipindex= chainActive.Tip()) != 0 && tipindex->nHeight > rewindtarget )
|
||||||
{
|
{
|
||||||
fprintf(stderr,"%d ",(int32_t)tipindex->nHeight);
|
fprintf(stderr,"%d ",(int32_t)tipindex->nHeight);
|
||||||
InvalidateBlock(state,tipindex);
|
InvalidateBlock(state,tipindex);
|
||||||
if ( !DisconnectTip(state) )
|
if ( !DisconnectTip(state) )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tipindex = chainActive.Tip();
|
tipindex = chainActive.Tip();
|
||||||
fprintf(stderr,"rewind done to %d\n",tipindex!=0?tipindex->nHeight:-1);*/
|
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
|
// Check that the header is valid (particularly PoW). This is mostly
|
||||||
// redundant with the call in AcceptBlockHeader.
|
// redundant with the call in AcceptBlockHeader.
|
||||||
if (!CheckBlockHeader(height,pindex,block,state,fCheckPOW))
|
if (!CheckBlockHeader(height,pindex,block,state,fCheckPOW))
|
||||||
|
{
|
||||||
|
fprintf(stderr,"checkblockheader error PoW.%d\n",fCheckPOW);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if ( fCheckPOW && !CheckEquihashSolution(&block, Params()) )
|
if ( fCheckPOW && !CheckEquihashSolution(&block, Params()) )
|
||||||
return state.DoS(100, error("CheckBlock(): Equihash solution invalid"),REJECT_INVALID, "invalid-solution");
|
return state.DoS(100, error("CheckBlock(): Equihash solution invalid"),REJECT_INVALID, "invalid-solution");
|
||||||
komodo_block2pubkey33(pubkey33,(CBlock *)&block);
|
komodo_block2pubkey33(pubkey33,(CBlock *)&block);
|
||||||
if ( fCheckPOW && !CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus()) )
|
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");
|
return state.DoS(1, error("CheckBlock(): proof of work failed"),REJECT_INVALID, "high-hash");
|
||||||
}
|
|
||||||
// Check the merkle root.
|
// Check the merkle root.
|
||||||
if (fCheckMerkleRoot) {
|
if (fCheckMerkleRoot) {
|
||||||
bool mutated;
|
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 )
|
//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;
|
static uint32_t counter;
|
||||||
if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
//if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
||||||
fprintf(stderr,"check deposit rejection\n");
|
fprintf(stderr,"check deposit rejection\n");
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
@@ -3969,7 +4206,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
|
|||||||
}
|
}
|
||||||
if (!CheckBlock(indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot))
|
if (!CheckBlock(indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot))
|
||||||
{
|
{
|
||||||
//fprintf(stderr,"TestBlockValidity failure B\n");
|
fprintf(stderr,"TestBlockValidity failure B\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ContextualCheckBlock(block, state, pindexPrev))
|
if (!ContextualCheckBlock(block, state, pindexPrev))
|
||||||
@@ -3977,7 +4214,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
|
|||||||
fprintf(stderr,"TestBlockValidity failure C\n");
|
fprintf(stderr,"TestBlockValidity failure C\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ConnectBlock(block, state, &indexDummy, viewNew, true))
|
if (!ConnectBlock(block, state, &indexDummy, viewNew, true,fCheckPOW))
|
||||||
{
|
{
|
||||||
//fprintf(stderr,"TestBlockValidity failure D\n");
|
//fprintf(stderr,"TestBlockValidity failure D\n");
|
||||||
return false;
|
return false;
|
||||||
@@ -4299,6 +4536,17 @@ bool static LoadBlockIndexDB()
|
|||||||
// Check whether we have a transaction index
|
// Check whether we have a transaction index
|
||||||
pblocktree->ReadFlag("txindex", fTxIndex);
|
pblocktree->ReadFlag("txindex", fTxIndex);
|
||||||
LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled");
|
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
|
// Fill in-memory data
|
||||||
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
|
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
|
||||||
@@ -4415,7 +4663,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
|
|||||||
CBlock block;
|
CBlock block;
|
||||||
if (!ReadBlockFromDisk(block, pindex))
|
if (!ReadBlockFromDisk(block, pindex))
|
||||||
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
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());
|
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
|
// Use the provided setting for -txindex in the new database
|
||||||
fTxIndex = GetBoolArg("-txindex", true);
|
fTxIndex = GetBoolArg("-txindex", true);
|
||||||
pblocktree->WriteFlag("txindex", fTxIndex);
|
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");
|
LogPrintf("Initializing databases...\n");
|
||||||
|
|
||||||
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
|
// 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/script.h"
|
||||||
#include "script/serverchecker.h"
|
#include "script/serverchecker.h"
|
||||||
#include "script/standard.h"
|
#include "script/standard.h"
|
||||||
|
#include "spentindex.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "tinyformat.h"
|
#include "tinyformat.h"
|
||||||
#include "txmempool.h"
|
#include "txmempool.h"
|
||||||
@@ -101,6 +102,12 @@ static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
|
|||||||
/** Maximum length of reject messages. */
|
/** Maximum length of reject messages. */
|
||||||
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
|
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
|
// Sanity check the magic numbers when we change them
|
||||||
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE);
|
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE);
|
||||||
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_PRIORITY_SIZE <= DEFAULT_BLOCK_MAX_SIZE);
|
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_PRIORITY_SIZE <= DEFAULT_BLOCK_MAX_SIZE);
|
||||||
@@ -268,6 +275,338 @@ struct CNodeStateStats {
|
|||||||
std::vector<int> vHeightInFlight;
|
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
|
struct CDiskTxPos : public CDiskBlockPos
|
||||||
{
|
{
|
||||||
unsigned int nTxOffset; // after header
|
unsigned int nTxOffset; // after header
|
||||||
@@ -431,6 +770,13 @@ public:
|
|||||||
ScriptError GetScriptError() const { return error; }
|
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 */
|
/** Functions for disk access for blocks */
|
||||||
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
|
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);
|
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 */
|
/** 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 */
|
/** Context-independent validity checks */
|
||||||
bool CheckBlockHeader(int32_t height,CBlockIndex *pindex,const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
|
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;
|
nLastBlockTx = nBlockTx;
|
||||||
nLastBlockSize = nBlockSize;
|
nLastBlockSize = nBlockSize;
|
||||||
blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
||||||
pblock->nTime = blocktime + 1;
|
//pblock->nTime = blocktime + 1;
|
||||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||||
//LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits);
|
//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 )
|
if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 )
|
||||||
@@ -479,8 +479,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
|||||||
// Fill in header
|
// Fill in header
|
||||||
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
|
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
|
||||||
pblock->hashReserved = uint256();
|
pblock->hashReserved = uint256();
|
||||||
//UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
|
if ( ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED == 0 || NOTARY_PUBKEY33[0] == 0 )
|
||||||
//pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
{
|
||||||
|
UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
|
||||||
|
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||||
|
}
|
||||||
pblock->nSolution.clear();
|
pblock->nSolution.clear();
|
||||||
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
|
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
|
||||||
|
|
||||||
@@ -488,8 +491,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
|||||||
if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false))
|
if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false))
|
||||||
{
|
{
|
||||||
static uint32_t counter;
|
static uint32_t counter;
|
||||||
if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
//if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
||||||
fprintf(stderr,"warning: testblockvalidity failed\n");
|
fprintf(stderr,"warning: miner testblockvalidity failed\n");
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in
|
|||||||
{
|
{
|
||||||
if ( KOMODO_LOADINGBLOCKS != 0 )
|
if ( KOMODO_LOADINGBLOCKS != 0 )
|
||||||
return true;
|
return true;
|
||||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
/* if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||||
{
|
{
|
||||||
if ( 1 && height > 792000 )
|
if ( 1 && height > 792000 )
|
||||||
{
|
{
|
||||||
@@ -211,7 +211,9 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in
|
|||||||
}
|
}
|
||||||
if ( height > 792000 )
|
if ( height > 792000 )
|
||||||
return false;
|
return false;
|
||||||
} else return false;
|
} else return false;*/
|
||||||
|
if ( ASSETCHAINS_SYMBOL[0] != 0 || height > 792000 )
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "chain.h"
|
#include "chain.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "checkpoints.h"
|
#include "checkpoints.h"
|
||||||
|
#include "base58.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "cc/betprotocol.h"
|
#include "cc/betprotocol.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
@@ -14,6 +15,10 @@
|
|||||||
#include "rpcserver.h"
|
#include "rpcserver.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "script/script.h"
|
||||||
|
#include "script/script_error.h"
|
||||||
|
#include "script/sign.h"
|
||||||
|
#include "script/standard.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@@ -124,6 +129,112 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
|
|||||||
return result;
|
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 blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
|
||||||
{
|
{
|
||||||
UniValue result(UniValue::VOBJ);
|
UniValue result(UniValue::VOBJ);
|
||||||
@@ -310,6 +421,102 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
|
|||||||
return mempoolToJSON(fVerbose);
|
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)
|
UniValue getblockhash(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (fHelp || params.size() != 1)
|
if (fHelp || params.size() != 1)
|
||||||
|
|||||||
@@ -96,6 +96,15 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "prioritisetransaction", 2 },
|
{ "prioritisetransaction", 2 },
|
||||||
{ "setban", 2 },
|
{ "setban", 2 },
|
||||||
{ "setban", 3 },
|
{ "setban", 3 },
|
||||||
|
{ "getblockhashes", 0 },
|
||||||
|
{ "getblockhashes", 1 },
|
||||||
|
{ "getblockhashes", 2 },
|
||||||
|
{ "getspentinfo", 0},
|
||||||
|
{ "getaddresstxids", 0},
|
||||||
|
{ "getaddressbalance", 0},
|
||||||
|
{ "getaddressdeltas", 0},
|
||||||
|
{ "getaddressutxos", 0},
|
||||||
|
{ "getaddressmempool", 0},
|
||||||
{ "zcrawjoinsplit", 1 },
|
{ "zcrawjoinsplit", 1 },
|
||||||
{ "zcrawjoinsplit", 2 },
|
{ "zcrawjoinsplit", 2 },
|
||||||
{ "zcrawjoinsplit", 3 },
|
{ "zcrawjoinsplit", 3 },
|
||||||
|
|||||||
528
src/rpcmisc.cpp
528
src/rpcmisc.cpp
@@ -11,6 +11,7 @@
|
|||||||
#include "netbase.h"
|
#include "netbase.h"
|
||||||
#include "rpcserver.h"
|
#include "rpcserver.h"
|
||||||
#include "timedata.h"
|
#include "timedata.h"
|
||||||
|
#include "txmempool.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
#include "wallet/wallet.h"
|
#include "wallet/wallet.h"
|
||||||
@@ -557,3 +558,530 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
return NullUniValue;
|
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);
|
UniValue joinsplit(UniValue::VOBJ);
|
||||||
|
|
||||||
joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old)));
|
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_new", ValueFromAmount(jsdescription.vpub_new)));
|
||||||
|
joinsplit.push_back(Pair("vpub_newZat", jsdescription.vpub_new));
|
||||||
|
|
||||||
joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex()));
|
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);
|
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("overwintered", tx.fOverwintered));
|
||||||
entry.push_back(Pair("version", tx.nVersion));
|
entry.push_back(Pair("version", tx.nVersion));
|
||||||
if (tx.fOverwintered) {
|
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("asm", txin.scriptSig.ToString()));
|
||||||
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
||||||
in.push_back(Pair("scriptSig", o));
|
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));
|
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
|
||||||
vin.push_back(in);
|
vin.push_back(in);
|
||||||
@@ -162,6 +178,16 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
|||||||
UniValue o(UniValue::VOBJ);
|
UniValue o(UniValue::VOBJ);
|
||||||
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
|
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
|
||||||
out.push_back(Pair("scriptPubKey", o));
|
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);
|
vout.push_back(out);
|
||||||
}
|
}
|
||||||
entry.push_back(Pair("vout", vout));
|
entry.push_back(Pair("vout", vout));
|
||||||
@@ -169,18 +195,76 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
|||||||
UniValue vjoinsplit = TxJoinSplitToJSON(tx);
|
UniValue vjoinsplit = TxJoinSplitToJSON(tx);
|
||||||
entry.push_back(Pair("vjoinsplit", vjoinsplit));
|
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()) {
|
if (!hashBlock.IsNull()) {
|
||||||
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
|
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
|
||||||
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
|
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
|
||||||
if (mi != mapBlockIndex.end() && (*mi).second) {
|
if (mi != mapBlockIndex.end() && (*mi).second) {
|
||||||
CBlockIndex* pindex = (*mi).second;
|
CBlockIndex* pindex = (*mi).second;
|
||||||
if (chainActive.Contains(pindex)) {
|
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("confirmations", 1 + chainActive.Height() - pindex->nHeight));
|
||||||
entry.push_back(Pair("time", pindex->GetBlockTime()));
|
entry.push_back(Pair("time", pindex->GetBlockTime()));
|
||||||
entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
|
entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
|
||||||
}
|
} else {
|
||||||
else
|
entry.push_back(Pair("height", -1));
|
||||||
entry.push_back(Pair("confirmations", 0));
|
entry.push_back(Pair("confirmations", 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,7 +363,6 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
|
|||||||
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
|
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
|
||||||
);
|
);
|
||||||
|
|
||||||
LOCK(cs_main);
|
|
||||||
|
|
||||||
uint256 hash = ParseHashV(params[0], "parameter 1");
|
uint256 hash = ParseHashV(params[0], "parameter 1");
|
||||||
|
|
||||||
@@ -289,8 +372,29 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
CTransaction tx;
|
CTransaction tx;
|
||||||
uint256 hashBlock;
|
uint256 hashBlock;
|
||||||
if (!GetTransaction(hash, tx, hashBlock, true))
|
int nHeight = 0;
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
|
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);
|
string strHex = EncodeHexTx(tx);
|
||||||
|
|
||||||
@@ -299,7 +403,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
UniValue result(UniValue::VOBJ);
|
UniValue result(UniValue::VOBJ);
|
||||||
result.push_back(Pair("hex", strHex));
|
result.push_back(Pair("hex", strHex));
|
||||||
TxToJSON(tx, hashBlock, result);
|
TxToJSONExpanded(tx, hashBlock, result, nHeight, nConfirmations, nBlockTime);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -281,6 +281,8 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "blockchain", "getbestblockhash", &getbestblockhash, true },
|
{ "blockchain", "getbestblockhash", &getbestblockhash, true },
|
||||||
{ "blockchain", "getblockcount", &getblockcount, true },
|
{ "blockchain", "getblockcount", &getblockcount, true },
|
||||||
{ "blockchain", "getblock", &getblock, true },
|
{ "blockchain", "getblock", &getblock, true },
|
||||||
|
{ "blockchain", "getblockdeltas", &getblockdeltas, false },
|
||||||
|
{ "blockchain", "getblockhashes", &getblockhashes, true },
|
||||||
{ "blockchain", "getblockhash", &getblockhash, true },
|
{ "blockchain", "getblockhash", &getblockhash, true },
|
||||||
{ "blockchain", "getblockheader", &getblockheader, true },
|
{ "blockchain", "getblockheader", &getblockheader, true },
|
||||||
{ "blockchain", "getchaintips", &getchaintips, true },
|
{ "blockchain", "getchaintips", &getchaintips, true },
|
||||||
@@ -292,6 +294,7 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "blockchain", "verifytxoutproof", &verifytxoutproof, true },
|
{ "blockchain", "verifytxoutproof", &verifytxoutproof, true },
|
||||||
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
|
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
|
||||||
{ "blockchain", "verifychain", &verifychain, true },
|
{ "blockchain", "verifychain", &verifychain, true },
|
||||||
|
{ "blockchain", "getspentinfo", &getspentinfo, false },
|
||||||
{ "blockchain", "paxprice", &paxprice, true },
|
{ "blockchain", "paxprice", &paxprice, true },
|
||||||
{ "blockchain", "paxpending", &paxpending, true },
|
{ "blockchain", "paxpending", &paxpending, true },
|
||||||
{ "blockchain", "paxprices", &paxprices, true },
|
{ "blockchain", "paxprices", &paxprices, true },
|
||||||
@@ -332,6 +335,13 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
|
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
|
||||||
#endif
|
#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 */
|
/* Utility functions */
|
||||||
{ "util", "createmultisig", &createmultisig, true },
|
{ "util", "createmultisig", &createmultisig, true },
|
||||||
{ "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */
|
{ "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 void EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp
|
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 getpeerinfo(const UniValue& params, bool fHelp);
|
||||||
extern UniValue ping(const UniValue& params, bool fHelp);
|
extern UniValue ping(const UniValue& params, bool fHelp);
|
||||||
extern UniValue addnode(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 settxfee(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
|
extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getrawmempool(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 getblockhash(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getblockheader(const UniValue& params, bool fHelp);
|
extern UniValue getblockheader(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getblock(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 getchaintips(const UniValue& params, bool fHelp);
|
||||||
extern UniValue invalidateblock(const UniValue& params, bool fHelp);
|
extern UniValue invalidateblock(const UniValue& params, bool fHelp);
|
||||||
extern UniValue reconsiderblock(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);
|
extern UniValue getblocksubsidy(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
|||||||
@@ -216,6 +216,17 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
|
|||||||
return subscript.GetSigOpCount(true);
|
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
|
bool CScript::IsPayToScriptHash() const
|
||||||
{
|
{
|
||||||
// Extra-fast test for pay-to-script-hash CScripts:
|
// Extra-fast test for pay-to-script-hash CScripts:
|
||||||
|
|||||||
@@ -566,6 +566,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
unsigned int GetSigOpCount(const CScript& scriptSig) const;
|
unsigned int GetSigOpCount(const CScript& scriptSig) const;
|
||||||
|
|
||||||
|
bool IsPayToPublicKeyHash() const;
|
||||||
|
|
||||||
bool IsPayToScriptHash() const;
|
bool IsPayToScriptHash() const;
|
||||||
bool IsPayToCryptoCondition() const;
|
bool IsPayToCryptoCondition() const;
|
||||||
bool MayAcceptCryptoCondition() const;
|
bool MayAcceptCryptoCondition() const;
|
||||||
|
|||||||
@@ -95,6 +95,11 @@ template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
|
|||||||
obj = htole32(obj);
|
obj = htole32(obj);
|
||||||
s.write((char*)&obj, 4);
|
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)
|
template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj)
|
||||||
{
|
{
|
||||||
obj = htole64(obj);
|
obj = htole64(obj);
|
||||||
@@ -118,6 +123,12 @@ template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
|
|||||||
s.read((char*)&obj, 4);
|
s.read((char*)&obj, 4);
|
||||||
return le32toh(obj);
|
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)
|
template<typename Stream> inline uint64_t ser_readdata64(Stream &s)
|
||||||
{
|
{
|
||||||
uint64_t obj;
|
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 "key.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
#include "chainparamsbase.h"
|
||||||
#include "txdb.h"
|
#include "txdb.h"
|
||||||
#include "txmempool.h"
|
#include "txmempool.h"
|
||||||
#include "ui_interface.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_COINS = 'c';
|
||||||
static const char DB_BLOCK_FILES = 'f';
|
static const char DB_BLOCK_FILES = 'f';
|
||||||
static const char DB_TXINDEX = 't';
|
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_BLOCK_INDEX = 'b';
|
||||||
|
|
||||||
static const char DB_BEST_BLOCK = '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(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);
|
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) {
|
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
|
||||||
@@ -260,6 +265,197 @@ bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos>
|
|||||||
return WriteBatch(batch);
|
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) {
|
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
|
||||||
return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
|
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);
|
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()
|
bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||||
{
|
{
|
||||||
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
||||||
|
|||||||
28
src/txdb.h
28
src/txdb.h
@@ -17,6 +17,17 @@
|
|||||||
class CBlockFileInfo;
|
class CBlockFileInfo;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
struct CDiskTxPos;
|
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;
|
class uint256;
|
||||||
|
|
||||||
//! -dbcache default (MiB)
|
//! -dbcache default (MiB)
|
||||||
@@ -53,7 +64,7 @@ public:
|
|||||||
class CBlockTreeDB : public CLevelDBWrapper
|
class CBlockTreeDB : public CLevelDBWrapper
|
||||||
{
|
{
|
||||||
public:
|
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:
|
private:
|
||||||
CBlockTreeDB(const CBlockTreeDB&);
|
CBlockTreeDB(const CBlockTreeDB&);
|
||||||
void operator=(const CBlockTreeDB&);
|
void operator=(const CBlockTreeDB&);
|
||||||
@@ -65,9 +76,24 @@ public:
|
|||||||
bool ReadReindexing(bool &fReindex);
|
bool ReadReindexing(bool &fReindex);
|
||||||
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
|
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
|
||||||
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
|
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 WriteFlag(const std::string &name, bool fValue);
|
||||||
bool ReadFlag(const std::string &name, bool &fValue);
|
bool ReadFlag(const std::string &name, bool &fValue);
|
||||||
bool LoadBlockIndexGuts();
|
bool LoadBlockIndexGuts();
|
||||||
|
bool blockOnchainActive(const uint256 &hash);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_TXDB_H
|
#endif // BITCOIN_TXDB_H
|
||||||
|
|||||||
@@ -119,6 +119,144 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
|||||||
return true;
|
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)
|
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);
|
mapTx.erase(hash);
|
||||||
nTransactionsUpdated++;
|
nTransactionsUpdated++;
|
||||||
minerPolicyEstimator->removeTx(hash);
|
minerPolicyEstimator->removeTx(hash);
|
||||||
|
removeAddressIndex(hash);
|
||||||
|
removeSpentIndex(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
#include "addressindex.h"
|
||||||
|
#include "spentindex.h"
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
#include "coins.h"
|
#include "coins.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
@@ -147,6 +149,21 @@ public:
|
|||||||
|
|
||||||
mutable CCriticalSection cs;
|
mutable CCriticalSection cs;
|
||||||
indexed_transaction_set mapTx;
|
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<COutPoint, CInPoint> mapNextTx;
|
||||||
std::map<uint256, const CTransaction*> mapNullifiers;
|
std::map<uint256, const CTransaction*> mapNullifiers;
|
||||||
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
|
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
|
||||||
@@ -164,6 +181,14 @@ public:
|
|||||||
void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967296.0; }
|
void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967296.0; }
|
||||||
|
|
||||||
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true);
|
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 remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
|
||||||
void removeWithAnchor(const uint256 &invalidRoot);
|
void removeWithAnchor(const uint256 &invalidRoot);
|
||||||
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
|
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