diff --git a/.github/workflows/ci-master.yml b/.github/workflows/ci-master.yml index 9a69ac704a..79b5109f51 100644 --- a/.github/workflows/ci-master.yml +++ b/.github/workflows/ci-master.yml @@ -71,7 +71,7 @@ jobs: working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Build Firo run: | - ./configure --disable-jni --enable-elysium --enable-tests --with-comparison-tool=no --prefix=$(realpath depends/x86_64-pc-linux-gnu) + ./configure --disable-jni --enable-tests --with-comparison-tool=no --prefix=$(realpath depends/x86_64-pc-linux-gnu) make -j$(nproc) working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Run Unit Tests @@ -141,7 +141,7 @@ jobs: working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Build Firo run: | - ./configure --without-libs --disable-jni --enable-elysium --prefix=$(realpath depends/x86_64-w64-mingw32) + ./configure --without-libs --disable-jni --prefix=$(realpath depends/x86_64-w64-mingw32) make -j$(nproc) working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Prepare Files for Artifact @@ -181,7 +181,7 @@ jobs: working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Build Firo run: | - ./configure --disable-jni --enable-elysium --prefix=$(grealpath depends/x86_64-apple-darwin*) + ./configure --disable-jni --prefix=$(grealpath depends/x86_64-apple-darwin*) make -j$(sysctl -n hw.activecpu) working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Prepare Files for Artifact diff --git a/Jenkinsfile b/Jenkinsfile index 1e11bc84d1..bdb9fe9bf1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -25,7 +25,7 @@ pipeline { sh 'mkdir -p dist' sh 'tar -C dist --strip-components=1 -xzf firo-*.tar.gz' dir('dist') { - sh './configure --prefix=`pwd`/../depends/x86_64-linux-gnu --enable-elysium --enable-tests --enable-crash-hooks' + sh './configure --prefix=`pwd`/../depends/x86_64-linux-gnu --enable-tests --enable-crash-hooks' sh 'make -j`nproc`' } } diff --git a/configure.ac b/configure.ac index 3e4e79638e..faa3f72a42 100644 --- a/configure.ac +++ b/configure.ac @@ -104,12 +104,6 @@ AC_ARG_WITH([bdb], [use_bdb=$withval], [use_bdb=auto]) - -AC_ARG_ENABLE([elysium], - [AS_HELP_STRING([--enable-elysium],[enable elysium (disabled by default)])], - [enable_elysium=$enableval], - [enable_elysium=no]) - AC_ARG_WITH([miniupnpc], [AS_HELP_STRING([--with-miniupnpc], [enable UPNP (default is yes if libminiupnpc is found)])], @@ -1053,15 +1047,6 @@ else AC_MSG_RESULT(no) fi -dnl enable elysium -AC_MSG_CHECKING([if elysium should be enabled]) -if test x$enable_elysium != xno; then - AC_MSG_RESULT(yes) - AC_DEFINE_UNQUOTED([ENABLE_ELYSIUM],[1],[Define if elysium should be compiled in]) -else - AC_MSG_RESULT(no) -fi - dnl enable upnp support AC_MSG_CHECKING([whether to build with support for UPnP]) if test x$have_miniupnpc = xno; then @@ -1171,7 +1156,6 @@ AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) -AM_CONDITIONAL([ENABLE_ELYSIUM],[test x$enable_elysium = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes]) AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes]) @@ -1328,4 +1312,4 @@ echo " CPPFLAGS = $CPPFLAGS" echo " CXX = $CXX" echo " CXXFLAGS = $CXXFLAGS" echo " LDFLAGS = $LDFLAGS" -echo +echo \ No newline at end of file diff --git a/contrib/bitcoin-qt.pro b/contrib/bitcoin-qt.pro index ec2a855913..7fe9e0a676 100644 --- a/contrib/bitcoin-qt.pro +++ b/contrib/bitcoin-qt.pro @@ -18,7 +18,6 @@ FORMS += \ ../src/qt/forms/signverifymessagedialog.ui \ ../src/qt/forms/transactiondescdialog.ui \ ../src/qt/forms/zerocoinpage.ui \ - ../src/qt/forms/sendmpdialog.ui \ ../src/qt/forms/sendcoinsdialog.ui \ RESOURCES += \ diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 798229fa8e..dee6034110 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -289,7 +289,6 @@ mkdir -p "$DISTSRC" --disable-ccache \ --disable-maintainer-mode \ --disable-dependency-tracking \ - --enable-elysium \ --enable-crash-hooks \ --without-libs \ ${CONFIGFLAGS} \ diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index dd5a541074..4077729844 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -108,15 +108,6 @@ 'lelantus_setmintstatus_validation.py', 'lelantus_mintspend.py', 'lelantus_spend_gettransaction.py', - 'elysium_create_denomination.py', - 'elysium_property_creation_fee.py', -# 'elysium_sendmint.py', - 'elysium_sendmint_wallet_encryption.py', - 'elysium_sendspend.py', - 'elysium_sendspend_wallet_encryption.py', - 'elysium_sigma_reindex.py', - 'elysium_sigma_reorg.py', - 'elysium_walletrecovery.py', 'mempool_doublesend_oneblock.py', 'mempool_reorg.py', 'mempool_spendcoinbase.py', diff --git a/qa/rpc-tests/elysium_create_denomination.py b/qa/rpc-tests/elysium_create_denomination.py deleted file mode 100755 index cc87eb0da8..0000000000 --- a/qa/rpc-tests/elysium_create_denomination.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python3 -from test_framework.authproxy import JSONRPCException -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import assert_equal, assert_raises_message - -class ElysiumCreateDenominationTest(ElysiumTestFramework): - def run_test(self): - super().run_test() - - # create non-sigma token - self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 1, 0, '', '', 'Normal Token', '', '', '1000000') - self.nodes[0].generate(1) - self.sync_all() - - # create sigma token - self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 2, 0, '', '', 'Sigma Token', '', '', '1000000', 1) - self.nodes[0].generate(1) - - self.sync_all() - - # test parameter value validation - assert_raises_message( - JSONRPCException, - 'Invalid address', - self.nodes[0].elysium_sendcreatedenomination, 'abc', 4, '1' - ) - - assert_raises_message( - JSONRPCException, - 'Property identifier is out of range', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], -1, '1' - ) - - assert_raises_message( - JSONRPCException, - 'Property identifier is out of range', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 0, '1' - ) - - assert_raises_message( - JSONRPCException, - 'Property identifier is out of range', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 4294967296, '1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid amount', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 3, '0.1' # fixed property will discard all fractional, so it will become 0 - ) - - assert_raises_message( - JSONRPCException, - 'Invalid amount', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 4, '0' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid amount', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 4, '-1' - ) - - # test parameter validation - assert_raises_message( - JSONRPCException, - 'Property identifier does not exist', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 5, '1' - ) - - assert_raises_message( - JSONRPCException, - 'Sender is not authorized to manage the property', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[1], 4, '1' - ) - - assert_raises_message( - JSONRPCException, - 'Property has not enabled Sigma', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 3, '1' - ) - - # test valid denomination creation - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], 4, '0.5') - self.nodes[0].generate(1) - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], 4, '1') - self.nodes[0].generate(1) - - self.sync_all() - - info = self.nodes[1].elysium_getproperty(4) - - assert_equal(info['denominations'][0]['id'], 0) - assert_equal(info['denominations'][0]['value'], '0.50000000') - assert_equal(info['denominations'][1]['id'], 1) - assert_equal(info['denominations'][1]['value'], '1.00000000') - - # test duplicate denomination check - assert_raises_message( - JSONRPCException, - 'Denomination with value 0.50000000 already exists', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 4, '0.5' - ) - - # test full denominations check - for i in range(255 - 2): - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], 4, str(i + 2)) - self.nodes[0].generate(1) # we need to mine here otherwise the input chaining will be too long - - assert_raises_message( - JSONRPCException, - 'No more room for new denomination', - self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 4, '1000' - ) - -if __name__ == '__main__': - ElysiumCreateDenominationTest().main() diff --git a/qa/rpc-tests/elysium_issuance_fixed.py b/qa/rpc-tests/elysium_issuance_fixed.py deleted file mode 100755 index 9e263f847e..0000000000 --- a/qa/rpc-tests/elysium_issuance_fixed.py +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/bin/env python3 -from test_framework.authproxy import JSONRPCException -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import assert_equal, assert_raises_message - -class ElysiumIssuanceFixedTest(ElysiumTestFramework): - def run_test(self): - super().run_test() - - # check parameter value validation - assert_raises_message( - JSONRPCException, - 'Invalid address', - self.nodes[0].elysium_sendissuancefixed, 'abc', 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid ecosystem (1 = main, 2 = test only)', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 0, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid ecosystem (1 = main, 2 = test only)', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 3, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid property type (1 = indivisible, 2 = divisible only)', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 0, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid property type (1 = indivisible, 2 = divisible only)', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 3, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Property appends/replaces are not yet supported', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 1, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'c' * 256, 'subcategory1', 'token1', 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 's' * 256, 'token1', 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 't' * 256, 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'h' * 256, 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'd' * 256, '1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid amount', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '-1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid amount', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '0' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid amount', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '0.1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid amount', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 2, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '-1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid amount', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 2, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '0' - ) - - assert_raises_message( - JSONRPCException, - 'Property name must not be empty', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', '', 'http://foo.com', 'data1', '1' - ) - - assert_raises_message( - JSONRPCException, - 'Sigma status is not valid', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '1', 4 - ) - - assert_raises_message( - JSONRPCException, - 'Sigma feature is not activated yet', - self.nodes[0].elysium_sendissuancefixed, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', '1', 1 - ) - - # create properties - tx1 = self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 1, 0, 'main', 'indivisible', 'token1', 'http://token1.com', 'data1', '1') - self.nodes[0].generate(150) # we need 100 blocks in order to specify sigma flag - self.sync_all() - - tx2 = self.nodes[1].elysium_sendissuancefixed(self.addrs[1], 1, 2, 0, 'main', 'divisible', 'token2', 'http://token2.com', 'data2', '1.1', 0) - self.nodes[1].generate(1) - self.sync_all() - - tx3 = self.nodes[2].elysium_sendissuancefixed(self.addrs[2], 2, 1, 0, 'test', 'indivisible', 'token3', 'http://token3.com', 'data3', '100', 1) - self.nodes[2].generate(1) - self.sync_all() - - tx4 = self.nodes[3].elysium_sendissuancefixed(self.addrs[3], 2, 2, 0, 'test', 'divisible', 'token4', 'http://token4.com', 'data4', '100.1', 2) - self.nodes[3].generate(1) - self.sync_all() - - tx5 = self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 1, 0, 'main', 'indivisible', 'token5', 'http://token5.com', 'data5', '1', 3) - self.nodes[0].generate(1) - self.sync_all() - - # check property creation - props = self.nodes[0].elysium_listproperties() - - assert_equal(len(props), 2 + 5) # 2 pre-defined properties + 5 new created - - self.assert_property_summary(props[2], 3, False, 'main', 'indivisible', 'token1', 'http://token1.com', 'data1') - self.assert_property_summary(props[3], 4, True, 'main', 'divisible', 'token2', 'http://token2.com', 'data2') - self.assert_property_summary(props[4], 5, False, 'main', 'indivisible', 'token5', 'http://token5.com', 'data5') # main eco tokens will come first - self.assert_property_summary(props[5], 2147483651, False, 'test', 'indivisible', 'token3', 'http://token3.com', 'data3') - self.assert_property_summary(props[6], 2147483652, True, 'test', 'divisible', 'token4', 'http://token4.com', 'data4') - - self.assert_property_info( - self.nodes[1].elysium_getproperty(3), - 3, - True, - self.addrs[0], - False, - 'main', - 'indivisible', - 'token1', - 'http://token1.com', - 'data1', - '1', - 'SoftDisabled', - tx1, - []) - self.assert_property_info( - self.nodes[2].elysium_getproperty(4), - 4, - True, - self.addrs[1], - True, - 'main', - 'divisible', - 'token2', - 'http://token2.com', - 'data2', - '1.10000000', - 'SoftDisabled', - tx2, - []) - self.assert_property_info( - self.nodes[1].elysium_getproperty(5), - 5, - True, - self.addrs[0], - False, - 'main', - 'indivisible', - 'token5', - 'http://token5.com', - 'data5', - '1', - 'HardEnabled', - tx5, - []) - self.assert_property_info( - self.nodes[3].elysium_getproperty(2147483651), - 2147483651, - True, - self.addrs[2], - False, - 'test', - 'indivisible', - 'token3', - 'http://token3.com', - 'data3', - '100', - 'SoftEnabled', - tx3, - []) - self.assert_property_info( - self.nodes[0].elysium_getproperty(2147483652), - 2147483652, - True, - self.addrs[3], - True, - 'test', - 'divisible', - 'token4', - 'http://token4.com', - 'data4', - '100.10000000', - 'HardDisabled', - tx4, - []) - -if __name__ == '__main__': - ElysiumIssuanceFixedTest().main() diff --git a/qa/rpc-tests/elysium_issuance_managed.py b/qa/rpc-tests/elysium_issuance_managed.py deleted file mode 100755 index bbd4c4ed67..0000000000 --- a/qa/rpc-tests/elysium_issuance_managed.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env python3 -from test_framework.authproxy import JSONRPCException -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import assert_equal, assert_raises_message - -class ElysiumIssuanceManagedTest(ElysiumTestFramework): - def run_test(self): - super().run_test() - - # check parameter value validation - assert_raises_message( - JSONRPCException, - 'Invalid address', - self.nodes[0].elysium_sendissuancemanaged, 'abc', 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid ecosystem (1 = main, 2 = test only)', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 0, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid ecosystem (1 = main, 2 = test only)', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 3, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid property type (1 = indivisible, 2 = divisible only)', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 0, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Invalid property type (1 = indivisible, 2 = divisible only)', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 3, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Property appends/replaces are not yet supported', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 1, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 0, 'c' * 256, 'subcategory1', 'token1', 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 0, 'category1', 's' * 256, 'token1', 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 't' * 256, 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'h' * 256, 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Text must not be longer than 255 characters', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'd' * 256 - ) - - assert_raises_message( - JSONRPCException, - 'Property name must not be empty', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', '', 'http://foo.com', 'data1' - ) - - assert_raises_message( - JSONRPCException, - 'Sigma status is not valid', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', 4 - ) - - assert_raises_message( - JSONRPCException, - 'Sigma feature is not activated yet', - self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 0, 'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1', 1 - ) - - # create properties - tx1 = self.nodes[0].elysium_sendissuancemanaged(self.addrs[0], 1, 1, 0, 'main', 'indivisible', 'token1', 'http://token1.com', 'data1') - self.nodes[0].generate(150) # we need 100 blocks in order to specify sigma flag - self.sync_all() - - tx2 = self.nodes[1].elysium_sendissuancemanaged(self.addrs[1], 1, 2, 0, 'main', 'divisible', 'token2', 'http://token2.com', 'data2', 0) - self.nodes[1].generate(1) - self.sync_all() - - tx3 = self.nodes[2].elysium_sendissuancemanaged(self.addrs[2], 2, 1, 0, 'test', 'indivisible', 'token3', 'http://token3.com', 'data3', 1) - self.nodes[2].generate(1) - self.sync_all() - - tx4 = self.nodes[3].elysium_sendissuancemanaged(self.addrs[3], 2, 2, 0, 'test', 'divisible', 'token4', 'http://token4.com', 'data4', 2) - self.nodes[3].generate(1) - self.sync_all() - - tx5 = self.nodes[0].elysium_sendissuancemanaged(self.addrs[0], 1, 1, 0, 'main', 'indivisible', 'token5', 'http://token5.com', 'data5', 3) - self.nodes[0].generate(1) - self.sync_all() - - # check property creation - props = self.nodes[0].elysium_listproperties() - - assert_equal(len(props), 2 + 5) # 2 pre-defined properties + 5 new created - - self.assert_property_summary(props[2], 3, False, 'main', 'indivisible', 'token1', 'http://token1.com', 'data1') - self.assert_property_summary(props[3], 4, True, 'main', 'divisible', 'token2', 'http://token2.com', 'data2') - self.assert_property_summary(props[4], 5, False, 'main', 'indivisible', 'token5', 'http://token5.com', 'data5') # main eco tokens will come first - self.assert_property_summary(props[5], 2147483651, False, 'test', 'indivisible', 'token3', 'http://token3.com', 'data3') - self.assert_property_summary(props[6], 2147483652, True, 'test', 'divisible', 'token4', 'http://token4.com', 'data4') - - self.assert_property_info( - self.nodes[1].elysium_getproperty(3), - 3, - False, - self.addrs[0], - False, - 'main', - 'indivisible', - 'token1', - 'http://token1.com', - 'data1', - '0', - 'SoftDisabled', - tx1, - []) - self.assert_property_info( - self.nodes[2].elysium_getproperty(4), - 4, - False, - self.addrs[1], - True, - 'main', - 'divisible', - 'token2', - 'http://token2.com', - 'data2', - '0.00000000', - 'SoftDisabled', - tx2, - []) - self.assert_property_info( - self.nodes[1].elysium_getproperty(5), - 5, - False, - self.addrs[0], - False, - 'main', - 'indivisible', - 'token5', - 'http://token5.com', - 'data5', - '0', - 'HardEnabled', - tx5, - []) - self.assert_property_info( - self.nodes[3].elysium_getproperty(2147483651), - 2147483651, - False, - self.addrs[2], - False, - 'test', - 'indivisible', - 'token3', - 'http://token3.com', - 'data3', - '0', - 'SoftEnabled', - tx3, - []) - self.assert_property_info( - self.nodes[0].elysium_getproperty(2147483652), - 2147483652, - False, - self.addrs[3], - True, - 'test', - 'divisible', - 'token4', - 'http://token4.com', - 'data4', - '0.00000000', - 'HardDisabled', - tx4, - []) - -if __name__ == '__main__': - ElysiumIssuanceManagedTest().main() diff --git a/qa/rpc-tests/elysium_property_creation_fee.py b/qa/rpc-tests/elysium_property_creation_fee.py deleted file mode 100755 index 0deb810816..0000000000 --- a/qa/rpc-tests/elysium_property_creation_fee.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python3 -from test_framework.authproxy import JSONRPCException -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import assert_raises_message - -class ElysiumPropertyCreationFeeTest(ElysiumTestFramework): - - def get_new_address(self, default_balance = 0): - addr = self.nodes[0].getnewaddress() - - if default_balance > 0: - self.nodes[0].sendtoaddress(addr, default_balance) - self.nodes[0].generate(1) - self.sync_all() - - return addr - - def test(self, balance = 1, ecosystem = 1, amount = None, expected_error = None): - addr = self.get_new_address(balance) - - operator = self.nodes[0].elysium_sendissuancemanaged - options = [addr, ecosystem, 1, 0, "", "", "Foo", "", ""] - - if amount is not None: - operator = self.nodes[0].elysium_sendissuancefixed - options.append(amount) - - if expected_error is None: - operator(*options) - self.nodes[0].generate(1) - self.sync_all() - else: - assert_raises_message( - JSONRPCException, - expected_error, - operator, - *options) - - def test_insufficient(self, balance = 1, ecosystem = 1, amount = None): - self.test(balance, ecosystem, amount, 'fees may not be sufficient') - - def run_test(self): - super().run_test() - - creation_fee_start_block = 250 - - # before creation fee is activated, all properies type should be able to create with low fee. - self.test(ecosystem = 1) - self.test(ecosystem = 1, amount = "10000") - self.test(ecosystem = 2) - self.test(ecosystem = 2, amount = "10000") - - # make sure, property creation fee is activated - self.nodes[0].generate(creation_fee_start_block - self.nodes[0].getblockcount()) - - # after the activation, 100 FIRO is required for creating main ecosystem property - self.test_insufficient(ecosystem = 1) - self.test_insufficient(ecosystem = 1, amount = "10000") - - # test ecosystem should be able to create with low fee - self.test(ecosystem = 2) - self.test(ecosystem = 2, amount = "10000") - - # creating main ecosystem property with 100 FIRO fee, should success - self.test(balance = 101, ecosystem = 1) - self.test(balance = 101, ecosystem = 1, amount = "10000") - -if __name__ == '__main__': - ElysiumPropertyCreationFeeTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/elysium_sendmint.py b/qa/rpc-tests/elysium_sendmint.py deleted file mode 100755 index 5bae9bf43d..0000000000 --- a/qa/rpc-tests/elysium_sendmint.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python3 -from test_framework.authproxy import JSONRPCException -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import assert_equal, assert_raises_message - -class ElysiumSendMintTest(ElysiumTestFramework): - def run_test(self): - super().run_test() - - sigma_start_block = 260 - - self.nodes[0].generatetoaddress(30, self.addrs[0]) - self.nodes[0].generate(sigma_start_block - self.nodes[0].getblockcount()) - - assert_equal(sigma_start_block, self.nodes[0].getblockcount()) - - # create non-sigma - self.nodes[0].elysium_sendissuancefixed( - self.addrs[0], 1, 1, 0, '', '', 'Non-Sigma', '', '', '1000000' - ) - self.nodes[0].generate(1) - nonSigmaProperty = 3 - - # create sigma with denominations (1, 2) - self.nodes[0].elysium_sendissuancefixed( - self.addrs[0], 1, 1, 0, '', '', 'Sigma', '', '', '1000000', 1 - ) - - self.nodes[0].generate(1) - sigmaProperty = 4 - - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], sigmaProperty, '1') - self.nodes[0].generate(1) - - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], sigmaProperty, '2') - self.nodes[0].generate(10) - - # non-sigma - addr = self.nodes[0].getnewaddress() - self.nodes[0].elysium_send(self.addrs[0], addr, nonSigmaProperty, "100") - self.nodes[0].sendtoaddress(addr, 100) - self.nodes[0].generate(10) - - assert_raises_message( - JSONRPCException, - 'Property has not enabled Sigma', - self.nodes[0].elysium_sendmint, addr, nonSigmaProperty, {"0": 1} - ) - - assert_equal("100", self.nodes[0].elysium_getbalance(addr, nonSigmaProperty)['balance']) - - # sigma - # mint without firo and token - addr = self.nodes[0].getnewaddress() - assert_raises_message( - JSONRPCException, - 'Sender has insufficient balance', - self.nodes[0].elysium_sendmint, addr, sigmaProperty, {"0": 1} - ) - - # mint without firo then fail - addr = self.nodes[0].getnewaddress() - self.nodes[0].elysium_send(self.addrs[0], addr, sigmaProperty, "100") - self.nodes[0].generate(10) - - assert_raises_message( - JSONRPCException, - 'Error choosing inputs for the send transaction', - self.nodes[0].elysium_sendmint, addr, sigmaProperty, {"0": 1} - ) - - assert_equal("100", self.nodes[0].elysium_getbalance(addr, sigmaProperty)['balance']) - assert_equal(0, len(self.nodes[0].elysium_listpendingmints())) - - # mint without token then fail - addr = self.nodes[0].getnewaddress() - self.nodes[0].sendtoaddress(addr, 100) - self.nodes[0].generate(10) - - assert_raises_message( - JSONRPCException, - 'Sender has insufficient balance', - self.nodes[0].elysium_sendmint, addr, sigmaProperty, {"0":1} - ) - - assert_equal("0", self.nodes[0].elysium_getbalance(addr, sigmaProperty)['balance']) - assert_equal(0, len(self.nodes[0].elysium_listpendingmints())) - - # success to mint should be shown on pending - addr = self.nodes[0].getnewaddress() - - self.nodes[0].elysium_send(self.addrs[0], addr, sigmaProperty, "100") - self.nodes[0].sendtoaddress(addr, 100) - self.nodes[0].generate(10) - self.nodes[0].elysium_sendmint(addr, sigmaProperty, {"0":1}) - - assert_equal(1, len(self.nodes[0].elysium_listpendingmints())) - assert_equal("99", self.nodes[0].elysium_getbalance(addr, sigmaProperty)['balance']) - - self.nodes[0].generate(1) - assert_equal(0, len(self.nodes[0].elysium_listpendingmints())) - assert_equal(1, len(self.nodes[0].elysium_listmints())) - -if __name__ == '__main__': - ElysiumSendMintTest().main() diff --git a/qa/rpc-tests/elysium_sendmint_wallet_encryption.py b/qa/rpc-tests/elysium_sendmint_wallet_encryption.py deleted file mode 100755 index c9743a62f2..0000000000 --- a/qa/rpc-tests/elysium_sendmint_wallet_encryption.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -from time import sleep -from test_framework.authproxy import JSONRPCException -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import (assert_raises_message, start_node, bitcoind_processes) - -class ElysiumSendMintWalletEncrytionTest(ElysiumTestFramework): - def run_test(self): - super().run_test() - - sigma_start_block = 150 - - self.nodes[0].generatetoaddress(100, self.addrs[0]) - self.nodes[0].generate(sigma_start_block - self.nodes[0].getblockcount()) - - self.nodes[0].elysium_sendissuancefixed( - self.addrs[0], 1, 1, 0, '', '', 'Sigma', '', '', '1000000', 1 - ) - self.nodes[0].generate(1) - sigmaProperty = 3 - - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], sigmaProperty, '1') - self.nodes[0].generate(10) - - passphase = 'test' - self.nodes[0].encryptwallet(passphase) - bitcoind_processes[0].wait() - self.nodes[0] = start_node(0, self.options.tmpdir, ['-elysium']) - - # try to mint using encrypted wallet - assert_raises_message( - JSONRPCException, - 'Wallet locked', - self.nodes[0].elysium_sendmint, self.addrs[0], sigmaProperty, {"0":1} - ) - - self.nodes[0].walletpassphrase(passphase, 3) - - self.nodes[0].elysium_sendmint(self.addrs[0], sigmaProperty, {"0":1}) - - sleep(3) - - assert_raises_message( - JSONRPCException, - 'Wallet locked', - self.nodes[0].elysium_sendmint, self.addrs[0], sigmaProperty, {"0":1} - ) - -if __name__ == "__main__": - ElysiumSendMintWalletEncrytionTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/elysium_sendspend.py b/qa/rpc-tests/elysium_sendspend.py deleted file mode 100755 index 6bf963a9fd..0000000000 --- a/qa/rpc-tests/elysium_sendspend.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 -from test_framework.authproxy import JSONRPCException -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import assert_equal, assert_raises_message -import time - -class ElysiumSendSpendTest(ElysiumTestFramework): - def run_test(self): - super().run_test() - - sigma_starting_block = 210 - - self.nodes[0].generatetoaddress(sigma_starting_block - self.nodes[0].getblockcount(), self.addrs[0]) - self.sync_all() - - assert_equal(sigma_starting_block, self.nodes[0].getblockcount()) - - # non-sigma - self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 1, 0, 'main', \ - 'indivisible', 'non-sigma', '', '', '1000000') - self.nodes[0].generate(1) - - nonSigmaProperty = 3 - - addr = self.nodes[1].getnewaddress() - self.nodes[0].elysium_send(self.addrs[0], addr, nonSigmaProperty, '100') - self.nodes[0].generate(1) - - self.sync_all() - - assert_raises_message( - JSONRPCException, - 'Denomination is not valid', - self.nodes[1].elysium_sendspend, self.addrs[1], nonSigmaProperty, 0 - ) - - # sigma - self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 1, 0, 'main', \ - 'indivisible', 'sigma', '', '', '1000000', 1) - self.nodes[0].generate(1) - - sigmaProperty = 4 - - addr = self.nodes[1].getnewaddress() - self.nodes[0].elysium_send(self.addrs[0], addr, sigmaProperty, '100') - - self.nodes[0].generate(1) - self.sync_all() - - assert_raises_message( - JSONRPCException, - 'Denomination is not valid', - self.nodes[1].elysium_sendspend, self.addrs[1], sigmaProperty, 0 - ) - - # generate some denominations and mint - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], sigmaProperty, '1') - self.nodes[0].generate(1) - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], sigmaProperty, '2') - self.nodes[0].generate(10) - self.sync_all() - - # spend without any mint - assert_raises_message( - JSONRPCException, - 'No available mint to spend', - self.nodes[1].elysium_sendspend, self.addrs[1], sigmaProperty, 0 - ) - - # have sigma mint but have no elysium mint - testing_node = self.nodes[1] # fresh node - addr = testing_node.getnewaddress() - self.nodes[0].sendtoaddress(addr, '100') - self.nodes[0].generate(1) - self.sync_all() - - testing_node.mint(2) - self.nodes[0].generate(10) - self.sync_all() - - assert_raises_message( - JSONRPCException, - 'No available mint to spend', - testing_node.elysium_sendspend, self.addrs[1], sigmaProperty, 0 - ) - - # have elysium mint have no sigma mint to spend - testing_node = self.nodes[2] # fresh node - addr = testing_node.getnewaddress() - self.nodes[0].sendtoaddress(addr, '100') - self.nodes[0].elysium_send(self.addrs[0], addr, sigmaProperty, '100') - self.nodes[0].generate(1) - self.sync_all() - - testing_node.elysium_sendmint(addr, sigmaProperty, {"0": 2}) - testing_node.generate(1) - self.sync_all() - time.sleep(1) - - assert_raises_message( - JSONRPCException, - 'Error no sigma mints to pay as transaction fee', - self.nodes[2].elysium_sendspend, self.addrs[0], sigmaProperty, 0 - ) - - # met all requirements - testing_node.mint(2) - testing_node.generate(10) - self.sync_all() - - receiver = self.nodes[0].getnewaddress() - - testing_node.elysium_sendspend(receiver, sigmaProperty, 0) - testing_node.elysium_sendspend(receiver, sigmaProperty, 0) - - testing_node.generate(1) - self.sync_all() - - assert_equal('2', self.nodes[0].elysium_getbalance(receiver, sigmaProperty)['balance']) - -if __name__ == '__main__': - ElysiumSendSpendTest().main() diff --git a/qa/rpc-tests/elysium_sendspend_wallet_encryption.py b/qa/rpc-tests/elysium_sendspend_wallet_encryption.py deleted file mode 100755 index 26a0a75245..0000000000 --- a/qa/rpc-tests/elysium_sendspend_wallet_encryption.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python3 -import time -from test_framework.authproxy import JSONRPCException -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import ( - assert_equal, - assert_raises_message, - bitcoind_processes, - connect_nodes, - start_node) - -class ElysiumSendSpendWalletEncryptionTest(ElysiumTestFramework): - def run_test(self): - super().run_test() - - sigma_start_block = 150 - passphase = "1234" - - owner = self.addrs[0] - - self.nodes[0].generatetoaddress( - sigma_start_block - self.nodes[0].getblockcount(), - owner) - self.sync_all() - - # create sigma - for _ in range(0, 10): - self.nodes[0].mint(1) - - self.nodes[0].generate(10) - - # create property - self.nodes[0].elysium_sendissuancefixed( - owner, 1, 1, 0, '', '', 'Sigma', '', '', '1000000', 1) - - self.nodes[0].generate(1) - sigmaProperty = 3 - - self.nodes[0].elysium_sendcreatedenomination(owner, sigmaProperty, '1') - self.nodes[0].generate(10) - - # mint 2 coins - self.nodes[0].elysium_sendmint(owner, sigmaProperty, {"0": 2}) - self.nodes[0].generate(10) - - # spend a coin - self.nodes[0].elysium_sendspend(owner, sigmaProperty, 0) - self.nodes[0].generate(1) - - blockcount = self.nodes[0].getblockcount() - - # encrypt wallet && restart node - self.nodes[0].encryptwallet(passphase) - bitcoind_processes[0].wait() - self.nodes[0] = start_node(0, self.options.tmpdir, ['-elysium', '-reindex']) - while self.nodes[0].getblockcount() < blockcount: - time.sleep(0.1) - - connect_nodes(self.nodes[0], 1) - - # try to spend using encrypted wallet - assert_raises_message( - JSONRPCException, - 'wallet locked', - self.nodes[0].elysium_sendspend, owner, sigmaProperty, 0) - - # Unlock - self.nodes[0].walletpassphrase(passphase, 10) - - # One coin remaining - unspends = self.nodes[0].elysium_listmints() - assert_equal(1, len(unspends)) - - # Spend another coin - self.nodes[0].elysium_sendspend(owner, sigmaProperty, 0) - - # No remaining coin - unspends = self.nodes[0].elysium_listmints() - assert_equal(0, len(unspends)) - -if __name__ == '__main__': - ElysiumSendSpendWalletEncryptionTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/elysium_sigma_reindex.py b/qa/rpc-tests/elysium_sigma_reindex.py deleted file mode 100755 index cf9e2c4d25..0000000000 --- a/qa/rpc-tests/elysium_sigma_reindex.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python3 -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import assert_equal, connect_nodes, start_node, stop_node, sync_blocks -import time - -class ElysiumSigmaReindexTest(ElysiumTestFramework): - def run_test(self): - super().run_test() - - sigma_start_block = 150 - self.nodes[0].generate(sigma_start_block - self.nodes[0].getblockcount()) - - # generate mints to spend - for _ in range(0, 10): - self.nodes[0].mint(1) - - self.nodes[0].generate(10) - self.sync_all() - - # create sigma with denominations (1, 2) - balance = '1000000' - self.nodes[0].elysium_sendissuancefixed( - self.addrs[0], 1, 1, 0, '', '', 'Sigma', '', '', balance, 1 - ) - - self.nodes[0].generate(1) - sigma_property = 3 - - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], sigma_property, '1') - self.nodes[0].generate(1) - - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], sigma_property, '2') - self.nodes[0].generate(10) - - # mint 4 coins - self.nodes[0].elysium_sendmint(self.addrs[0], sigma_property, {0: 2, 1: 2}) - - # spend 2 coins, then 2 coins remaining - self.nodes[0].generate(1) - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 0) - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 1) - - self.nodes[0].generate(1) - - # generate 2 coins more - unconfirmed_txid = self.nodes[0].elysium_sendmint(self.addrs[0], sigma_property, {0: 1, 1: 1}) - raw_unconfirmed = self.nodes[0].getrawtransaction(unconfirmed_txid) - - # check before reindex - self.sync_all() - confirmed_mints = self.nodes[0].elysium_listmints() - unconfirmed_mints = self.nodes[0].elysium_listpendingmints() - - assert_equal(2, len(confirmed_mints)) - assert_equal(2, len(unconfirmed_mints)) - - blockcount = self.nodes[0].getblockcount() - - # restart with reindexing - stop_node(self.nodes[0], 0) - self.nodes[0] = start_node(0, self.options.tmpdir, ['-elysium', '-reindex']) - - while self.nodes[0].getblockcount() < blockcount: - time.sleep(0.1) - - connect_nodes(self.nodes[0], 1) - - reindexed_confirmed_mints = self.nodes[0].elysium_listmints() - self.compare_mints(confirmed_mints, reindexed_confirmed_mints) - - reindexed_unconfirmed_mints = self.nodes[0].elysium_listpendingmints() - self.compare_mints(unconfirmed_mints, reindexed_unconfirmed_mints) - - # spend remaining mints - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 0) - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 1) - - self.nodes[0].generate(1) - - # all mints should be spend - remaining_mints = self.nodes[0].elysium_listmints() - assert_equal(0, len(remaining_mints)) - - # re-broadcast and try to remint remaining coins - self.nodes[0].clearmempool() - self.nodes[0].sendrawtransaction(raw_unconfirmed) - self.nodes[0].generate(1) - - new_confirmed_mints = self.nodes[0].elysium_listmints() - self.compare_mints(unconfirmed_mints, new_confirmed_mints) - - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 0) - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 1) - - self.nodes[0].generate(1) - - remaining_mints = self.nodes[0].elysium_listmints() - assert_equal(0, len(remaining_mints)) - - # all mints are spend then elysium balance should be the same as before - assert_equal(balance, self.nodes[0].elysium_getbalance(self.addrs[0], sigma_property)['balance']) - -if __name__ == '__main__': - ElysiumSigmaReindexTest().main() diff --git a/qa/rpc-tests/elysium_sigma_reorg.py b/qa/rpc-tests/elysium_sigma_reorg.py deleted file mode 100755 index 76ccc5e8ae..0000000000 --- a/qa/rpc-tests/elysium_sigma_reorg.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python3 -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import assert_equal - -class ElysiumSigmaReorgTest(ElysiumTestFramework): - def run_test(self): - super().run_test() - - sigma_start_block = 150 - self.nodes[0].generate(sigma_start_block - self.nodes[0].getblockcount()) - - # generate mints to spend - for _ in range(0, 10): - self.nodes[0].mint(1) - - self.nodes[0].generate(10) - self.sync_all() - - # create sigma with denominations (1, 2) - balance = '1000000' - self.nodes[0].elysium_sendissuancefixed( - self.addrs[0], 1, 1, 0, '', '', 'Sigma', '', '', balance, 1 - ) - - self.nodes[0].generate(1) - sigma_property = 3 - - self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], sigma_property, '1') - self.nodes[0].generate(10) - - # reorg to reverse mint and spend - self.nodes[0].elysium_sendmint(self.addrs[0], sigma_property, {0: 2}) - self.nodes[0].generate(1) - - mint_txid = self.nodes[0].elysium_sendmint(self.addrs[0], sigma_property, {0: 1}) - mint_tx = self.nodes[0].getrawtransaction(mint_txid) - - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 0) - - forked_block = self.nodes[0].generate(1) - - assert_equal(2, len(self.nodes[0].elysium_listmints())) - assert_equal(0, len(self.nodes[0].elysium_listpendingmints())) - - # reorg - self.nodes[0].invalidateblock(forked_block[0]) - - # elysium state still doesn't detect reorg until new block come. - assert_equal(2, len(self.nodes[0].elysium_listmints())) - assert_equal(0, len(self.nodes[0].elysium_listpendingmints())) - - # forked - self.nodes[0].clearmempool() - self.nodes[0].generate(1) - - assert_equal(2, len(self.nodes[0].elysium_listmints())) # a spend is reverse to confirmed - assert_equal(1, len(self.nodes[0].elysium_listpendingmints())) # a mint is reverse to unconfirmed - - # re-broadcast mint and spend - self.nodes[0].clearmempool() - self.nodes[0].sendrawtransaction(mint_tx) - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 0) - - self.nodes[0].generate(1) - - assert_equal(2, len(self.nodes[0].elysium_listmints())) - assert_equal(0, len(self.nodes[0].elysium_listpendingmints())) - - # spend all and check balance - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 0) - self.nodes[0].elysium_sendspend(self.addrs[0], sigma_property, 0) - - self.nodes[0].generate(1) - - assert_equal(balance, self.nodes[0].elysium_getbalance(self.addrs[0], sigma_property)['balance']) - -if __name__ == '__main__': - ElysiumSigmaReorgTest().main() diff --git a/qa/rpc-tests/elysium_walletrecovery.py b/qa/rpc-tests/elysium_walletrecovery.py deleted file mode 100755 index 5004787008..0000000000 --- a/qa/rpc-tests/elysium_walletrecovery.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -import os -from shutil import rmtree -from test_framework.test_framework import ElysiumTestFramework -from test_framework.util import ( - assert_equal, - connect_nodes_bi, - start_node, - stop_node, - sync_blocks) - -class ElysiumWalletRecoveryTest(ElysiumTestFramework): - def get_datadir(self, node): - return os.path.join(self.options.tmpdir, f"node{node}", "regtest") - - def get_walletfile(self, node): - datadir = self.get_datadir(node) - return os.path.join(datadir, "wallet.dat") - - def load_wallet_content(self, node): - with open(self.get_walletfile(node), mode='rb') as f: - return f.read() - - def clear_datadir(self, node): - datadir = self.get_datadir(node) - rmtree(datadir) - os.mkdir(datadir) - - def connect_to_other(self, node): - for i in range(0, len(self.nodes)): - if i != node: - connect_nodes_bi(self.nodes, node, i) - - def run_test(self): - # stop node and read wallet.dat - stop_node(self.nodes[0], 0) - fresh_wallet_content = self.load_wallet_content(0) - - self.nodes[0] = start_node(0, self.options.tmpdir, ["-elysium"]) - self.connect_to_other(0) - - super().run_test() - - # generate sigma property - owner = self.addrs[0] - - sigma_start_block = 150 - self.nodes[0].generatetoaddress( - sigma_start_block - self.nodes[0].getblockcount(), - owner) - - self.nodes[0].elysium_sendissuancefixed( - owner, 1, 1, 0, '', '', 'Test Sigma', '', '', '3', 1) - - self.nodes[0].generate(10) - sigmaProperty = 3 - - self.nodes[0].elysium_sendcreatedenomination(owner, sigmaProperty, '1') - self.nodes[0].generate(10) - - # generate two coins and spend one of them - self.nodes[0].elysium_sendmint(owner, sigmaProperty, {"0": 2}) - self.nodes[0].generate(10) - - for _ in range(10): - self.nodes[0].mint(1) - - self.nodes[0].generate(10) - - self.nodes[0].elysium_sendspend(owner, sigmaProperty, 0) - self.nodes[0].generate(10) - - sync_blocks(self.nodes) - - # stop, clear state and restore fresh wallet - stop_node(self.nodes[0], 0) - self.clear_datadir(0) - - walletfile = self.get_walletfile(0) - with open(walletfile, 'wb+') as wf: - wf.write(fresh_wallet_content) - - # start and sync - self.nodes[0] = start_node(0, self.options.tmpdir, ["-elysium"]) - self.connect_to_other(0) - - sync_blocks(self.nodes) - - # verify state - unspents = self.nodes[0].elysium_listmints() - assert_equal(1, len(unspents)) - assert_equal('2', self.nodes[0].elysium_getbalance(owner, sigmaProperty)['balance']) - - self.nodes[0].elysium_sendspend(owner, sigmaProperty, 0) - self.nodes[0].generate(10) - - unspents = self.nodes[0].elysium_listmints() - assert_equal(0, len(unspents)) - assert_equal('3', self.nodes[0].elysium_getbalance(owner, sigmaProperty)['balance']) - -if __name__ == '__main__': - ElysiumWalletRecoveryTest().main() diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py index 871ba9c76e..2c6d187168 100644 --- a/qa/rpc-tests/test_framework/test_framework.py +++ b/qa/rpc-tests/test_framework/test_framework.py @@ -285,62 +285,6 @@ def setup_network(self): binary=[self.options.testbinary] + [self.options.refbinary]*(self.num_nodes-1)) -class ElysiumTestFramework(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.addrs = [] - - def run_test(self): - for rpc in self.nodes: - addr = rpc.getnewaddress() - id = rpc.sendtoaddress(addr, 500) - self.nodes[0].sendrawtransaction(rpc.getrawtransaction(id)) - self.addrs.append(addr) - - self.nodes[0].generate(10) - - if len(self.nodes[0].getrawmempool()) > 0: - raise Exception("Fail to send funds for all initial addresses") - self.sync_all() - - def setup_nodes(self): - return start_nodes(self.num_nodes, self.options.tmpdir, [['-elysium'] for _ in range(self.num_nodes)]) - - def assert_property_summary(self, prop, id, divisible, cat, subcat, name, url, data): - assert_equal(prop['propertyid'], id) - assert_equal(prop['name'], name) - assert_equal(prop['category'], cat) - assert_equal(prop['subcategory'], subcat) - assert_equal(prop['data'], data) - assert_equal(prop['url'], url) - assert_equal(prop['divisible'], divisible) - - def assert_property_info(self, prop, id, fixed, issuer, divisible, cat, subcat, name, url, data, tokens, sigma, createtx, denoms): - assert_equal(prop['propertyid'], id) - assert_equal(prop['name'], name) - assert_equal(prop['category'], cat) - assert_equal(prop['subcategory'], subcat) - assert_equal(prop['data'], data) - assert_equal(prop['url'], url) - assert_equal(prop['divisible'], divisible) - assert_equal(prop['issuer'], issuer) - assert_equal(prop['creationtxid'], createtx) - assert_equal(prop['fixedissuance'], fixed) - assert_equal(prop['managedissuance'], not fixed) - assert_equal(prop['totaltokens'], tokens) - assert_equal(prop['sigmastatus'], sigma) - assert_equal(len(prop['denominations']), len(denoms)) - - for i in range(len(denoms)): - assert_equal(prop['denominations'][i]['id'], denoms[i]['id']) - assert_equal(prop['denominations'][i]['value'], denoms[i]['value']) - - def compare_mints(self, expected, actual): - mint_key_extractor = lambda m : (m['propertyid'], m['denomination'], m['value']) - expected.sort(key = mint_key_extractor) - actual.sort(key = mint_key_extractor) - - assert_equal(expected, actual) # # Znode tests support @@ -986,20 +930,3 @@ def generate_until_sigma_activated(self, num_node): return [] return node.generate(required_block - current_block) - - def create_default_property(self, name, num_node, address, sigma = True, amount = None): - node = self.nodes[num_node] - - sigma_status = 1 if sigma else 0 - - if amount is None: - node.elysium_sendissuancemanaged(address, 1, 1, 0, '', '', name, '', '', sigma_status) - else: - node.elysium_sendissuancefixed(address, 1, 1, 0, '', '', name, '', '', amount, sigma_status) - - node.generate(1) - self.sync_all() - - # get lastest id - properties = node.elysium_listproperties() - return max(map(lambda p: p["propertyid"], properties)) diff --git a/src/Makefile.am b/src/Makefile.am index 005a93bc0e..429a2b5349 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -928,7 +928,3 @@ else check-local: $(error Please rerun configure with tests enabling flag) endif - -if ENABLE_ELYSIUM -include Makefile.elysium.include -endif diff --git a/src/Makefile.elysium.include b/src/Makefile.elysium.include deleted file mode 100644 index 79ed4bda1c..0000000000 --- a/src/Makefile.elysium.include +++ /dev/null @@ -1,119 +0,0 @@ -ELYSIUM_H = \ - elysium/activation.h \ - elysium/consensushash.h \ - elysium/convert.h \ - elysium/createpayload.h \ - elysium/createtx.h \ - elysium/dex.h \ - elysium/ecdsa_context.h \ - elysium/ecdsa_signature.h \ - elysium/errors.h \ - elysium/fees.h \ - elysium/fetchwallettx.h \ - elysium/log.h \ - elysium/mdex.h \ - elysium/notifications.h \ - elysium/elysium.h \ - elysium/packetencoder.h \ - elysium/parse_string.h \ - elysium/pending.h \ - elysium/persistence.h \ - elysium/property.h \ - elysium/rpc.h \ - elysium/rpcpayload.h \ - elysium/rpcrawtx.h \ - elysium/rpcrequirements.h \ - elysium/rpctxobject.h \ - elysium/rpcvalues.h \ - elysium/rules.h \ - elysium/script.h \ - elysium/sigma.h \ - elysium/sigmaprimitives.h \ - elysium/sigmadb.h \ - elysium/signaturebuilder.h \ - elysium/sp.h \ - elysium/sto.h \ - elysium/tally.h \ - elysium/tx.h \ - elysium/txprocessor.h \ - elysium/uint256_extensions.h \ - elysium/utils.h \ - elysium/utilsbitcoin.h \ - elysium/version.h \ - elysium/walletcache.h \ - elysium/wallettxs.h - -ELYSIUM_CPP = \ - elysium/activation.cpp \ - elysium/consensushash.cpp \ - elysium/convert.cpp \ - elysium/createpayload.cpp \ - elysium/createtx.cpp \ - elysium/dex.cpp \ - elysium/ecdsa_context.cpp \ - elysium/ecdsa_signature.cpp \ - elysium/fees.cpp \ - elysium/fetchwallettx.cpp \ - elysium/log.cpp \ - elysium/mdex.cpp \ - elysium/notifications.cpp \ - elysium/elysium.cpp \ - elysium/packetencoder.cpp \ - elysium/parse_string.cpp \ - elysium/pending.cpp \ - elysium/persistence.cpp \ - elysium/property.cpp \ - elysium/rpc.cpp \ - elysium/rpcpayload.cpp \ - elysium/rpcrawtx.cpp \ - elysium/rpcrequirements.cpp \ - elysium/rpctxobject.cpp \ - elysium/rpcvalues.cpp \ - elysium/rules.cpp \ - elysium/script.cpp \ - elysium/sigma.cpp \ - elysium/sigmaprimitives.cpp \ - elysium/sigmadb.cpp \ - elysium/signaturebuilder.cpp \ - elysium/sp.cpp \ - elysium/sto.cpp \ - elysium/tally.cpp \ - elysium/tx.cpp \ - elysium/txprocessor.cpp \ - elysium/utils.cpp \ - elysium/utilsbitcoin.cpp \ - elysium/version.cpp \ - elysium/walletcache.cpp \ - elysium/wallettxs.cpp - -if ENABLE_WALLET -ELYSIUM_H += \ - elysium/rpctx.h \ - elysium/sigmawallet.h \ - elysium/sigmawalletv0.h \ - elysium/sigmawalletv1.h \ - elysium/wallet.h \ - elysium/walletmodels.h - -ELYSIUM_CPP += \ - elysium/rpctx.cpp \ - elysium/sigmawallet.cpp \ - elysium/sigmawalletv0.cpp \ - elysium/sigmawalletv1.cpp \ - elysium/wallet.cpp \ - elysium/walletmodels.cpp -endif - -libbitcoin_server_a_SOURCES += \ - $(ELYSIUM_CPP) \ - $(ELYSIUM_H) - -elysium/libbitcoin_server_a-version.$(OBJEXT): obj/build.h # build info - -CLEAN_ELYSIUM = elysium/*.gcda elysium/*.gcno - -CLEANFILES += $(CLEAN_ELYSIUM) - -if ENABLE_TESTS -include Makefile.elysiumtest.include -endif diff --git a/src/Makefile.elysiumtest.include b/src/Makefile.elysiumtest.include deleted file mode 100644 index 120cb418cb..0000000000 --- a/src/Makefile.elysiumtest.include +++ /dev/null @@ -1,56 +0,0 @@ -ELYSIUM_TEST_H = \ - elysium/test/utils_tx.h - -ELYSIUM_TEST_CPP = \ - elysium/test/alert_tests.cpp \ - elysium/test/build_tx_tests.cpp \ - elysium/test/checkpoint_tests.cpp \ - elysium/test/create_payload_tests.cpp \ - elysium/test/create_tx_tests.cpp \ - elysium/test/crowdsale_participation_tests.cpp \ - elysium/test/dex_purchase_tests.cpp \ - elysium/test/ecdsa_signature_tests.cpp \ - elysium/test/encoding_b_tests.cpp \ - elysium/test/encoding_c_tests.cpp \ - elysium/test/elysium_handler_tx.cpp \ - elysium/test/elysium_tests.cpp \ - elysium/test/lock_tests.cpp \ - elysium/test/marker_tests.cpp \ - elysium/test/output_restriction_tests.cpp \ - elysium/test/packetencoder_tests.cpp \ - elysium/test/parsing_b_tests.cpp \ - elysium/test/parsing_c_tests.cpp \ - elysium/test/property_tests.cpp \ - elysium/test/rounduint64_tests.cpp \ - elysium/test/rules_txs_tests.cpp \ - elysium/test/script_extraction_tests.cpp \ - elysium/test/script_solver_tests.cpp \ - elysium/test/sender_bycontribution_tests.cpp \ - elysium/test/sender_firstin_tests.cpp \ - elysium/test/sigma_tests.cpp \ - elysium/test/sigmadb_tests.cpp \ - elysium/test/sigmaprimitives_tests.cpp \ - elysium/test/signaturebuilder_sigmav1_tests.cpp \ - elysium/test/sp_tests.cpp \ - elysium/test/strtoint64_tests.cpp \ - elysium/test/swapbyteorder_tests.cpp \ - elysium/test/tally_tests.cpp \ - elysium/test/uint256_extensions_tests.cpp \ - elysium/test/utils_tx.cpp - -if ENABLE_WALLET -ELYSIUM_TEST_CPP += \ - elysium/test/sigmawallet_tests.cpp \ - elysium/test/sigmawalletv0_tests.cpp \ - elysium/test/sigmawalletv1_tests.cpp \ - elysium/test/wallet_tests.cpp \ - elysium/test/walletmodels_tests.cpp -endif - -BITCOIN_TESTS += \ - $(ELYSIUM_TEST_CPP) \ - $(ELYSIUM_TEST_H) - -CLEAN_ELYSIUM_TEST = elysium/test/*.gcda elysium/test/*.gcno - -CLEANFILES += $(CLEAN_ELYSIUM_TEST) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 56d62cfaff..32fc60c7d6 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -119,15 +119,6 @@ QT_FORMS_UI = \ qt/forms/sendtopcodedialog.ui \ qt/forms/signverifymessagedialog.ui \ qt/forms/transactiondescdialog.ui \ - qt/forms/sendmpdialog.ui \ - qt/forms/lookupaddressdialog.ui \ - qt/forms/lookupspdialog.ui \ - qt/forms/lookuptxdialog.ui \ - qt/forms/txhistorydialog.ui \ - qt/forms/metadexcanceldialog.ui \ - qt/forms/metadexdialog.ui \ - qt/forms/tradehistorydialog.ui \ - qt/forms/elyassetsdialog.ui \ qt/forms/lelantusdialog.ui \ qt/forms/createpcodedialog.ui @@ -186,15 +177,6 @@ QT_MOC_CPP = \ qt/moc_walletframe.cpp \ qt/moc_walletmodel.cpp \ qt/moc_walletview.cpp \ - qt/moc_sendmpdialog.cpp \ - qt/moc_lookupaddressdialog.cpp \ - qt/moc_lookupspdialog.cpp \ - qt/moc_lookuptxdialog.cpp \ - qt/moc_txhistorydialog.cpp \ - qt/moc_elyassetsdialog.cpp \ - qt/moc_metadexdialog.cpp \ - qt/moc_metadexcanceldialog.cpp \ - qt/moc_tradehistorydialog.cpp \ qt/moc_lelantusmodel.cpp \ qt/moc_lelantusdialog.cpp \ qt/moc_lelantuscoincontroldialog.cpp \ @@ -286,16 +268,6 @@ BITCOIN_QT_H = \ qt/walletmodeltransaction.h \ qt/walletview.h \ qt/winshutdownmonitor.h \ - qt/lookupaddressdialog.h \ - qt/lookupspdialog.h \ - qt/lookuptxdialog.h \ - qt/txhistorydialog.h \ - qt/elyassetsdialog.h \ - qt/metadexdialog.h \ - qt/metadexcanceldialog.h \ - qt/tradehistorydialog.h \ - qt/sendmpdialog.h \ - qt/elysium_qtutils.h \ qt/lelantusmodel.h \ qt/lelantusdialog.h \ qt/lelantuscoincontroldialog.h \ @@ -355,11 +327,6 @@ RES_ICONS = \ qt/res/icons/meta_partcancelled.png \ qt/res/icons/meta_partfilled.png \ qt/res/icons/meta_pending.png \ - qt/res/icons/elysium_in.png \ - qt/res/icons/elysium_inout.png \ - qt/res/icons/elysium_invalid.png \ - qt/res/icons/elysium_out.png \ - qt/res/icons/elysium_hourglass.png \ qt/res/icons/network_disabled.png \ qt/res/icons/open.png \ qt/res/icons/overview.png \ @@ -455,8 +422,7 @@ BITCOIN_QT_BASE_CPP = \ qt/rpcconsole.cpp \ qt/splashscreen.cpp \ qt/trafficgraphwidget.cpp \ - qt/utilitydialog.cpp \ - qt/elysium_qtutils.cpp + qt/utilitydialog.cpp BITCOIN_QT_WINDOWS_CPP = qt/winshutdownmonitor.cpp @@ -500,17 +466,6 @@ BITCOIN_QT_WALLET_CPP = \ qt/automintmodel.cpp \ qt/sparkmodel.cpp -FIRO_QT_ELYSIUM_CPP = \ - qt/elyassetsdialog.cpp \ - qt/lookupaddressdialog.cpp \ - qt/lookupspdialog.cpp \ - qt/lookuptxdialog.cpp \ - qt/metadexcanceldialog.cpp \ - qt/metadexdialog.cpp \ - qt/sendmpdialog.cpp \ - qt/tradehistorydialog.cpp \ - qt/txhistorydialog.cpp - BITCOIN_QT_CPP = $(BITCOIN_QT_BASE_CPP) if TARGET_WINDOWS BITCOIN_QT_CPP += $(BITCOIN_QT_WINDOWS_CPP) @@ -518,9 +473,6 @@ endif if ENABLE_WALLET BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_CPP) endif -if ENABLE_ELYSIUM -BITCOIN_QT_CPP += $(FIRO_QT_ELYSIUM_CPP) -endif RES_IMAGES = \ qt/res/images/splash.png \ diff --git a/src/elysium/COPYING b/src/elysium/COPYING deleted file mode 100644 index 873ce4faee..0000000000 --- a/src/elysium/COPYING +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2018-2019 Firo Developers -Copyright (c) 2013-2015 Omni Core Developers -Copyright (c) 2009-2015 Bitcoin Core Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/src/elysium/activation.cpp b/src/elysium/activation.cpp deleted file mode 100644 index 2f45602563..0000000000 --- a/src/elysium/activation.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/** - * @file activation.cpp - * - * This file contains feature activation utility code. - * - * Note main functions 'ActivateFeature()' and 'DeactivateFeature()' are consensus breaking and reside in rules.cpp - */ - -#include "elysium/activation.h" - -#include "elysium/log.h" -#include "elysium/version.h" - -#include "validation.h" -#include "ui_interface.h" - -#include - -#include -#include -#include - -namespace elysium -{ -//! Pending activations -std::vector vecPendingActivations; -//! Completed activations -std::vector vecCompletedActivations; - -/** - * Deletes pending activations with the given identifier. - * - * Deletion is not supported on the CompletedActivations vector. - */ -static void DeletePendingActivation(uint16_t featureId) -{ - for (std::vector::iterator it = vecPendingActivations.begin(); it != vecPendingActivations.end(); ) { - if ((*it).featureId == featureId) { - it = vecPendingActivations.erase(it); - } else { - ++it; - } - } -} - -/** - * Moves an activation from PendingActivations to CompletedActivations when it is activated. - * - * A signal is fired to notify the UI about the status update. - */ -static void PendingActivationCompleted(const FeatureActivation& activation) -{ - DeletePendingActivation(activation.featureId); - vecCompletedActivations.push_back(activation); - uiInterface.ElysiumStateChanged(); -} - -/** - * Adds a feature activation to the PendingActivations vector. - * - * If this feature was previously scheduled for activation, then the state pending objects are deleted. - */ -void AddPendingActivation(uint16_t featureId, int activationBlock, uint32_t minClientVersion, const std::string& featureName) -{ - DeletePendingActivation(featureId); - - FeatureActivation featureActivation; - featureActivation.featureId = featureId; - featureActivation.featureName = featureName; - featureActivation.activationBlock = activationBlock; - featureActivation.minClientVersion = minClientVersion; - - vecPendingActivations.push_back(featureActivation); - - uiInterface.ElysiumStateChanged(); -} - -/** - * Checks if any activations went live in the block. - */ -void CheckLiveActivations(int blockHeight) -{ - std::vector vecPendingActivations = GetPendingActivations(); - for (std::vector::iterator it = vecPendingActivations.begin(); it != vecPendingActivations.end(); ++it) { - const FeatureActivation& liveActivation = *it; - if (liveActivation.activationBlock > blockHeight) { - continue; - } - if (ELYSIUM_VERSION < liveActivation.minClientVersion) { - std::string msgText = strprintf("Shutting down due to unsupported feature activation (%d: %s)", liveActivation.featureId, liveActivation.featureName); - PrintToLog(msgText); - if (!GetBoolArg("-overrideforcedshutdown", false)) { - boost::filesystem::path persistPath = GetDataDir() / "MP_persist"; - if (boost::filesystem::exists(persistPath)) boost::filesystem::remove_all(persistPath); // prevent the node being restarted without a reparse after forced shutdown - AbortNode(msgText, msgText); - } - } - PendingActivationCompleted(liveActivation); - } -} - - -/** - * Returns the vector of pending activations. - */ -std::vector GetPendingActivations() -{ - return vecPendingActivations; -} - -/** - * Returns the vector of completed activations. - */ -std::vector GetCompletedActivations() -{ - return vecCompletedActivations; -} - -/** - * Removes all pending or completed activations. - * - * A signal is fired to notify the UI about the status update. - */ -void ClearActivations() -{ - vecPendingActivations.clear(); - vecCompletedActivations.clear(); - uiInterface.ElysiumStateChanged(); -} - -/** - * Determines whether the sender is an authorized source for Exodus Core feature activation. - * - * The option "-elysiumactivationallowsender=source" can be used to whitelist additional sources, - * and the option "-elysiumactivationignoresender=source" can be used to ignore a source. - * - * To consider any activation as authorized, "-elysiumactivationallowsender=any" can be used. This - * should only be done for testing purposes! - */ -bool CheckActivationAuthorization(const std::string& sender) -{ - std::set whitelisted; - - // Mainnet - 4 out of 5 signatures required from developers & board members - /* - "address": "3Fc5gWzEQh1YGeqVXH6E4GDEGgbZJREJQ3", - "scriptPubKey": "a91498a2d17e08ac677dc220b92e0b79406f2f441c2487", - "sigsrequired": 4, - "addresses": [ - "1883ZMsRJfzKNozUBJBTCxQ7EaiNioNDWz", // Zathras - zathras@exodus.foundation - Project maintainer, developer - "1HHv91gRxqBzQ3gydMob3LU8hqXcWoLfvd", // dexx - dexx@bitwatch.co - Project maintainer, developer - "1oyvGmABkeFRUECn2t8DEZPes6F7Gsc9T", // J.R. Willett - jr@exodus.foundation - Founder and Board Member - "17xr7sbehYY4YSZX9yuJe6gK9rrdRrZx26", // Craig Sellars - craig@exodus.foundation - Technologist and Board Member - "16oDZYCspsczfgKXVj3xyvsxH21NpEj94F" // Adam Chamely - adam@exodus.foundation - Project maintainer, developer - ], - */ - whitelisted.insert("48UM25xTXCxPRwnv36YjjJNaAK4whKR8Rd"); - - // Testnet / Regtest - // use -elysiumactivationallowsender for testing - - // Add manually whitelisted sources - if (mapMultiArgs.count("-elysiumactivationallowsender")) { - const std::vector &sources = mapMultiArgs.at("-elysiumactivationallowsender"); - - for (std::vector::const_iterator it = sources.begin(); it != sources.end(); ++it) { - whitelisted.insert(*it); - } - } - - // Remove manually ignored sources - if (mapMultiArgs.count("-elysiumactivationignoresender")) { - const std::vector &sources = mapMultiArgs.at("-elysiumactivationignoresender"); - - for (std::vector::const_iterator it = sources.begin(); it != sources.end(); ++it) { - whitelisted.erase(*it); - } - } - - bool fAuthorized = (whitelisted.count(sender) || - whitelisted.count("any")); - - return fAuthorized; -} - -/** - * Determines whether the sender is an authorized source to deactivate features. - * - * The custom options "-elysiumactivationallowsender=source" and "-elysiumactivationignoresender=source" are also applied to deactivations. - */ -bool CheckDeactivationAuthorization(const std::string& sender) -{ - std::set whitelisted; - - // Mainnet - 3 out of 5 signatures required from developers & board members - /* - "address" : "34kwkVRSvFVEoUwcQSgpQ4ZUasuZ54DJLD", - "script" : "multisig", - "sigsrequired" : 3, - "addresses" : [ - "1883ZMsRJfzKNozUBJBTCxQ7EaiNioNDWz", // Zathras - zathras@exodus.foundation - Project maintainer, developer - "1HHv91gRxqBzQ3gydMob3LU8hqXcWoLfvd", // dexx - dexx@bitwatch.co - Project maintainer, developer - "1oyvGmABkeFRUECn2t8DEZPes6F7Gsc9T", // J.R. Willett - jr@exodus.foundation - Founder and Board Member - "17xr7sbehYY4YSZX9yuJe6gK9rrdRrZx26", // Craig Sellars - craig@exodus.foundation - Technologist and Board Member - "16oDZYCspsczfgKXVj3xyvsxH21NpEj94F" // Adam Chamely - adam@exodus.foundation - Project maintainer, developer - ], - */ - whitelisted.insert("48UM25xTXCxPRwnv36YjjJNaAK4whKR8Rd"); - - // Testnet / Regtest - // use -elysiumactivationallowsender for testing - - // Add manually whitelisted sources - custom sources affect both activation and deactivation - if (mapMultiArgs.count("-elysiumactivationallowsender")) { - const std::vector &sources = mapMultiArgs.at("-elysiumactivationallowsender"); - - for (std::vector::const_iterator it = sources.begin(); it != sources.end(); ++it) { - whitelisted.insert(*it); - } - } - - // Remove manually ignored sources - custom sources affect both activation and deactivation - if (mapMultiArgs.count("-elysiumactivationignoresender")) { - const std::vector &sources = mapMultiArgs.at("-elysiumactivationignoresender"); - - for (std::vector::const_iterator it = sources.begin(); it != sources.end(); ++it) { - whitelisted.erase(*it); - } - } - - bool fAuthorized = (whitelisted.count(sender) || - whitelisted.count("any")); - - return fAuthorized; -} - -} // namespace elysium diff --git a/src/elysium/activation.h b/src/elysium/activation.h deleted file mode 100644 index ec450a7d0f..0000000000 --- a/src/elysium/activation.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef ELYSIUM_ACTIVATION_H -#define ELYSIUM_ACTIVATION_H - -#include -#include -#include - -namespace elysium -{ -/** A structure to represent a feature activation - */ -struct FeatureActivation -{ - uint16_t featureId; - int activationBlock; - uint32_t minClientVersion; - std::string featureName; -}; - -/** Determines whether the sender is an authorized source for Omni Core activations. */ -bool CheckActivationAuthorization(const std::string& sender); -/** Determines whether the sender is an authorized source to deactivate features. */ -bool CheckDeactivationAuthorization(const std::string& sender); -/** Returns the vector of pending activations */ -std::vector GetPendingActivations(); -/** Returns the vector of completed activations */ -std::vector GetCompletedActivations(); -/** Removes all pending or completed activations. */ -void ClearActivations(); -/** Checks if any activations went live in the block */ -void CheckLiveActivations(int blockHeight); -/** Adds a pending activation */ -void AddPendingActivation(uint16_t featureId, int activationBlock, uint32_t minClientVersion, const std::string& featureName); -} - -#endif // ELYSIUM_ACTIVATION_H diff --git a/src/elysium/consensushash.cpp b/src/elysium/consensushash.cpp deleted file mode 100644 index 878dd3f1a6..0000000000 --- a/src/elysium/consensushash.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/** - * @file consensushash.cpp - * - * This file contains the function to generate consensus hashes. - */ - -#include "elysium/consensushash.h" -#include "elysium/dex.h" -#include "elysium/mdex.h" -#include "elysium/log.h" -#include "elysium/elysium.h" -#include "elysium/parse_string.h" -#include "elysium/sp.h" - -#include "arith_uint256.h" -#include "uint256.h" - -#include -#include -#include -#include - -#include - -namespace elysium -{ -bool ShouldConsensusHashBlock(int block) { - if (elysium_debug_consensus_hash_every_block) { - return true; - } - - if (!mapMultiArgs.count("-elysiumshowblockconsensushash")) { - return false; - } - - const std::vector& vecBlocks = mapMultiArgs.at("-elysiumshowblockconsensushash"); - for (std::vector::const_iterator it = vecBlocks.begin(); it != vecBlocks.end(); ++it) { - int64_t paramBlock = StrToInt64(*it, false); - if (paramBlock < 1) continue; // ignore non numeric values - if (paramBlock == block) { - return true; - } - } - - return false; -} - -// Generates a consensus string for hashing based on a tally object -std::string GenerateConsensusString(const CMPTally& tallyObj, const std::string& address, const uint32_t propertyId) -{ - int64_t balance = tallyObj.getMoney(propertyId, BALANCE); - int64_t sellOfferReserve = tallyObj.getMoney(propertyId, SELLOFFER_RESERVE); - int64_t acceptReserve = tallyObj.getMoney(propertyId, ACCEPT_RESERVE); - int64_t metaDExReserve = tallyObj.getMoney(propertyId, METADEX_RESERVE); - - // return a blank string if all balances are empty - if (!balance && !sellOfferReserve && !acceptReserve && !metaDExReserve) return ""; - - return strprintf("%s|%d|%d|%d|%d|%d", - address, propertyId, balance, sellOfferReserve, acceptReserve, metaDExReserve); -} - -// Generates a consensus string for hashing based on a DEx sell offer object -std::string GenerateConsensusString(const CMPOffer& offerObj, const std::string& address) -{ - return strprintf("%s|%s|%d|%d|%d|%d|%d", - offerObj.getHash().GetHex(), address, offerObj.getProperty(), offerObj.getOfferAmountOriginal(), - offerObj.getXZCDesiredOriginal(), offerObj.getMinFee(), offerObj.getBlockTimeLimit()); -} - -// Generates a consensus string for hashing based on a DEx accept object -std::string GenerateConsensusString(const CMPAccept& acceptObj, const std::string& address) -{ - return strprintf("%s|%s|%d|%d|%d", - acceptObj.getHash().GetHex(), address, acceptObj.getAcceptAmount(), acceptObj.getAcceptAmountRemaining(), - acceptObj.getAcceptBlock()); -} - -// Generates a consensus string for hashing based on a MetaDEx object -std::string GenerateConsensusString(const CMPMetaDEx& tradeObj) -{ - return strprintf("%s|%s|%d|%d|%d|%d|%d", - tradeObj.getHash().GetHex(), tradeObj.getAddr(), tradeObj.getProperty(), tradeObj.getAmountForSale(), - tradeObj.getDesProperty(), tradeObj.getAmountDesired(), tradeObj.getAmountRemaining()); -} - -// Generates a consensus string for hashing based on a crowdsale object -std::string GenerateConsensusString(const CMPCrowd& crowdObj) -{ - return strprintf("%d|%d|%d|%d|%d", - crowdObj.getPropertyId(), crowdObj.getCurrDes(), crowdObj.getDeadline(), crowdObj.getUserCreated(), - crowdObj.getIssuerCreated()); -} - -// Generates a consensus string for hashing based on a property issuer -std::string GenerateConsensusString(const uint32_t propertyId, const std::string& address) -{ - return strprintf("%d|%s", propertyId, address); -} - -/** - * Obtains a hash of the active state to use for consensus verification and checkpointing. - * - * For increased flexibility, so other implementations like OmniWallet and OmniChest can - * also apply this methodology without necessarily using the same exact data types (which - * would be needed to hash the data bytes directly), create a string in the following - * format for each entry to use for hashing: - * - * ---STAGE 1 - BALANCES--- - * Format specifiers & placeholders: - * "%s|%d|%d|%d|%d|%d" - "address|propertyid|balance|selloffer_reserve|accept_reserve|metadex_reserve" - * - * Note: empty balance records and the pending tally are ignored. Addresses are sorted based - * on lexicographical order, and balance records are sorted by the property identifiers. - * - * ---STAGE 2 - DEX SELL OFFERS--- - * Format specifiers & placeholders: - * "%s|%s|%d|%d|%d|%d|%d" - "txid|address|propertyid|offeramount|btcdesired|minfee|timelimit" - * - * Note: ordered ascending by txid. - * - * ---STAGE 3 - DEX ACCEPTS--- - * Format specifiers & placeholders: - * "%s|%s|%d|%d|%d" - "matchedselloffertxid|buyer|acceptamount|acceptamountremaining|acceptblock" - * - * Note: ordered ascending by matchedselloffertxid followed by buyer. - * - * ---STAGE 4 - METADEX TRADES--- - * Format specifiers & placeholders: - * "%s|%s|%d|%d|%d|%d|%d" - "txid|address|propertyidforsale|amountforsale|propertyiddesired|amountdesired|amountremaining" - * - * Note: ordered ascending by txid. - * - * ---STAGE 5 - CROWDSALES--- - * Format specifiers & placeholders: - * "%d|%d|%d|%d|%d" - "propertyid|propertyiddesired|deadline|usertokens|issuertokens" - * - * Note: ordered by property ID. - * - * ---STAGE 6 - PROPERTIES--- - * Format specifiers & placeholders: - * "%d|%s" - "propertyid|issueraddress" - * - * Note: ordered by property ID. - * - * The byte order is important, and we assume: - * SHA256("abc") = "ad1500f261ff10b49c7a1796a36103b02322ae5dde404141eacf018fbf1678ba" - * - */ -uint256 GetConsensusHash() -{ - // allocate and init a SHA256_CTX - SHA256_CTX shaCtx; - SHA256_Init(&shaCtx); - - LOCK(cs_main); - - if (elysium_debug_consensus_hash) PrintToLog("Beginning generation of current consensus hash...\n"); - - // Balances - loop through the tally map, updating the sha context with the data from each balance and tally type - // Placeholders: "address|propertyid|balance|selloffer_reserve|accept_reserve|metadex_reserve" - // Sort alphabetically first - std::map tallyMapSorted; - for (std::unordered_map::iterator uoit = mp_tally_map.begin(); uoit != mp_tally_map.end(); ++uoit) { - tallyMapSorted.insert(std::make_pair(uoit->first,uoit->second)); - } - for (std::map::iterator my_it = tallyMapSorted.begin(); my_it != tallyMapSorted.end(); ++my_it) { - const std::string& address = my_it->first; - CMPTally& tally = my_it->second; - tally.init(); - uint32_t propertyId = 0; - while (0 != (propertyId = (tally.next()))) { - std::string dataStr = GenerateConsensusString(tally, address, propertyId); - if (dataStr.empty()) continue; // skip empty balances - if (elysium_debug_consensus_hash) PrintToLog("Adding balance data to consensus hash: %s\n", dataStr); - SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length()); - } - } - - // DEx sell offers - loop through the DEx and add each sell offer to the consensus hash (ordered by txid) - // Placeholders: "txid|address|propertyid|offeramount|btcdesired|minfee|timelimit" - std::vector > vecDExOffers; - for (OfferMap::iterator it = my_offers.begin(); it != my_offers.end(); ++it) { - const CMPOffer& selloffer = it->second; - const std::string& sellCombo = it->first; - std::string seller = sellCombo.substr(0, sellCombo.size() - 2); - std::string dataStr = GenerateConsensusString(selloffer, seller); - vecDExOffers.push_back(std::make_pair(arith_uint256(selloffer.getHash().ToString()), dataStr)); - } - std::sort (vecDExOffers.begin(), vecDExOffers.end()); - for (std::vector >::iterator it = vecDExOffers.begin(); it != vecDExOffers.end(); ++it) { - const std::string& dataStr = it->second; - if (elysium_debug_consensus_hash) PrintToLog("Adding DEx offer data to consensus hash: %s\n", dataStr); - SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length()); - } - - // DEx accepts - loop through the accepts map and add each accept to the consensus hash (ordered by matchedtxid then buyer) - // Placeholders: "matchedselloffertxid|buyer|acceptamount|acceptamountremaining|acceptblock" - std::vector > vecAccepts; - for (AcceptMap::const_iterator it = my_accepts.begin(); it != my_accepts.end(); ++it) { - const CMPAccept& accept = it->second; - const std::string& acceptCombo = it->first; - std::string buyer = acceptCombo.substr((acceptCombo.find("+") + 1), (acceptCombo.size()-(acceptCombo.find("+") + 1))); - std::string dataStr = GenerateConsensusString(accept, buyer); - std::string sortKey = strprintf("%s-%s", accept.getHash().GetHex(), buyer); - vecAccepts.push_back(std::make_pair(sortKey, dataStr)); - } - std::sort (vecAccepts.begin(), vecAccepts.end()); - for (std::vector >::iterator it = vecAccepts.begin(); it != vecAccepts.end(); ++it) { - const std::string& dataStr = it->second; - if (elysium_debug_consensus_hash) PrintToLog("Adding DEx accept to consensus hash: %s\n", dataStr); - SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length()); - } - - // MetaDEx trades - loop through the MetaDEx maps and add each open trade to the consensus hash (ordered by txid) - // Placeholders: "txid|address|propertyidforsale|amountforsale|propertyiddesired|amountdesired|amountremaining" - std::vector > vecMetaDExTrades; - for (md_PropertiesMap::const_iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - const md_PricesMap& prices = my_it->second; - for (md_PricesMap::const_iterator it = prices.begin(); it != prices.end(); ++it) { - const md_Set& indexes = it->second; - for (md_Set::const_iterator it = indexes.begin(); it != indexes.end(); ++it) { - const CMPMetaDEx& obj = *it; - std::string dataStr = GenerateConsensusString(obj); - vecMetaDExTrades.push_back(std::make_pair(arith_uint256(obj.getHash().ToString()), dataStr)); - } - } - } - std::sort (vecMetaDExTrades.begin(), vecMetaDExTrades.end()); - for (std::vector >::iterator it = vecMetaDExTrades.begin(); it != vecMetaDExTrades.end(); ++it) { - const std::string& dataStr = it->second; - if (elysium_debug_consensus_hash) PrintToLog("Adding MetaDEx trade data to consensus hash: %s\n", dataStr); - SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length()); - } - - // Crowdsales - loop through open crowdsales and add to the consensus hash (ordered by property ID) - // Note: the variables of the crowdsale (amount, bonus etc) are not part of the crowdsale map and not included here to - // avoid additionalal loading of SP entries from the database - // Placeholders: "propertyid|propertyiddesired|deadline|usertokens|issuertokens" - std::vector > vecCrowds; - for (CrowdMap::const_iterator it = my_crowds.begin(); it != my_crowds.end(); ++it) { - const CMPCrowd& crowd = it->second; - uint32_t propertyId = crowd.getPropertyId(); - std::string dataStr = GenerateConsensusString(crowd); - vecCrowds.push_back(std::make_pair(propertyId, dataStr)); - } - std::sort (vecCrowds.begin(), vecCrowds.end()); - for (std::vector >::iterator it = vecCrowds.begin(); it != vecCrowds.end(); ++it) { - std::string dataStr = (*it).second; - if (elysium_debug_consensus_hash) PrintToLog("Adding Crowdsale entry to consensus hash: %s\n", dataStr); - SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length()); - } - - // Properties - loop through each property and store the issuer (to capture state changes via change issuer transactions) - // Note: we are loading every SP from the DB to check the issuer, if using consensus_hash_every_block debug option this - // will slow things down dramatically. Not an issue to do it once every 10,000 blocks for checkpoint verification. - // Placeholders: "propertyid|issueraddress" - for (uint8_t ecosystem = 1; ecosystem <= 2; ecosystem++) { - uint32_t startPropertyId = (ecosystem == 1) ? 1 : TEST_ECO_PROPERTY_1; - for (uint32_t propertyId = startPropertyId; propertyId < _my_sps->peekNextSPID(ecosystem); propertyId++) { - CMPSPInfo::Entry sp; - if (!_my_sps->getSP(propertyId, sp)) { - PrintToLog("Error loading property ID %d for consensus hashing, hash should not be trusted!\n"); - continue; - } - std::string dataStr = GenerateConsensusString(propertyId, sp.issuer); - if (elysium_debug_consensus_hash) PrintToLog("Adding property to consensus hash: %s\n", dataStr); - SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length()); - } - } - - // extract the final result and return the hash - uint256 consensusHash; - SHA256_Final((unsigned char*)&consensusHash, &shaCtx); - if (elysium_debug_consensus_hash) PrintToLog("Finished generation of consensus hash. Result: %s\n", consensusHash.GetHex()); - - return consensusHash; -} - -uint256 GetMetaDExHash(const uint32_t propertyId) -{ - SHA256_CTX shaCtx; - SHA256_Init(&shaCtx); - - LOCK(cs_main); - - std::vector > vecMetaDExTrades; - for (md_PropertiesMap::const_iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - if (propertyId == 0 || propertyId == my_it->first) { - const md_PricesMap& prices = my_it->second; - for (md_PricesMap::const_iterator it = prices.begin(); it != prices.end(); ++it) { - const md_Set& indexes = it->second; - for (md_Set::const_iterator it = indexes.begin(); it != indexes.end(); ++it) { - const CMPMetaDEx& obj = *it; - std::string dataStr = GenerateConsensusString(obj); - vecMetaDExTrades.push_back(std::make_pair(arith_uint256(obj.getHash().ToString()), dataStr)); - } - } - } - } - std::sort (vecMetaDExTrades.begin(), vecMetaDExTrades.end()); - for (std::vector >::iterator it = vecMetaDExTrades.begin(); it != vecMetaDExTrades.end(); ++it) { - const std::string& dataStr = it->second; - SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length()); - } - - uint256 metadexHash; - SHA256_Final((unsigned char*)&metadexHash, &shaCtx); - - return metadexHash; -} - -/** Obtains a hash of the balances for a specific property. */ -uint256 GetBalancesHash(const uint32_t hashPropertyId) -{ - SHA256_CTX shaCtx; - SHA256_Init(&shaCtx); - - LOCK(cs_main); - - std::map tallyMapSorted; - for (std::unordered_map::iterator uoit = mp_tally_map.begin(); uoit != mp_tally_map.end(); ++uoit) { - tallyMapSorted.insert(std::make_pair(uoit->first,uoit->second)); - } - for (std::map::iterator my_it = tallyMapSorted.begin(); my_it != tallyMapSorted.end(); ++my_it) { - const std::string& address = my_it->first; - CMPTally& tally = my_it->second; - tally.init(); - uint32_t propertyId = 0; - while (0 != (propertyId = (tally.next()))) { - if (propertyId != hashPropertyId) continue; - std::string dataStr = GenerateConsensusString(tally, address, propertyId); - if (dataStr.empty()) continue; - if (elysium_debug_consensus_hash) PrintToLog("Adding data to balances hash: %s\n", dataStr); - SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length()); - } - } - - uint256 balancesHash; - SHA256_Final((unsigned char*)&balancesHash, &shaCtx); - - return balancesHash; -} - -} // namespace elysium diff --git a/src/elysium/consensushash.h b/src/elysium/consensushash.h deleted file mode 100644 index ebbdde11d5..0000000000 --- a/src/elysium/consensushash.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ELYSIUM_CONSENSUSHASH_H -#define ELYSIUM_CONSENSUSHASH_H - -#include "uint256.h" - -namespace elysium -{ -/** Checks if a given block should be consensus hashed. */ -bool ShouldConsensusHashBlock(int block); - -/** Obtains a hash of all balances to use for consensus verification and checkpointing. */ -uint256 GetConsensusHash(); - -/** Obtains a hash of the overall MetaDEx state (default) or a specific orderbook (supply a property ID). */ -uint256 GetMetaDExHash(const uint32_t propertyId = 0); - -/** Obtains a hash of the balances for a specific property. */ -uint256 GetBalancesHash(const uint32_t hashPropertyId); - -} // namespace elysium - -#endif // ELYSIUM_CONSENSUSHASH_H diff --git a/src/elysium/convert.cpp b/src/elysium/convert.cpp deleted file mode 100644 index 420785f409..0000000000 --- a/src/elysium/convert.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "elysium/convert.h" - -#include -#include - -namespace elysium -{ - -// TODO: move to seperate file with checks -static bool isBigEndian() -{ - union - { - uint32_t i; - char c[4]; - } bint = {0x01020304}; - - return 1 == bint.c[0]; -} - -uint64_t rounduint64(double ld) -{ - return static_cast(round(fabs(ld))); -} - -void swapByteOrder16(uint16_t& us) -{ - if (isBigEndian()) return; - - us = (us >> 8) | - (us << 8); -} - -void swapByteOrder32(uint32_t& ui) -{ - if (isBigEndian()) return; - - ui = (ui >> 24) | - ((ui << 8) & 0x00FF0000) | - ((ui >> 8) & 0x0000FF00) | - (ui << 24); -} - -void swapByteOrder64(uint64_t& ull) -{ - if (isBigEndian()) return; - - ull = (ull >> 56) | - ((ull << 40) & 0x00FF000000000000) | - ((ull << 24) & 0x0000FF0000000000) | - ((ull << 8) & 0x000000FF00000000) | - ((ull >> 8) & 0x00000000FF000000) | - ((ull >> 24) & 0x0000000000FF0000) | - ((ull >> 40) & 0x000000000000FF00) | - (ull << 56); -} - -} // namespace elysium diff --git a/src/elysium/convert.h b/src/elysium/convert.h deleted file mode 100644 index bdb2dae9f9..0000000000 --- a/src/elysium/convert.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef ELYSIUM_CONVERT_H -#define ELYSIUM_CONVERT_H - -#include -#include - -namespace elysium -{ - -/** - * Converts numbers to 64 bit wide unsigned integer whereby - * any signedness is ignored. If absolute value of the number - * is greater or equal than .5, then the result is rounded - * up and down otherwise. - */ -uint64_t rounduint64(double); - -/** - * Swaps byte order on little-endian systems and does nothing - * otherwise. swapByteOrder cycles on LE systems. - */ -void swapByteOrder16(uint16_t&); -void swapByteOrder32(uint32_t&); -void swapByteOrder64(uint64_t&); - -template -void swapByteOrder(T& t) -{ - switch (sizeof(t)) { - case sizeof(uint16_t): - swapByteOrder16(reinterpret_cast(t)); - break; - case sizeof(uint32_t): - swapByteOrder32(reinterpret_cast(t)); - break; - case sizeof(uint64_t): - swapByteOrder64(reinterpret_cast(t)); - break; - default: - throw std::invalid_argument("swapByteOrder(): invalid size"); - } -} - -} // namespace elysium - -#endif // ELYSIUM_CONVERT_H diff --git a/src/elysium/createpayload.cpp b/src/elysium/createpayload.cpp deleted file mode 100644 index 9e4e3aead1..0000000000 --- a/src/elysium/createpayload.cpp +++ /dev/null @@ -1,676 +0,0 @@ -#include "createpayload.h" - -#include "convert.h" -#include "sigma.h" -#include "tx.h" -#include "utils.h" - -#include "../clientversion.h" -#include "../tinyformat.h" -#include "../streams.h" -#include "../version.h" - -#include -#include - -#include - -/** - * Pushes bytes to the end of a vector. - */ -#define PUSH_BACK_BYTES(vector, value)\ - vector.insert(vector.end(), reinterpret_cast(&(value)),\ - reinterpret_cast(&(value)) + sizeof((value))); - -/** - * Pushes bytes to the end of a vector based on a pointer. - */ -#define PUSH_BACK_BYTES_PTR(vector, ptr, size)\ - vector.insert(vector.end(), reinterpret_cast((ptr)),\ - reinterpret_cast((ptr)) + (size)); - - -std::vector CreatePayload_SimpleSend(uint32_t propertyId, uint64_t amount) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_SIMPLE_SEND; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - elysium::swapByteOrder64(amount); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, amount); - - return payload; -} - -std::vector CreatePayload_SendAll(uint8_t ecosystem) -{ - std::vector payload; - uint16_t messageVer = 0; - uint16_t messageType = ELYSIUM_TYPE_SEND_ALL; - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, ecosystem); - - return payload; -} - -std::vector CreatePayload_DExSell(uint32_t propertyId, uint64_t amountForSale, uint64_t amountDesired, uint8_t timeLimit, uint64_t minFee, uint8_t subAction) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_TRADE_OFFER; - uint16_t messageVer = 1; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - elysium::swapByteOrder64(amountForSale); - elysium::swapByteOrder64(amountDesired); - elysium::swapByteOrder64(minFee); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, amountForSale); - PUSH_BACK_BYTES(payload, amountDesired); - PUSH_BACK_BYTES(payload, timeLimit); - PUSH_BACK_BYTES(payload, minFee); - PUSH_BACK_BYTES(payload, subAction); - - return payload; -} - -std::vector CreatePayload_DExAccept(uint32_t propertyId, uint64_t amount) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_ACCEPT_OFFER_BTC; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - elysium::swapByteOrder64(amount); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, amount); - - return payload; -} - -std::vector CreatePayload_SendToOwners(uint32_t propertyId, uint64_t amount, uint32_t distributionProperty) -{ - bool v0 = (propertyId == distributionProperty) ? true : false; - - std::vector payload; - - uint16_t messageType = ELYSIUM_TYPE_SEND_TO_OWNERS; - uint16_t messageVer = (v0) ? 0 : 1; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - elysium::swapByteOrder64(amount); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, amount); - if (!v0) { - elysium::swapByteOrder32(distributionProperty); - PUSH_BACK_BYTES(payload, distributionProperty); - } - - return payload; -} - -std::vector CreatePayload_IssuanceFixed(uint8_t ecosystem, uint16_t propertyType, uint32_t previousPropertyId, std::string category, - std::string subcategory, std::string name, std::string url, std::string data, uint64_t amount, - boost::optional sigmaStatus) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_CREATE_PROPERTY_FIXED; - uint16_t messageVer = sigmaStatus ? 1 : 0; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(propertyType); - elysium::swapByteOrder32(previousPropertyId); - elysium::swapByteOrder64(amount); - - if (category.size() > 255) category = category.substr(0,255); - if (subcategory.size() > 255) subcategory = subcategory.substr(0,255); - if (name.size() > 255) name = name.substr(0,255); - if (url.size() > 255) url = url.substr(0,255); - if (data.size() > 255) data = data.substr(0,255); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, ecosystem); - PUSH_BACK_BYTES(payload, propertyType); - PUSH_BACK_BYTES(payload, previousPropertyId); - payload.insert(payload.end(), category.begin(), category.end()); - payload.push_back('\0'); - payload.insert(payload.end(), subcategory.begin(), subcategory.end()); - payload.push_back('\0'); - payload.insert(payload.end(), name.begin(), name.end()); - payload.push_back('\0'); - payload.insert(payload.end(), url.begin(), url.end()); - payload.push_back('\0'); - payload.insert(payload.end(), data.begin(), data.end()); - payload.push_back('\0'); - PUSH_BACK_BYTES(payload, amount); - - if (sigmaStatus) { - PUSH_BACK_BYTES(payload, sigmaStatus.get()); - } - - return payload; -} - -std::vector CreatePayload_IssuanceVariable(uint8_t ecosystem, uint16_t propertyType, uint32_t previousPropertyId, std::string category, - std::string subcategory, std::string name, std::string url, std::string data, uint32_t propertyIdDesired, - uint64_t amountPerUnit, uint64_t deadline, uint8_t earlyBonus, uint8_t issuerPercentage) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(propertyType); - elysium::swapByteOrder32(previousPropertyId); - elysium::swapByteOrder32(propertyIdDesired); - elysium::swapByteOrder64(amountPerUnit); - elysium::swapByteOrder64(deadline); - if (category.size() > 255) category = category.substr(0,255); - if (subcategory.size() > 255) subcategory = subcategory.substr(0,255); - if (name.size() > 255) name = name.substr(0,255); - if (url.size() > 255) url = url.substr(0,255); - if (data.size() > 255) data = data.substr(0,255); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, ecosystem); - PUSH_BACK_BYTES(payload, propertyType); - PUSH_BACK_BYTES(payload, previousPropertyId); - payload.insert(payload.end(), category.begin(), category.end()); - payload.push_back('\0'); - payload.insert(payload.end(), subcategory.begin(), subcategory.end()); - payload.push_back('\0'); - payload.insert(payload.end(), name.begin(), name.end()); - payload.push_back('\0'); - payload.insert(payload.end(), url.begin(), url.end()); - payload.push_back('\0'); - payload.insert(payload.end(), data.begin(), data.end()); - payload.push_back('\0'); - PUSH_BACK_BYTES(payload, propertyIdDesired); - PUSH_BACK_BYTES(payload, amountPerUnit); - PUSH_BACK_BYTES(payload, deadline); - PUSH_BACK_BYTES(payload, earlyBonus); - PUSH_BACK_BYTES(payload, issuerPercentage); - - return payload; -} - -std::vector CreatePayload_IssuanceManaged(uint8_t ecosystem, uint16_t propertyType, uint32_t previousPropertyId, std::string category, - std::string subcategory, std::string name, std::string url, std::string data, - boost::optional sigmaStatus) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL; - uint16_t messageVer = sigmaStatus ? 1 : 0; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(propertyType); - elysium::swapByteOrder32(previousPropertyId); - - if (category.size() > 255) category = category.substr(0,255); - if (subcategory.size() > 255) subcategory = subcategory.substr(0,255); - if (name.size() > 255) name = name.substr(0,255); - if (url.size() > 255) url = url.substr(0,255); - if (data.size() > 255) data = data.substr(0,255); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, ecosystem); - PUSH_BACK_BYTES(payload, propertyType); - PUSH_BACK_BYTES(payload, previousPropertyId); - payload.insert(payload.end(), category.begin(), category.end()); - payload.push_back('\0'); - payload.insert(payload.end(), subcategory.begin(), subcategory.end()); - payload.push_back('\0'); - payload.insert(payload.end(), name.begin(), name.end()); - payload.push_back('\0'); - payload.insert(payload.end(), url.begin(), url.end()); - payload.push_back('\0'); - payload.insert(payload.end(), data.begin(), data.end()); - payload.push_back('\0'); - - if (sigmaStatus) { - PUSH_BACK_BYTES(payload, sigmaStatus.get()); - } - - return payload; -} - -std::vector CreatePayload_CloseCrowdsale(uint32_t propertyId) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_CLOSE_CROWDSALE; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - - return payload; -} - -std::vector CreatePayload_Grant(uint32_t propertyId, uint64_t amount, std::string memo) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_GRANT_PROPERTY_TOKENS; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - elysium::swapByteOrder64(amount); - if (memo.size() > 255) memo = memo.substr(0,255); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, amount); - payload.insert(payload.end(), memo.begin(), memo.end()); - payload.push_back('\0'); - - return payload; -} - - -std::vector CreatePayload_Revoke(uint32_t propertyId, uint64_t amount, std::string memo) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_REVOKE_PROPERTY_TOKENS; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - elysium::swapByteOrder64(amount); - if (memo.size() > 255) memo = memo.substr(0,255); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, amount); - payload.insert(payload.end(), memo.begin(), memo.end()); - payload.push_back('\0'); - - return payload; -} - -std::vector CreatePayload_ChangeIssuer(uint32_t propertyId) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_CHANGE_ISSUER_ADDRESS; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - - return payload; -} - -std::vector CreatePayload_EnableFreezing(uint32_t propertyId) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_ENABLE_FREEZING; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - - return payload; -} - -std::vector CreatePayload_DisableFreezing(uint32_t propertyId) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_DISABLE_FREEZING; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - - return payload; -} - -std::vector CreatePayload_FreezeTokens(uint32_t propertyId, uint64_t amount, const std::string& address) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_FREEZE_PROPERTY_TOKENS; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - elysium::swapByteOrder64(amount); - std::vector addressBytes = AddressToBytes(address); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, amount); - payload.insert(payload.end(), addressBytes.begin(), addressBytes.end()); - - return payload; -} - -std::vector CreatePayload_UnfreezeTokens(uint32_t propertyId, uint64_t amount, const std::string& address) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_TYPE_UNFREEZE_PROPERTY_TOKENS; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder32(propertyId); - elysium::swapByteOrder64(amount); - std::vector addressBytes = AddressToBytes(address); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, amount); - payload.insert(payload.end(), addressBytes.begin(), addressBytes.end()); - - return payload; -} - -std::vector CreatePayload_MetaDExTrade(uint32_t propertyIdForSale, uint64_t amountForSale, uint32_t propertyIdDesired, uint64_t amountDesired) -{ - std::vector payload; - - uint16_t messageType = ELYSIUM_TYPE_METADEX_TRADE; - uint16_t messageVer = 0; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder32(propertyIdForSale); - elysium::swapByteOrder64(amountForSale); - elysium::swapByteOrder32(propertyIdDesired); - elysium::swapByteOrder64(amountDesired); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyIdForSale); - PUSH_BACK_BYTES(payload, amountForSale); - PUSH_BACK_BYTES(payload, propertyIdDesired); - PUSH_BACK_BYTES(payload, amountDesired); - - return payload; -} - -std::vector CreatePayload_MetaDExCancelPrice(uint32_t propertyIdForSale, uint64_t amountForSale, uint32_t propertyIdDesired, uint64_t amountDesired) -{ - std::vector payload; - - uint16_t messageType = ELYSIUM_TYPE_METADEX_CANCEL_PRICE; - uint16_t messageVer = 0; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder32(propertyIdForSale); - elysium::swapByteOrder64(amountForSale); - elysium::swapByteOrder32(propertyIdDesired); - elysium::swapByteOrder64(amountDesired); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyIdForSale); - PUSH_BACK_BYTES(payload, amountForSale); - PUSH_BACK_BYTES(payload, propertyIdDesired); - PUSH_BACK_BYTES(payload, amountDesired); - - return payload; -} - -std::vector CreatePayload_MetaDExCancelPair(uint32_t propertyIdForSale, uint32_t propertyIdDesired) -{ - std::vector payload; - - uint16_t messageType = ELYSIUM_TYPE_METADEX_CANCEL_PAIR; - uint16_t messageVer = 0; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder32(propertyIdForSale); - elysium::swapByteOrder32(propertyIdDesired); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyIdForSale); - PUSH_BACK_BYTES(payload, propertyIdDesired); - - return payload; -} - -std::vector CreatePayload_MetaDExCancelEcosystem(uint8_t ecosystem) -{ - std::vector payload; - - uint16_t messageType = ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM; - uint16_t messageVer = 0; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, ecosystem); - - return payload; -} - -std::vector CreatePayload_DeactivateFeature(uint16_t featureId) -{ - std::vector payload; - - uint16_t messageVer = 65535; - uint16_t messageType = ELYSIUM_MESSAGE_TYPE_DEACTIVATION; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(featureId); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, featureId); - - return payload; -} - -std::vector CreatePayload_ActivateFeature(uint16_t featureId, uint32_t activationBlock, uint32_t minClientVersion) -{ - std::vector payload; - - uint16_t messageVer = 65535; - uint16_t messageType = ELYSIUM_MESSAGE_TYPE_ACTIVATION; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(featureId); - elysium::swapByteOrder32(activationBlock); - elysium::swapByteOrder32(minClientVersion); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, featureId); - PUSH_BACK_BYTES(payload, activationBlock); - PUSH_BACK_BYTES(payload, minClientVersion); - - return payload; -} - -std::vector CreatePayload_ElysiumAlert(uint16_t alertType, uint32_t expiryValue, const std::string& alertMessage) -{ - std::vector payload; - uint16_t messageType = ELYSIUM_MESSAGE_TYPE_ALERT; - uint16_t messageVer = 65535; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder16(alertType); - elysium::swapByteOrder32(expiryValue); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, alertType); - PUSH_BACK_BYTES(payload, expiryValue); - payload.insert(payload.end(), alertMessage.begin(), alertMessage.end()); - payload.push_back('\0'); - - return payload; -} - -std::vector CreatePayload_CreateDenomination(uint32_t propertyId, uint64_t value) -{ - std::vector payload; - - uint16_t messageType = ELYSIUM_TYPE_CREATE_DENOMINATION; - uint16_t messageVer = 0; - - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - elysium::swapByteOrder32(propertyId); - elysium::swapByteOrder64(value); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, value); - - return payload; -} - -std::vector CreatePayload_SimpleMint( - uint32_t propertyId, const std::vector>& mints) -{ - std::vector payload; - uint16_t messageVer = 0; - uint16_t messageType = ELYSIUM_TYPE_SIMPLE_MINT; - elysium::swapByteOrder(messageVer); - elysium::swapByteOrder(messageType); - elysium::swapByteOrder(propertyId); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - - if (mints.size() > ELYSIUM_MAX_SIMPLE_MINTS) { - throw std::invalid_argument("amount of mints exceeded limit"); - } - - if (mints.size() == 0) { - throw std::invalid_argument("no mints provided"); - } - - auto mintAmount = static_cast(mints.size()); - PUSH_BACK_BYTES(payload, mintAmount); - - CDataStream serialized(SER_NETWORK, CLIENT_VERSION); - for (auto const &mint : mints) { - serialized << mint; - } - payload.insert(payload.end(), serialized.begin(), serialized.end()); - - return payload; -} - -// V0 -std::vector CreatePayload_SimpleSpend( - uint32_t propertyId, uint8_t denomination, uint32_t group, - uint16_t groupSize, elysium::SigmaProof const &proof, - secp_primitives::Scalar const &serial) -{ - std::vector payload; - uint16_t messageVer = 0; - uint16_t messageType = ELYSIUM_TYPE_SIMPLE_SPEND; - elysium::swapByteOrder(messageVer); - elysium::swapByteOrder(messageType); - elysium::swapByteOrder(propertyId); - elysium::swapByteOrder(group); - elysium::swapByteOrder(groupSize); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, denomination); - PUSH_BACK_BYTES(payload, group); - PUSH_BACK_BYTES(payload, groupSize); - - CDataStream serialized(SER_NETWORK, PROTOCOL_VERSION); - serialized << serial; - serialized << proof; - payload.insert(payload.end(), serialized.begin(), serialized.end()); - - return payload; -} - -// V1 -std::vector CreatePayload_SimpleSpend( - uint32_t propertyId, uint8_t denomination, uint32_t group, - uint16_t groupSize, elysium::SigmaProof const &proof, - ECDSASignature const &signature, CPubKey const &pubkey) -{ - if (pubkey.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE) { - throw std::invalid_argument("Publickey size is invalid"); - } - - std::vector payload; - uint16_t messageVer = 1; - uint16_t messageType = ELYSIUM_TYPE_SIMPLE_SPEND; - elysium::swapByteOrder(messageVer); - elysium::swapByteOrder(messageType); - elysium::swapByteOrder(propertyId); - elysium::swapByteOrder(group); - elysium::swapByteOrder(groupSize); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - PUSH_BACK_BYTES(payload, propertyId); - PUSH_BACK_BYTES(payload, denomination); - PUSH_BACK_BYTES(payload, group); - PUSH_BACK_BYTES(payload, groupSize); - - CDataStream serialized(SER_NETWORK, PROTOCOL_VERSION); - serialized.write(reinterpret_cast(pubkey.begin()), pubkey.size()); - serialized << proof; - serialized << signature; - payload.insert(payload.end(), serialized.begin(), serialized.end()); - - return payload; -} - -#undef PUSH_BACK_BYTES -#undef PUSH_BACK_BYTES_PTR diff --git a/src/elysium/createpayload.h b/src/elysium/createpayload.h deleted file mode 100644 index 1bd70bdf86..0000000000 --- a/src/elysium/createpayload.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef FIRO_ELYSIUM_CREATEPAYLOAD_H -#define FIRO_ELYSIUM_CREATEPAYLOAD_H - -#include "ecdsa_signature.h" -#include "sp.h" -#include "sigma.h" - -#include - -#include -#include - -#include - -using elysium::ECDSASignature; -using elysium::SigmaStatus; - -std::vector CreatePayload_SimpleSend(uint32_t propertyId, uint64_t amount); -std::vector CreatePayload_SimpleMint(uint32_t propertyId, const std::vector>& mints); -std::vector CreatePayload_SimpleSpend(uint32_t propertyId, uint8_t denomination, uint32_t group, - uint16_t groupSize, elysium::SigmaProof const &proof, secp_primitives::Scalar const &serial); -std::vector CreatePayload_SimpleSpend(uint32_t propertyId, uint8_t denomination, uint32_t group, - uint16_t groupSize, elysium::SigmaProof const &proof, - ECDSASignature const &signature, CPubKey const &pubkey); -std::vector CreatePayload_SendAll(uint8_t ecosystem); -std::vector CreatePayload_DExSell(uint32_t propertyId, uint64_t amountForSale, uint64_t amountDesired, uint8_t timeLimit, uint64_t minFee, uint8_t subAction); -std::vector CreatePayload_DExAccept(uint32_t propertyId, uint64_t amount); -std::vector CreatePayload_SendToOwners(uint32_t propertyId, uint64_t amount, uint32_t distributionProperty); -std::vector CreatePayload_IssuanceFixed(uint8_t ecosystem, uint16_t propertyType, uint32_t previousPropertyId, std::string category, - std::string subcategory, std::string name, std::string url, std::string data, uint64_t amount, - boost::optional sigmaStatus = boost::none); -std::vector CreatePayload_IssuanceVariable(uint8_t ecosystem, uint16_t propertyType, uint32_t previousPropertyId, std::string category, - std::string subcategory, std::string name, std::string url, std::string data, uint32_t propertyIdDesired, - uint64_t amountPerUnit, uint64_t deadline, uint8_t earlyBonus, uint8_t issuerPercentage); -std::vector CreatePayload_IssuanceManaged(uint8_t ecosystem, uint16_t propertyType, uint32_t previousPropertyId, std::string category, - std::string subcategory, std::string name, std::string url, std::string data, - boost::optional sigmaStatus = boost::none); -std::vector CreatePayload_CloseCrowdsale(uint32_t propertyId); -std::vector CreatePayload_Grant(uint32_t propertyId, uint64_t amount, std::string memo); -std::vector CreatePayload_Revoke(uint32_t propertyId, uint64_t amount, std::string memo); -std::vector CreatePayload_ChangeIssuer(uint32_t propertyId); -std::vector CreatePayload_EnableFreezing(uint32_t propertyId); -std::vector CreatePayload_DisableFreezing(uint32_t propertyId); -std::vector CreatePayload_FreezeTokens(uint32_t propertyId, uint64_t amount, const std::string& address); -std::vector CreatePayload_UnfreezeTokens(uint32_t propertyId, uint64_t amount, const std::string& address); -std::vector CreatePayload_MetaDExTrade(uint32_t propertyIdForSale, uint64_t amountForSale, uint32_t propertyIdDesired, uint64_t amountDesired); -std::vector CreatePayload_MetaDExCancelPrice(uint32_t propertyIdForSale, uint64_t amountForSale, uint32_t propertyIdDesired, uint64_t amountDesired); -std::vector CreatePayload_MetaDExCancelPair(uint32_t propertyIdForSale, uint32_t propertyIdDesired); -std::vector CreatePayload_MetaDExCancelEcosystem(uint8_t ecosystem); -std::vector CreatePayload_ElysiumAlert(uint16_t alertType, uint32_t expiryValue, const std::string& alertMessage); -std::vector CreatePayload_DeactivateFeature(uint16_t featureId); -std::vector CreatePayload_ActivateFeature(uint16_t featureId, uint32_t activationBlock, uint32_t minClientVersion); -std::vector CreatePayload_CreateDenomination(uint32_t propertyId, uint64_t value); - -#endif // FIRO_ELYSIUM_CREATEPAYLOAD_H diff --git a/src/elysium/createtx.cpp b/src/elysium/createtx.cpp deleted file mode 100644 index 3d69e03c8e..0000000000 --- a/src/elysium/createtx.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "createtx.h" - -#include "packetencoder.h" -#include "script.h" - -#include "../base58.h" -#include "../coins.h" -#include "../pubkey.h" -#include "../uint256.h" - -#include "../primitives/transaction.h" - -#include "../script/script.h" -#include "../script/standard.h" - -#include -#include -#include - -#include - -/** Creates a new previous output entry. */ -PrevTxsEntry::PrevTxsEntry(const uint256& txid, uint32_t nOut, int64_t nValue, const CScript& scriptPubKey) - : outPoint(txid, nOut), txOut(nValue, scriptPubKey) -{ -} - -/** Creates a new transaction builder. */ -TxBuilder::TxBuilder() -{ -} - -/** Creates a new transaction builder to extend a transaction. */ -TxBuilder::TxBuilder(const CMutableTransaction& transactionIn) - : transaction(transactionIn) -{ -} - -/** Adds an outpoint as input to the transaction. */ -TxBuilder& TxBuilder::addInput(const COutPoint& outPoint) -{ - CTxIn txIn(outPoint); - transaction.vin.push_back(txIn); - - return *this; -} - -/** Adds a transaction input to the transaction. */ -TxBuilder& TxBuilder::addInput(const uint256& txid, uint32_t nOut) -{ - COutPoint outPoint(txid, nOut); - - return addInput(outPoint); -} - -/** Adds an output to the transaction. */ -TxBuilder& TxBuilder::addOutput(const CScript& scriptPubKey, int64_t value) -{ - CTxOut txOutput(value, scriptPubKey); - transaction.vout.push_back(txOutput); - - return *this; -} - -/** Adds a collection of outputs to the transaction. */ -TxBuilder& TxBuilder::addOutputs(const std::vector >& txOutputs) -{ - for (std::vector >::const_iterator it = txOutputs.begin(); - it != txOutputs.end(); ++it) { - addOutput(it->first, it->second); - } - - return *this; -} - -/** Adds an output for change. */ -TxBuilder& TxBuilder::addChange(const CTxDestination& destination, const CCoinsViewCache& view, int64_t txFee, uint32_t position) -{ - CTransaction tx(transaction); - - if (!view.HaveInputs(tx)) { - return *this; - } - - CScript scriptPubKey = GetScriptForDestination(destination); - - int64_t txChange = view.GetValueIn(tx) - tx.GetValueOut() - txFee; - int64_t minValue = GetDustThreshold(scriptPubKey); - - if (txChange < minValue) { - return *this; - } - - std::vector::iterator it = transaction.vout.end(); - if (position < transaction.vout.size()) { - it = transaction.vout.begin() + position; - } - - CTxOut txOutput(txChange, scriptPubKey); - transaction.vout.insert(it, txOutput); - - return *this; -} - -/** Returns the created transaction. */ -CMutableTransaction TxBuilder::build() -{ - return transaction; -} - -/** Creates a new Elysium transaction builder. */ -ElysiumTxBuilder::ElysiumTxBuilder() - : TxBuilder() -{ -} - -/** Creates a new Elysium transaction builder to extend a transaction. */ -ElysiumTxBuilder::ElysiumTxBuilder(const CMutableTransaction& transactionIn) - : TxBuilder(transactionIn) -{ -} - -/** Adds a collection of previous outputs as inputs to the transaction. */ -ElysiumTxBuilder& ElysiumTxBuilder::addInputs(const std::vector& prevTxs) -{ - for (std::vector::const_iterator it = prevTxs.begin(); - it != prevTxs.end(); ++it) { - addInput(it->outPoint); - } - - return *this; -} - -/** Adds an output for the reference address. */ -ElysiumTxBuilder& ElysiumTxBuilder::addReference(const std::string& destination, int64_t value) -{ - CBitcoinAddress addr(destination); - CScript scriptPubKey = GetScriptForDestination(addr.Get()); - - int64_t minValue = GetDustThreshold(scriptPubKey); - value = std::max(minValue, value); - - return (ElysiumTxBuilder&) TxBuilder::addOutput(scriptPubKey, value); -} - -/** Embeds a payload with class C (op-return) encoding. */ -ElysiumTxBuilder& ElysiumTxBuilder::addOpReturn(const std::vector& data) -{ - transaction.vout.push_back(elysium::EncodeClassC(data.begin(), data.end())); - return *this; -} - -/** Embeds a payload with class B (bare-multisig) encoding. */ -ElysiumTxBuilder& ElysiumTxBuilder::addMultisig(const std::vector& data, const std::string& seed, const CPubKey& pubKey) -{ - elysium::EncodeClassB(seed, pubKey, data.begin(), data.end(), std::back_inserter(transaction.vout)); - return *this; -} - -/** Adds an output for change. */ -ElysiumTxBuilder& ElysiumTxBuilder::addChange(const std::string& destination, const CCoinsViewCache& view, int64_t txFee, uint32_t position) -{ - CBitcoinAddress addr(destination); - - return (ElysiumTxBuilder&) TxBuilder::addChange(addr.Get(), view, txFee, position); -} - -/** Adds previous transaction outputs to coins view. */ -void InputsToView(const std::vector& prevTxs, CCoinsViewCache& view) -{ - for (std::vector::const_iterator it = prevTxs.begin(); it != prevTxs.end(); ++it) { - ModifyCoin(view, it->outPoint, - [it](Coin & coin){ - coin.out.scriptPubKey = it->txOut.scriptPubKey; - coin.out.nValue = it->txOut.nValue; - }); - } -} diff --git a/src/elysium/createtx.h b/src/elysium/createtx.h deleted file mode 100644 index 9379742a4e..0000000000 --- a/src/elysium/createtx.h +++ /dev/null @@ -1,228 +0,0 @@ -#ifndef ELYSIUM_CREATETX_H -#define ELYSIUM_CREATETX_H - -class CCoinsViewCache; -class CMutableTransaction; -class COutPoint; -class CPubKey; -class CScript; -class CTxOut; -class uint256; - -#include "script/standard.h" - -#include -#include -#include -#include - -/** - * A structure representing previous transaction outputs. - */ -struct PrevTxsEntry -{ - /** Creates a new previous output entry. */ - PrevTxsEntry(const uint256& txid, uint32_t nOut, int64_t nValue, const CScript& scriptPubKey); - - COutPoint outPoint; - CTxOut txOut; -}; - -// TODO: -// CMutableTransaction tx = ElysiumTxBuilder().addInput(input).addOpReturn(data).build(); -// ... currently doesn't work, because addInput() returns a reference to a TxBuilder, -// but not to an ElysiumTxBuilder. - -/** - * Builder to create transactions. - * - * The TxBuilder class can be used to build transactions by adding outputs to a - * newly created, or an already existing, transaction. The builder can also be - * used to add change outputs. - * - * Example usage: - * - * @code - * // build a transaction with two outputs and change: - * CMutableTransaction tx = TxBuilder() - * .addInput(outPoint) - * .addOutput(scriptPubKeyA, nValueA) - * .addOutput(scriptPubKeyB, nValueB) - * .addChange(destinationForChange, viewContainingInputs, nFee) - * .build(); - * @endcode - */ -class TxBuilder -{ -public: - /** - * Creates a new transaction builder. - */ - TxBuilder(); - - /** - * Creates a new transaction builder to extend a transaction. - * - * @param transactionIn The transaction used to build upon - */ - TxBuilder(const CMutableTransaction& transactionIn); - - /** - * Adds an outpoint as input to the transaction. - * - * @param outPoint The transaction outpoint to add - */ - TxBuilder& addInput(const COutPoint& outPoint); - - /** - * Adds a transaction input to the transaction. - * - * @param txid The hash of the input transaction - * @param nOut The index of the transaction output used as input - */ - TxBuilder& addInput(const uint256& txid, uint32_t nOut); - - /** - * Adds an output to the transaction. - * - * @param scriptPubKey The output script - * @param value The output value - */ - TxBuilder& addOutput(const CScript& scriptPubKey, int64_t value); - - /** - * Adds a collection of outputs to the transaction. - * - * @param txOutputs The outputs to add - */ - TxBuilder& addOutputs(const std::vector >& txOutputs); - - /** - * Adds an output for change. - * - * Optionally a position can be provided, where the change output should be - * inserted, starting with 0. If the number of outputs is smaller than the - * position, then the change output is added to the end. - * - * If the change amount would be considered as dust, then no change output - * is added. - * - * @param destination The destination of the change - * @param view The coins view, which contains the inputs being spent - * @param txFee The desired transaction fees - * @param position The position of the change output (default: last position) - */ - TxBuilder& addChange(const CTxDestination& destination, const CCoinsViewCache& view, int64_t txFee, uint32_t position = 999999); - - /** - * Returns the created transaction. - * - * @return The created transaction - */ - CMutableTransaction build(); - -protected: - CMutableTransaction transaction; -}; - -/** - * Builder to create Elysium transactions. - * - * The ElysiumTxBuilder class is an extension of the TxBuilder, with additional - * methods to build Elysium transactions. Payloads can be embedded with class B - * (bare-multisig) or class C (op-return) encoding. - * - * The output values are based on the dust threshold, but may optionally be - * higher for reference outputs. - * - * Example usage: - * - * @code - * // add a bare-multisig encoded payload to an existing transaction: - * CMutableTransaction modifiedTx = ElysiumTxBuilder(basisTx) - * .addMultisig(payload, obfuscationSeed, redeemingPubKey) - * .build(); - * @endcode - */ -class ElysiumTxBuilder: public TxBuilder -{ -public: - /** - * Creates a new Elysium transaction builder. - */ - ElysiumTxBuilder(); - - /** - * Creates a new Elysium transaction builder to extend a transaction. - * - * @param transactionIn The transaction used to build upon - */ - ElysiumTxBuilder(const CMutableTransaction& transactionIn); - - /** - * Adds a collection of previous outputs as inputs to the transaction. - * - * @param outPoint The transaction outpoint to add - */ - ElysiumTxBuilder& addInputs(const std::vector& prevTxs); - - /** - * Adds an output for the reference address. - * - * The output value is set to at least the dust threshold. - * - * @param destination The reference address - * @param value The optional reference amount - */ - ElysiumTxBuilder& addReference(const std::string& destination, int64_t value = 0); - - /** - * Embeds a payload with class C (op-return) encoding. - * - * If the data encoding fails, then the transaction is not modified. - * - * @param data The payload to embed - */ - ElysiumTxBuilder& addOpReturn(const std::vector& data); - - /** - * Embeds a payload with class B (bare-multisig) encoding. - * - * If the data encoding fails, then the transaction is not modified. - * - * @param data The payload to embed - * @param seed The address of the sender, used as seed for obfuscation - * @param pubKey A public key that may be used to redeem the multisig dust - */ - ElysiumTxBuilder& addMultisig(const std::vector& data, const std::string& seed, const CPubKey& pubKey); - - /** - * Adds an output for change. - * - * Optionally a position can be provided, where the change output should be - * inserted, starting with 0. If the number of outputs is smaller than the - * position, then the change output is added to the end. - * - * If no position is specified, then the change output is added to the first - * position. This default behavior differs from the TxBuilder class. - * - * If the change amount would be considered as dust, then no change output is added. - * - * @param destination The destination of the change - * @param view The coins view, which contains the inputs being spent - * @param txFee The desired transaction fees - * @param position The position of the change output (default: first position) - */ - ElysiumTxBuilder& addChange(const std::string& destination, const CCoinsViewCache& view, int64_t txFee, uint32_t position = 0); -}; - -/** - * Adds previous transaction outputs to coins view. - * - * @param prevTxs The previous transaction outputs - * @param view The coins view to modify - */ -void InputsToView(const std::vector& prevTxs, CCoinsViewCache& view); - - -#endif // ELYSIUM_CREATETX_H diff --git a/src/elysium/dex.cpp b/src/elysium/dex.cpp deleted file mode 100644 index 8542bd1791..0000000000 --- a/src/elysium/dex.cpp +++ /dev/null @@ -1,575 +0,0 @@ -/** - * @file dex.cpp - * - * This file contains DEx logic. - */ - -#include "elysium/dex.h" - -#include "elysium/convert.h" -#include "elysium/errors.h" -#include "elysium/log.h" -#include "elysium/elysium.h" -#include "elysium/rules.h" -#include "elysium/uint256_extensions.h" - -#include "arith_uint256.h" -#include "validation.h" -#include "tinyformat.h" -#include "uint256.h" - -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include - -namespace elysium -{ -/** - * Checks, if such a sell offer exists. - */ -bool DEx_offerExists(const std::string& addressSeller, uint32_t propertyId) -{ - std::string key = STR_SELLOFFER_ADDR_PROP_COMBO(addressSeller, propertyId); - - return !(my_offers.find(key) == my_offers.end()); -} - -/** - * Retrieves a sell offer. - * - * @return The sell offer, or NULL, if no match was found - */ -CMPOffer* DEx_getOffer(const std::string& addressSeller, uint32_t propertyId) -{ - if (elysium_debug_dex) PrintToLog("%s(%s, %d)\n", __func__, addressSeller, propertyId); - - std::string key = STR_SELLOFFER_ADDR_PROP_COMBO(addressSeller, propertyId); - OfferMap::iterator it = my_offers.find(key); - - if (it != my_offers.end()) return &(it->second); - - return NULL; -} - -/** - * Checks, if such an accept order exists. - */ -bool DEx_acceptExists(const std::string& addressSeller, uint32_t propertyId, const std::string& addressBuyer) -{ - std::string key = STR_ACCEPT_ADDR_PROP_ADDR_COMBO(addressSeller, addressBuyer, propertyId); - - return !(my_accepts.find(key) == my_accepts.end()); -} - -/** - * Retrieves an accept order. - * - * @return The accept order, or NULL, if no match was found - */ -CMPAccept* DEx_getAccept(const std::string& addressSeller, uint32_t propertyId, const std::string& addressBuyer) -{ - if (elysium_debug_dex) PrintToLog("%s(%s, %d, %s)\n", __func__, addressSeller, propertyId, addressBuyer); - - std::string key = STR_ACCEPT_ADDR_PROP_ADDR_COMBO(addressSeller, addressBuyer, propertyId); - AcceptMap::iterator it = my_accepts.find(key); - - if (it != my_accepts.end()) return &(it->second); - - return NULL; -} - -namespace legacy -{ -/** - * Legacy calculation of Master Core 0.0.9. - * - * @see: - * https://github.com/mastercoin-MSC/elysium/blob/mscore-0.0.9/src/elysium_dex.cpp#L439-L449 - */ -static int64_t calculateDesiredBTC(const int64_t amountOffered, const int64_t amountDesired, const int64_t amountAvailable) -{ - uint64_t nValue = static_cast(amountOffered); - uint64_t amount_des = static_cast(amountDesired); - uint64_t balanceReallyAvailable = static_cast(amountAvailable); - - double BTC; - - BTC = amount_des * balanceReallyAvailable; - BTC /= (double) nValue; - amount_des = rounduint64(BTC); - - return static_cast(amount_des); -} -} - -/** - * Determines the amount of bitcoins desired, in case it needs to be recalculated. - * - * TODO: don't expose it! - * @return The amount of bitcoins desired - */ -int64_t calculateDesiredBTC(const int64_t amountOffered, const int64_t amountDesired, const int64_t amountAvailable) -{ - if (amountOffered == 0) { - return 0; // divide by null protection - } - - arith_uint256 amountOffered256 = ConvertTo256(amountOffered); - arith_uint256 amountDesired256 = ConvertTo256(amountDesired); - arith_uint256 amountAvailable256 = ConvertTo256(amountAvailable); - - amountDesired256 = DivideAndRoundUp((amountDesired256 * amountAvailable256), amountOffered256); - - return ConvertTo64(amountDesired256); -} - -/** - * Creates a new sell offer. - * - * TODO: change nAmended: uint64_t -> int64_t - * @return 0 if everything is OK - */ -int DEx_offerCreate(const std::string& addressSeller, uint32_t propertyId, int64_t amountOffered, int block, int64_t amountDesired, int64_t minAcceptFee, uint8_t paymentWindow, const uint256& txid, uint64_t* nAmended) -{ - int rc = DEX_ERROR_SELLOFFER; - - // sanity checks - // shold not be removed, because it may be used when updating/destroying an offer - if (paymentWindow == 0) { - return (DEX_ERROR_SELLOFFER -101); - } - if (amountDesired == 0) { - return (DEX_ERROR_SELLOFFER -101); - } - if (DEx_getOffer(addressSeller, propertyId)) { - return (DEX_ERROR_SELLOFFER -10); // offer already exists - } - - const std::string key = STR_SELLOFFER_ADDR_PROP_COMBO(addressSeller, propertyId); - if (elysium_debug_dex) PrintToLog("%s(%s|%s), nValue=%d)\n", __func__, addressSeller, key, amountOffered); - - const int64_t balanceReallyAvailable = getMPbalance(addressSeller, propertyId, BALANCE); - - /** - * After this feature is enabled, it is no longer valid to create orders, which offer more than - * the seller has available, and the amounts are no longer adjusted based on the actual balance. - */ - if (IsFeatureActivated(FEATURE_DEXMATH, block)) { - if (amountOffered > balanceReallyAvailable) { - PrintToLog("%s: rejected: sender %s has insufficient balance of property %d [%s < %s]\n", __func__, - addressSeller, propertyId, FormatDivisibleMP(balanceReallyAvailable), FormatDivisibleMP(amountOffered)); - return (DEX_ERROR_SELLOFFER -25); - } - } - - // ------------------------------------------------------------------------- - // legacy:: - - // if offering more than available -- put everything up on sale - if (amountOffered > balanceReallyAvailable) { - PrintToLog("%s: adjusting order: %s offers %s %s, but has only %s %s available\n", __func__, - addressSeller, FormatDivisibleMP(amountOffered), strMPProperty(propertyId), - FormatDivisibleMP(balanceReallyAvailable), strMPProperty(propertyId)); - - // AND we must also re-adjust the BTC desired in this case... - amountDesired = legacy::calculateDesiredBTC(amountOffered, amountDesired, balanceReallyAvailable); - amountOffered = balanceReallyAvailable; - if (nAmended) *nAmended = amountOffered; - - PrintToLog("%s: adjusting order: updated amount for sale: %s %s, offered for: %s BTC\n", __func__, - FormatDivisibleMP(amountOffered), strMPProperty(propertyId), FormatDivisibleMP(amountDesired)); - } - // ------------------------------------------------------------------------- - - if (amountOffered > 0) { - assert(update_tally_map(addressSeller, propertyId, -amountOffered, BALANCE)); - assert(update_tally_map(addressSeller, propertyId, amountOffered, SELLOFFER_RESERVE)); - - CMPOffer sellOffer(block, amountOffered, propertyId, amountDesired, minAcceptFee, paymentWindow, txid); - my_offers.insert(std::make_pair(key, sellOffer)); - - rc = 0; - } - - return rc; -} - -/** - * Destorys a sell offer. - * - * The remaining amount reserved for the offer is returned to the available balance. - * - * @return 0 if the offer was destroyed - */ -int DEx_offerDestroy(const std::string& addressSeller, uint32_t propertyId) -{ - if (!DEx_offerExists(addressSeller, propertyId)) { - return (DEX_ERROR_SELLOFFER -11); // offer does not exist - } - - const int64_t amountReserved = getMPbalance(addressSeller, propertyId, SELLOFFER_RESERVE); - - // return the remaining reserved amount back to the seller - if (amountReserved > 0) { - assert(update_tally_map(addressSeller, propertyId, -amountReserved, SELLOFFER_RESERVE)); - assert(update_tally_map(addressSeller, propertyId, amountReserved, BALANCE)); - } - - // delete the offer - const std::string key = STR_SELLOFFER_ADDR_PROP_COMBO(addressSeller, propertyId); - OfferMap::iterator it = my_offers.find(key); - my_offers.erase(it); - - if (elysium_debug_dex) PrintToLog("%s(%s|%s)\n", __func__, addressSeller, key); - - return 0; -} - -/** - * Updates a sell offer. - * - * The old offer is destroyed, and replaced by the updated offer. - * - * @return 0 if everything is OK - */ -int DEx_offerUpdate(const std::string& addressSeller, uint32_t propertyId, int64_t amountOffered, int block, int64_t amountDesired, int64_t minAcceptFee, uint8_t paymentWindow, const uint256& txid, uint64_t* nAmended) -{ - if (elysium_debug_dex) PrintToLog("%s(%s, %d)\n", __func__, addressSeller, propertyId); - - if (!DEx_offerExists(addressSeller, propertyId)) { - return (DEX_ERROR_SELLOFFER -12); // offer does not exist - } - - int rc = DEx_offerDestroy(addressSeller, propertyId); - - if (rc == 0) { - // if the old offer was destroyed successfully, try to create a new one - rc = DEx_offerCreate(addressSeller, propertyId, amountOffered, block, amountDesired, minAcceptFee, paymentWindow, txid, nAmended); - } - - return rc; -} - -/** - * Creates a new accept order. - * - * TODO: change nAmended: uint64_t -> int64_t - * @return 0 if everything is OK - */ -int DEx_acceptCreate(const std::string& addressBuyer, const std::string& addressSeller, uint32_t propertyId, int64_t amountAccepted, int block, int64_t feePaid, uint64_t* nAmended) -{ - int rc = DEX_ERROR_ACCEPT -10; - const std::string keySellOffer = STR_SELLOFFER_ADDR_PROP_COMBO(addressSeller, propertyId); - const std::string keyAcceptOrder = STR_ACCEPT_ADDR_PROP_ADDR_COMBO(addressSeller, addressBuyer, propertyId); - - OfferMap::const_iterator my_it = my_offers.find(keySellOffer); - - if (my_it == my_offers.end()) { - PrintToLog("%s: rejected: no matching sell offer for accept order found\n", __func__); - return (DEX_ERROR_ACCEPT -15); - } - - const CMPOffer& offer = my_it->second; - - PrintToLog("%s: found a matching sell offer [seller: %s, buyer: %s, property: %d)\n", __func__, - addressSeller, addressBuyer, propertyId); - - // the older accept is the valid one: do not accept any new ones! - if (DEx_acceptExists(addressSeller, propertyId, addressBuyer)) { - PrintToLog("%s: rejected: an accept order from this same seller for this same offer already exists\n", __func__); - return DEX_ERROR_ACCEPT -205; - } - - // ensure the correct BTC fee was paid in this acceptance message - if (feePaid < offer.getMinFee()) { - PrintToLog("%s: rejected: transaction fee too small [%d < %d]\n", __func__, feePaid, offer.getMinFee()); - return DEX_ERROR_ACCEPT -105; - } - - int64_t amountReserved = 0; - int64_t amountRemainingForSale = getMPbalance(addressSeller, propertyId, SELLOFFER_RESERVE); - - // ensure the buyer only can reserve the amount that is still available - if (amountRemainingForSale >= amountAccepted) { - amountReserved = amountAccepted; - } else { - amountReserved = amountRemainingForSale; - PrintToLog("%s: buyer wants to reserve %d tokens, but only %d tokens are available\n", __func__, amountAccepted, amountRemainingForSale); - } - - if (amountReserved > 0) { - assert(update_tally_map(addressSeller, propertyId, -amountReserved, SELLOFFER_RESERVE)); - assert(update_tally_map(addressSeller, propertyId, amountReserved, ACCEPT_RESERVE)); - - CMPAccept acceptOffer(amountReserved, block, offer.getBlockTimeLimit(), offer.getProperty(), offer.getOfferAmountOriginal(), offer.getXZCDesiredOriginal(), offer.getHash()); - my_accepts.insert(std::make_pair(keyAcceptOrder, acceptOffer)); - - rc = 0; - } - - if (nAmended) *nAmended = amountReserved; - - return rc; -} - -/** - * Finalizes an accepted offer. - * - * This function is called by handler_block() for each accepted offer that has - * expired. This function is also called when the purchase has been completed, - * and the buyer bought everything that was reserved. - * - * @return 0 if everything is OK - */ -int DEx_acceptDestroy(const std::string& addressBuyer, const std::string& addressSeller, uint32_t propertyid, bool fForceErase) -{ - int rc = DEX_ERROR_ACCEPT -20; - CMPOffer* p_offer = DEx_getOffer(addressSeller, propertyid); - CMPAccept* p_accept = DEx_getAccept(addressSeller, propertyid, addressBuyer); - bool fReturnToMoney = true; - - if (!p_accept) return rc; // sanity check - - // if the offer is gone, ACCEPT_RESERVE should go back to seller's BALANCE - // otherwise move the previously accepted amount back to SELLOFFER_RESERVE - if (!p_offer) { - fReturnToMoney = true; - } else { - PrintToLog("%s: finalize trade [offer=%s, accept=%s]\n", __func__, - p_offer->getHash().GetHex(), p_accept->getHash().GetHex()); - - // offer exists, determine whether it's the original offer or some random new one - if (p_offer->getHash() == p_accept->getHash()) { - // same offer, return to SELLOFFER_RESERVE - fReturnToMoney = false; - } else { - // old offer is gone ! - fReturnToMoney = true; - } - } - - const int64_t amountRemaining = p_accept->getAcceptAmountRemaining(); - - if (amountRemaining > 0) { - if (fReturnToMoney) { - assert(update_tally_map(addressSeller, propertyid, -amountRemaining, ACCEPT_RESERVE)); - assert(update_tally_map(addressSeller, propertyid, amountRemaining, BALANCE)); - } else { - assert(update_tally_map(addressSeller, propertyid, -amountRemaining, ACCEPT_RESERVE)); - assert(update_tally_map(addressSeller, propertyid, amountRemaining, SELLOFFER_RESERVE)); - } - } - - // can only erase when is NOT called from an iterator loop - if (fForceErase) { - std::string key = STR_ACCEPT_ADDR_PROP_ADDR_COMBO(addressSeller, addressBuyer, propertyid); - AcceptMap::iterator it = my_accepts.find(key); - - if (my_accepts.end() != it) { - my_accepts.erase(it); - } - } - - rc = 0; - return rc; -} - -namespace legacy -{ -/** - * Legacy calculation of Master Core 0.0.9. - * - * @see: - * https://github.com/mastercoin-MSC/elysium/blob/mscore-0.0.9/src/elysium_dex.cpp#L660-L668 - */ -static int64_t calculateDExPurchase(const int64_t amountOffered, const int64_t amountDesired, const int64_t amountPaid) -{ - uint64_t acceptOfferAmount = static_cast(amountOffered); - uint64_t acceptBTCDesired = static_cast(amountDesired); - uint64_t XZC_paid = static_cast(amountPaid); - - const double XZC_desired_original = acceptBTCDesired; - const double offer_amount_original = acceptOfferAmount; - - double perc_X = (double) XZC_paid / XZC_desired_original; - double Purchased = offer_amount_original * perc_X; - - uint64_t units_purchased = rounduint64(Purchased); - - return static_cast(units_purchased); -} -} - -/** - * Determines the purchased amount of tokens. - * - * The amount is rounded up, which may be in favor of the buyer, to avoid small - * leftovers of 1 willet. This is not exploitable due to transaction fees. - * - * The desired amount must not be zero, and the purchased amount should be checked - * against the actual amount that is still left for sale. - * - * @return The amount of tokens purchased - */ -int64_t calculateDExPurchase(const int64_t amountOffered, const int64_t amountDesired, const int64_t amountPaid) -{ - // conversion - arith_uint256 amountOffered256 = ConvertTo256(amountOffered); - arith_uint256 amountDesired256 = ConvertTo256(amountDesired); - arith_uint256 amountPaid256 = ConvertTo256(amountPaid); - - // actual calculation; round up - arith_uint256 amountPurchased256 = DivideAndRoundUp((amountPaid256 * amountOffered256), amountDesired256); - - // convert back to int64_t - return ConvertTo64(amountPurchased256); -} - -/** - * Handles incoming BTC payment for the offer. - * TODO: change nAmended: uint64_t -> int64_t - */ -int DEx_payment(const uint256& txid, unsigned int vout, const std::string& addressSeller, const std::string& addressBuyer, int64_t amountPaid, int block, uint64_t* nAmended) -{ - if (elysium_debug_dex) PrintToLog("%s(%s, %s)\n", __func__, addressSeller, addressBuyer); - - int rc = DEX_ERROR_PAYMENT; - - uint32_t propertyId = ELYSIUM_PROPERTY_ELYSIUM; // test for ELYSIUM accept first - CMPAccept* p_accept = DEx_getAccept(addressSeller, propertyId, addressBuyer); - - if (!p_accept) { - propertyId = ELYSIUM_PROPERTY_TELYSIUM; // test for TELYSIUM accept second - p_accept = DEx_getAccept(addressSeller, propertyId, addressBuyer); - } - - if (!p_accept) { - // there must be an active accept order for this payment - return (DEX_ERROR_PAYMENT -1); - } - - // ------------------------------------------------------------------------- - - const int64_t amountDesired = p_accept->getXZCDesiredOriginal(); - const int64_t amountOffered = p_accept->getOfferAmountOriginal(); - - // divide by 0 protection - if (0 == amountDesired) { - if (elysium_debug_dex) PrintToLog("%s: ERROR: desired amount of accept order is zero", __func__); - - return (DEX_ERROR_PAYMENT -2); - } - - int64_t amountPurchased = 0; - - /** - * As long as this feature is disabled, floating point math is used to - * determine the purchased amount. - * - * After this feature is enabled, plain integer math is used to determine - * the purchased amount. The purchased amount is rounded up, which may be - * in favor of the buyer, to avoid small leftovers of 1 willet. - * - * This is not exploitable due to transaction fees. - */ - if (IsFeatureActivated(FEATURE_DEXMATH, block)) { - amountPurchased = calculateDExPurchase(amountOffered, amountDesired, amountPaid); - } else { - // Fallback to original calculation: - amountPurchased = legacy::calculateDExPurchase(amountOffered, amountDesired, amountPaid); - } - - // ------------------------------------------------------------------------- - - const int64_t amountRemaining = p_accept->getAcceptAmountRemaining(); // actual amount desired, in the Accept - - if (elysium_debug_dex) PrintToLog( - "%s: BTC desired: %s, offered amount: %s, amount to purchase: %s, amount remaining: %s\n", __func__, - FormatDivisibleMP(amountDesired), FormatDivisibleMP(amountOffered), - FormatDivisibleMP(amountPurchased), FormatDivisibleMP(amountRemaining)); - - // if units_purchased is greater than what's in the Accept, the buyer gets only what's in the Accept - if (amountRemaining < amountPurchased) { - amountPurchased = amountRemaining; - - if (nAmended) *nAmended = amountPurchased; - } - - if (amountPurchased > 0) { - PrintToLog("%s: seller %s offered %s %s for %s BTC\n", __func__, - addressSeller, FormatDivisibleMP(amountOffered), strMPProperty(propertyId), FormatDivisibleMP(amountDesired)); - PrintToLog("%s: buyer %s pays %s BTC to purchase %s %s\n", __func__, - addressBuyer, FormatDivisibleMP(amountPaid), FormatDivisibleMP(amountPurchased), strMPProperty(propertyId)); - - assert(update_tally_map(addressSeller, propertyId, -amountPurchased, ACCEPT_RESERVE)); - assert(update_tally_map(addressBuyer, propertyId, amountPurchased, BALANCE)); - - bool valid = true; - p_txlistdb->recordPaymentTX(txid, valid, block, vout, propertyId, amountPurchased, addressBuyer, addressSeller); - - rc = 0; - PrintToLog("#######################################################\n"); - } - - // reduce the amount of units still desired by the buyer and if 0 destroy the Accept order - if (p_accept->reduceAcceptAmountRemaining_andIsZero(amountPurchased)) { - const int64_t reserveSell = getMPbalance(addressSeller, propertyId, SELLOFFER_RESERVE); - const int64_t reserveAccept = getMPbalance(addressSeller, propertyId, ACCEPT_RESERVE); - - DEx_acceptDestroy(addressBuyer, addressSeller, propertyId, true); - - // delete the Offer object if there is nothing in its Reserves -- everything got puchased and paid for - if ((0 == reserveSell) && (0 == reserveAccept)) { - DEx_offerDestroy(addressSeller, propertyId); - } - } - - return rc; -} - -unsigned int eraseExpiredAccepts(int blockNow) -{ - unsigned int how_many_erased = 0; - AcceptMap::iterator it = my_accepts.begin(); - - while (my_accepts.end() != it) { - const CMPAccept& acceptOrder = it->second; - - int blocksSinceAccept = blockNow - acceptOrder.getAcceptBlock(); - int blocksPaymentWindow = static_cast(acceptOrder.getBlockTimeLimit()); - - if (blocksSinceAccept >= blocksPaymentWindow) { - PrintToLog("%s: sell offer: %s\n", __func__, acceptOrder.getHash().GetHex()); - PrintToLog("%s: erasing at block: %d, order confirmed at block: %d, payment window: %d\n", - __func__, blockNow, acceptOrder.getAcceptBlock(), acceptOrder.getBlockTimeLimit()); - - // extract the seller, buyer and property from the key - std::vector vstr; - boost::split(vstr, it->first, boost::is_any_of("-+"), boost::token_compress_on); - std::string addressSeller = vstr[0]; - uint32_t propertyId = atoi(vstr[1]); - std::string addressBuyer = vstr[2]; - - DEx_acceptDestroy(addressBuyer, addressSeller, propertyId); - - my_accepts.erase(it++); - - ++how_many_erased; - } else it++; - } - - return how_many_erased; -} - - -} // namespace elysium diff --git a/src/elysium/dex.h b/src/elysium/dex.h deleted file mode 100644 index d9b89339f7..0000000000 --- a/src/elysium/dex.h +++ /dev/null @@ -1,246 +0,0 @@ -#ifndef ELYSIUM_DEX_H -#define ELYSIUM_DEX_H - -#include "elysium/log.h" -#include "elysium/elysium.h" -#include "elysium/tx.h" - -#include "amount.h" -#include "tinyformat.h" -#include "uint256.h" - -#include - -#include -#include -#include -#include - -/** Lookup key to find DEx offers. */ -inline std::string STR_SELLOFFER_ADDR_PROP_COMBO(const std::string& address, uint32_t propertyId) -{ - return strprintf("%s-%d", address, propertyId); -} -/** Lookup key to find DEx accepts. */ -inline std::string STR_ACCEPT_ADDR_PROP_ADDR_COMBO(const std::string& seller, const std::string& buyer, uint32_t propertyId) -{ - return strprintf("%s-%d+%s", seller, propertyId, buyer); -} -/** Lookup key to find DEx payments. */ -inline std::string STR_PAYMENT_SUBKEY_TXID_PAYMENT_COMBO(const std::string& txidStr, unsigned int paymentNumber) -{ - return strprintf("%s-%d", txidStr, paymentNumber); -} -/** Lookup key to find MetaDEx sub-records. TODO: not here! */ -inline std::string STR_REF_SUBKEY_TXID_REF_COMBO(const std::string& txidStr, unsigned int refNumber) -{ - return strprintf("%s%d", txidStr, refNumber); -} - -/** A single outstanding offer, from one seller of one property. - * - * There many be more than one accepted offers. - */ -class CMPOffer -{ -private: - int offerBlock; - //! amount of ELYSIUM for sale specified when the offer was placed - int64_t offer_amount_original; - uint32_t property; - //! amount desired, in FIRO - int64_t XZC_desired_original; - int64_t min_fee; - uint8_t blocktimelimit; - uint256 txid; - uint8_t subaction; - -public: - uint256 getHash() const { return txid; } - uint32_t getProperty() const { return property; } - int64_t getMinFee() const { return min_fee ; } - uint8_t getBlockTimeLimit() const { return blocktimelimit; } - uint8_t getSubaction() const { return subaction; } - - int64_t getOfferAmountOriginal() const { return offer_amount_original; } - int64_t getXZCDesiredOriginal() const { return XZC_desired_original; } - - CMPOffer() - : offerBlock(0), offer_amount_original(0), property(0), XZC_desired_original(0), min_fee(0), - blocktimelimit(0), subaction(0) - { - } - - CMPOffer(int block, int64_t amountOffered, uint32_t propertyId, int64_t amountDesired, - int64_t minAcceptFee, uint8_t paymentWindow, const uint256& tx) - : offerBlock(block), offer_amount_original(amountOffered), property(propertyId), - XZC_desired_original(amountDesired), min_fee(minAcceptFee), blocktimelimit(paymentWindow), - txid(tx), subaction(0) - { - if (elysium_debug_dex) PrintToLog("%s(%d): %s\n", __func__, amountOffered, txid.GetHex()); - } - - CMPOffer(const CMPTransaction& tx) - : offerBlock(tx.block), offer_amount_original(tx.nValue), property(tx.property), - XZC_desired_original(tx.amount_desired), min_fee(tx.min_fee), - blocktimelimit(tx.blocktimelimit), subaction(tx.subaction) - { - } - - void saveOffer(std::ofstream& file, SHA256_CTX* shaCtx, const std::string& address) const - { - std::string lineOut = strprintf("%s,%d,%d,%d,%d,%d,%d,%d,%s", - address, - offerBlock, - offer_amount_original, - property, - XZC_desired_original, - (ELYSIUM_PROPERTY_XZC), - min_fee, - blocktimelimit, - txid.ToString() - ); - - // add the line to the hash - SHA256_Update(shaCtx, lineOut.c_str(), lineOut.length()); - - // write the line - file << lineOut << std::endl; - } -}; - -/** Accepted offer on the DEx. - * - * Once the accepted offer is seen on the network, the amount of MSC being purchased is - * taken out of seller's "sell offer"-reserve and put into this buyer's "accept"-reserve. - */ -class CMPAccept -{ -private: - int64_t accept_amount_original; // amount of ELYSIUM/TELYSIUM desired to purchased - int64_t accept_amount_remaining; // amount of ELYSIUM/TELYSIUM remaining to purchased - uint8_t blocktimelimit; // copied from the offer during creation - uint32_t property; // copied from the offer during creation - - int64_t offer_amount_original; // copied from the Offer during Accept's creation - int64_t XZC_desired_original; // copied from the Offer during Accept's creation - - // the original offers TXIDs, needed to match Accept to the Offer during Accept's destruction, etc. - uint256 offer_txid; - int block; - -public: - // TODO: it may not intuitive that this is *not* the hash of the accept order - uint256 getHash() const { return offer_txid; } - - int64_t getOfferAmountOriginal() const { return offer_amount_original; } - int64_t getXZCDesiredOriginal() const { return XZC_desired_original; } - - int64_t getAcceptAmount() const { return accept_amount_original; } - - uint8_t getBlockTimeLimit() const { return blocktimelimit; } - uint32_t getProperty() const { return property; } - - int getAcceptBlock() const { return block; } - - CMPAccept(int64_t amountAccepted, int blockIn, uint8_t paymentWindow, uint32_t propertyId, - int64_t offerAmountOriginal, int64_t amountDesired, const uint256& txid) - : accept_amount_remaining(amountAccepted), blocktimelimit(paymentWindow), - property(propertyId), offer_amount_original(offerAmountOriginal), - XZC_desired_original(amountDesired), offer_txid(txid), block(blockIn) - { - accept_amount_original = accept_amount_remaining; - PrintToLog("%s(%d): %s\n", __func__, amountAccepted, txid.GetHex()); - } - - CMPAccept(int64_t acceptAmountOriginal, int64_t acceptAmountRemaining, int blockIn, - uint8_t paymentWindow, uint32_t propertyId, int64_t offerAmountOriginal, - int64_t amountDesired, const uint256& txid) - : accept_amount_original(acceptAmountOriginal), - accept_amount_remaining(acceptAmountRemaining), blocktimelimit(paymentWindow), - property(propertyId), offer_amount_original(offerAmountOriginal), - XZC_desired_original(amountDesired), offer_txid(txid), block(blockIn) - { - PrintToLog("%s(%d[%d]): %s\n", __func__, acceptAmountRemaining, acceptAmountOriginal, txid.GetHex()); - } - - void print() - { - // TODO: no floating numbers - PrintToLog("buying: %12.8lf (originally= %12.8lf) in block# %d\n", - (double) accept_amount_remaining / (double) COIN, (double) accept_amount_original / (double) COIN, block); - } - - int64_t getAcceptAmountRemaining() const - { - PrintToLog("%s(); buyer still wants = %d\n", __func__, accept_amount_remaining); - - return accept_amount_remaining; - } - - /** - * Reduce the remaining accepted amount. - * - * @param really_purchased The number of units purchased - * @return True if the customer is fully satisfied (nothing desired to be purchased) - */ - bool reduceAcceptAmountRemaining_andIsZero(const int64_t really_purchased) - { - bool bRet = false; - - if (really_purchased >= accept_amount_remaining) bRet = true; - - accept_amount_remaining -= really_purchased; - - return bRet; - } - - void saveAccept(std::ofstream& file, SHA256_CTX* shaCtx, const std::string& address, const std::string& buyer) const - { - std::string lineOut = strprintf("%s,%d,%s,%d,%d,%d,%d,%d,%d,%s", - address, - property, - buyer, - block, - accept_amount_remaining, - accept_amount_original, - blocktimelimit, - offer_amount_original, - XZC_desired_original, - offer_txid.ToString()); - - // add the line to the hash - SHA256_Update(shaCtx, lineOut.c_str(), lineOut.length()); - - // write the line - file << lineOut << std::endl; - } -}; - -namespace elysium -{ -typedef std::map OfferMap; -typedef std::map AcceptMap; - -extern OfferMap my_offers; -extern AcceptMap my_accepts; - -/** Determines the amount of bitcoins desired, in case it needs to be recalculated. TODO: don't expose! */ -int64_t calculateDesiredBTC(const int64_t amountOffered, const int64_t amountDesired, const int64_t amountAvailable); - -bool DEx_offerExists(const std::string& addressSeller, uint32_t propertyId); -CMPOffer* DEx_getOffer(const std::string& addressSeller, uint32_t propertyId); -bool DEx_acceptExists(const std::string& addressSeller, uint32_t propertyId, const std::string& addressBuyer); -CMPAccept* DEx_getAccept(const std::string& addressSeller, uint32_t propertyId, const std::string& addressBuyer); -int DEx_offerCreate(const std::string& addressSeller, uint32_t propertyId, int64_t amountOffered, int block, int64_t amountDesired, int64_t minAcceptFee, uint8_t paymentWindow, const uint256& txid, uint64_t* nAmended = NULL); -int DEx_offerDestroy(const std::string& addressSeller, uint32_t propertyId); -int DEx_offerUpdate(const std::string& addressSeller, uint32_t propertyId, int64_t amountOffered, int block, int64_t amountDesired, int64_t minAcceptFee, uint8_t paymentWindow, const uint256& txid, uint64_t* nAmended = NULL); -int DEx_acceptCreate(const std::string& addressBuyer, const std::string& addressSeller, uint32_t propertyId, int64_t amountAccepted, int block, int64_t feePaid, uint64_t* nAmended = NULL); -int DEx_acceptDestroy(const std::string& addressBuyer, const std::string& addressSeller, uint32_t propertyid, bool fForceErase = false); -int DEx_payment(const uint256& txid, unsigned int vout, const std::string& addressSeller, const std::string& addressBuyer, int64_t amountPaid, int block, uint64_t* nAmended = NULL); - -unsigned int eraseExpiredAccepts(int block); -} // namespace elysium - - -#endif // ELYSIUM_DEX_H diff --git a/src/elysium/doc/configuration.md b/src/elysium/doc/configuration.md deleted file mode 100644 index 6294012531..0000000000 --- a/src/elysium/doc/configuration.md +++ /dev/null @@ -1,88 +0,0 @@ -Configuration -============= - -Omni Core can be configured by providing one or more optional command-line arguments: -```bash -$ omnicored -setting=value -setting=value -``` - -All settings can alternatively also be configured via the `bitcoin.conf`. - -Depending on the operating system, the default locations for the configuration file are: - -- Unix systems: `$HOME/.bitcoin/bitcoin.conf` -- Mac OS X: `$HOME/Library/Application Support/Bitcoin/bitcoin.conf` -- Microsoft Windows: `%APPDATA%/Bitcoin/bitcoin.conf` - -A typical `bitcoin.conf` may include: -``` -server=1 -rpcuser=omnicorerpc -rpcpassword=5hMTZI9iBGFqKxsWfOUF -rpcallowip=127.0.0.1 -rpcport=8332 -txindex=1 -datacarriersize=80 -logtimestamps=1 -omnidebug=tally -omnidebug=packets -omnidebug=pending -``` - -## Optional settings - -To run and use Omni Core, no explicit configuration is necessary. - -More information about the general configuration and Bitcoin Core specific options are available in the [Bitcoin wiki](https://en.bitcoin.it/wiki/Running_Bitcoin). - -#### General options: - -| Name | Type | Default | Description | -|------------------------------|--------------|----------------|---------------------------------------------------------------------------------| -| `startclean` | boolean | `0` | clear all persistence files on startup; triggers reparsing of Omni transactions | -| `omnitxcache` | number | `500000` | the maximum number of transactions in the input transaction cache | -| `omniprogressfrequency` | number | `30` | time in seconds after which the initial scanning progress is reported | -| `omniseedblockfilter` | boolean | `1` | set skipping of blocks without Omni transactions during initial scan | -| `omnishowblockconsensushash` | number | `0` | calculate and log the consensus hash for the specified block | - -#### Log options: - -| Name | Type | Default | Description | -|------------------------------|--------------|----------------|---------------------------------------------------------------------------------| -| `omnilogfile` | string | `omnicore.log` | the path of the log file (in the data directory per default) | -| `omnidebug` | multi string | `""` | enable or disable log categories, can be `"all"`, `"none"` | - -#### Transaction options: - -| Name | Type | Default | Description | -|------------------------------|--------------|----------------|---------------------------------------------------------------------------------| -| `autocommit` | boolean | `1` | enable or disable broadcasting of transactions, when creating transactions | -| `datacarrier` | boolean | `1` | if disabled, payloads are embedded multisig, and not in `OP_RETURN` scripts | -| `datacarriersize` | number | `80` | the maximum size in byte of payloads embedded in `OP_RETURN` scripts | - -**Note:** the options `-datacarrier` and `datacarriersize` affect the global relay policies of transactions with `OP_RETURN` scripts. - -#### RPC server options: - -| Name | Type | Default | Description | -|------------------------------|--------------|----------------|---------------------------------------------------------------------------------| -| `rpcforceutf8` | boolean | `1` | replace invalid UTF-8 encoded characters with question marks in RPC responses | - -#### User interface options: - -| Name | Type | Default | Description | -|------------------------------|--------------|----------------|---------------------------------------------------------------------------------| -| `disclaimer` | boolean | `0` | explicitly show QT disclaimer on startup | -| `omniuiwalletscope` | number | `65535` | max. transactions to show in trade and transaction history | - -#### Alert and activation options: - -| Name | Type | Default | Description | -|------------------------------|--------------|----------------|---------------------------------------------------------------------------------| -| `overrideforcedshutdown` | boolean | `0` | overwrite shutdown, triggered by an alert | -| `omnialertallowsender` | multi string | `""` | whitelist senders of alerts, can be `"any"` | -| `omnialertignoresender` | multi string | `""` | ignore senders of alerts | -| `omniactivationallowsender` | multi string | `""` | whitelist senders of activations | -| `omniactivationignoresender` | multi string | `""` | ignore senders of activations | - -**Note:** alert and activation related options are consensus affecting and should only be used for tests or under exceptional circumstances! diff --git a/src/elysium/doc/release-notes.md b/src/elysium/doc/release-notes.md deleted file mode 100644 index bf4f6175ce..0000000000 --- a/src/elysium/doc/release-notes.md +++ /dev/null @@ -1,98 +0,0 @@ -Omni Core v0.3.0 -=================== - -v0.3.0 includes new logic for the freeze tokens functionality. - -v0.3.0 is a major release and consensus critical in terms of the Omni Layer protocol rules. An upgrade is mandatory, and highly recommended. Prior releases will not be compatible with new behaviour in this release. - -Please report bugs using the issue tracker on GitHub: - - https://github.com/OmniLayer/omnicore/issues - -Table of contents -================= - -- [Omni Core v0.3.0](#omni-core-v030) -- [Upgrading and downgrading](#upgrading-and-downgrading) - - [How to upgrade](#how-to-upgrade) - - [Downgrading](#downgrading) - - [Compatibility with Bitcoin Core](#compatibility-with-bitcoin-core) -- [Consensus affecting changes](#consensus-affecting-changes) - - [Freezing tokens for managed properties](#freezing-tokens-for-managed-properties) -- [Notable changes](#notable-changes) - - [Various bug fixes and improvements](#various-bug-fixes-and-improvements) -- [Change log](#change-log) -- [Credits](#credits) - -Upgrading and downgrading -========================= - -How to upgrade --------------- - -If you are running Bitcoin Core or an older version of Omni Core, shut it down. Wait until it has completely shut down, then copy the new version of `omnicored`, `omnicore-cli` and `omnicore-qt`. On Microsoft Windows the setup routine can be used to automate these steps. - -During the first startup historical Omni transactions are reprocessed and Omni Core will not be usable for approximately 15 minutes up to two hours. The progress of the initial scan is reported on the console, the GUI and written to the `debug.log`. The scan may be interrupted, but can not be resumed, and then needs to start from the beginning. - -Downgrading ------------ - -Downgrading to an Omni Core version prior 0.3.0 is generally not supported as older versions will not provide accurate information due to the changes in consensus rules. - -Compatibility with Bitcoin Core -------------------------------- - -Omni Core is based on Bitcoin Core 0.13.2 and can be used as replacement for Bitcoin Core. Switching between Omni Core and Bitcoin Core is fully supported at any time. - -Downgrading to a Bitcoin Core version prior 0.12 may not be supported due to the obfuscation of the blockchain database. - -Downgrading to a Bitcoin Core version prior 0.10 is not supported due to the new headers-first synchronization. - -Consensus affecting changes -=========================== - -Freezing tokens for managed properties --------------------------------------- - -Omni Core 0.3.0 contains a feature that, if an issuer chooses to enable, permits an issuer of a centrally managed token to freeze tokens residing at any address for that specific property. This feature is restricted to the managed token type (where the issuer retains control over the supply of tokens) and may not be used for any other token type (for example tokens issued via crowdsale or via fixed amount cannot be frozen). - -Further, feature ID 14 adds a waiting period for a managed issuer to enable the freezing feature. Once activated a waiting period (currently 4096 blocks) is enforced between the 'enable freezing' transaction and the 'freeze tokens' transaction. - -See also [JSON-RPC API documentation](https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md). - -Notable changes -=============== - -Various bug fixes and improvements ----------------------------------- - -Various smaller improvements were added Omni Core 0.2.0, such as: - -- Fixing log spam generated by unconfirmed transactions -- Including the reason for a transaction being invalidated in the RPC response -- Adds an RPC to hash all balances in the state - -Change log -========== - -The following list includes relevant pull requests merged into this release: -``` -- #480 Add checkpoint for block 470000 -- #481 Add seed blocks for 460,000 to 470,000 -- #482 Remove git created macros to make builds deterministic -- #483 Update alert keys -- #493 Add seed blocks for block 470,000 to 490,000 -- #494 Add checkpoints for blocks 480,000 and 490,000 -- #505 Fix log spam from unconfirmed transactions -- #507 Persist the parsing result and include the reason for tx invalidation in RPC response -- #508 Add omni_getbalanceshash RPC -- #511 Travis CI: move back to the minimal image -- #512 Reintroduce forced client upgrade -- #514 Enable freezing for centrally managed tokens -- #515 Bump version to Omni Core 0.3.0 -``` - -Credits -======= - -Thanks to everyone who contributed to this release, and especially the Bitcoin Core developers for providing the foundation for Omni Core! diff --git a/src/elysium/doc/release-notes/mastercore-0.0.9-release-notes.md b/src/elysium/doc/release-notes/mastercore-0.0.9-release-notes.md deleted file mode 100644 index 90352a18a1..0000000000 --- a/src/elysium/doc/release-notes/mastercore-0.0.9-release-notes.md +++ /dev/null @@ -1,21 +0,0 @@ -Master Core version 0.0.9-rel is available from: - -- https://github.com/mastercoin-MSC/mastercore/releases/tag/v0.0.9 - -General -======= - -- This release is consensus critical. You MUST update before block 342650. After block 342650 prior versions WILL provide incorrect data -- This release modifies the schema. You MUST reparse when upgrading (run once with the --startclean option) -- Integrators should regularly poll getinfo_MP for any alerts to ensure they are kept aprised of any urgent issues - -Changelog -========= - -- Mainnet Send To Owners transaction processing is live from block 342650 -- STO support added to listtransactions_MP -- STO RPC calls getsto_MP and sendtoowners_MP added -- Added --startclean option to automate reparsing (removal of MP_ state folders etc) -- Alerting system added including evaluation and shutdown in event of new protocol messages being made live that are unsupported by client -- getinfo_MP RPC call added -- Numerous bugfixes \ No newline at end of file diff --git a/src/elysium/doc/release-notes/mastercore-0.0.9.1-release-notes.md b/src/elysium/doc/release-notes/mastercore-0.0.9.1-release-notes.md deleted file mode 100644 index eade93358f..0000000000 --- a/src/elysium/doc/release-notes/mastercore-0.0.9.1-release-notes.md +++ /dev/null @@ -1,66 +0,0 @@ -Omni Core version 0.0.9.1-rel is available from: - - https://github.com/mastercoin-MSC/mastercore/releases/tag/v0.0.9.1 - -0.0.9.1 is a minor release and not consensus critical. An upgrade is only mandatory if you are using a version prior 0.0.9. - -Please report bugs using the issue tracker at GitHub: - - https://github.com/mastercoin-MSC/mastercore/issues - -IMPORTANT -========= - -- This is the first experimental release of Omni Layer support in the QT UI, please be vigilant with testing and do not risk large amounts of Bitcoin and Omni Layer tokens. -- The transaction index is no longer defaulted to enabled. You will need to ensure you have "txindex=1" (without the quotes) in your configuration file. -- If you are upgrading from a version earlier than 0.0.9-rel you must start with the --startclean parameter at least once to refresh your persistence files. -- The first time Omni Core is run the startup process may take an hour or more as existing Omni Layer transactions are parsed. This is normal and should only be required the first time Omni Core is run. - -Upgrading and downgrading -========================== - -How to Upgrade --------------- - -If you are running an older version, shut it down. Wait until it has completely shut down (which might take a few minutes for older versions), then copy the new version of mastercored/mastercore-qt. - -If you are upgrading from any version earlier than 0.0.9, the first time you run you must start with the --startclean parameter at least once to refresh your persistence files. - -Downgrading ------------ - -Downgrading is not currently supported as older versions will not provide accurate information. - -Changelog -========= - -General -------- - -- Extra console debugging removed -- Bitcoin 0.10 blockchain detection (will refuse to start if out of order block storage is detected) -- txindex default value now matches Bitcoin Core (false) -- Update authorized alert senders -- Added support for TX70 to RPC output -- Fix missing LOCK of cs_main in selectCoins() -- Versioning code updated - - -UI --- - -- New signal added for changes to Omni state (emitted from block handler for blocks containing Omni transactions) -- Fix double clicking a transaction in overview does not activate the Bitcoin history tab -- Splash screen updated to reflect new branding -- Fix frame alignment in overview page -- Update send page behaviour and layout per feedback -- Fix column resizing on balances tab -- Right align amounts in balances tab -- Various rebranding to Omni Core -- Rewritten Omni transaction history tab -- Add protection against long labels growing the UI size to ridiculous proportions -- Update signalling to all Omni pages to ensure up to date info -- Override display of Mastercoin metadata for rebrand (RPC unchanged) -- Acknowledgement of disclaimer will now be remembered -- Ecosystem display fixed in property lookup -- Fix intermittent startup freezes due to locks diff --git a/src/elysium/doc/release-notes/mastercore-0.0.9.2-release-notes.md b/src/elysium/doc/release-notes/mastercore-0.0.9.2-release-notes.md deleted file mode 100644 index 8466312477..0000000000 --- a/src/elysium/doc/release-notes/mastercore-0.0.9.2-release-notes.md +++ /dev/null @@ -1,36 +0,0 @@ -Omni Core v0.0.9.2 -================== - -v0.0.9.2 is a minor release and not consensus critical in terms of the Omni Layer protocol rules. Due to recent events related to the Bitcoin network, it is recommended to upgrade to this version. - -Please report bugs using the issue tracker on GitHub: - - https://github.com/OmniLayer/omnicore/issues - -General -------- - -On 4 July 2015, after the activation of [BIP 66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki), a handful of miners accidently started to create invalid blocks, which may not be detected by outdated clients. This can result in transaction confirmations that aren't valid on the main chain of the Bitcoin network. - -For further information about this incident, please see: - - https://bitcoin.org/en/alert/2015-07-04-spv-mining - -How to Upgrade --------------- - -If you are running an older version, shut it down. Wait until it has completely shut down (which might take a few minutes for older versions), then copy the new version of `mastercored` or `mastercore-qt`. - -If you are upgrading from any version earlier than 0.0.9, the first time you run you must start with the `--startclean` parameter at least once to refresh the persistence files. - -Downgrading ------------ - -Downgrading is currently not supported as older versions will not provide accurate information. - -Notable changes ---------------- - -This release upgrades the underlying code base of Omni Core from Bitcoin Core 0.9.3 to Bitcoin Core 0.9.5. - -Please see the official release notes of [Bitcoin Core 0.9.5](release-notes.md), as well as the historical release notes of [Omni Core 0.0.9.1](release-notes/omnicore-0.0.9.1-release-notes.md) for details about recent changes. diff --git a/src/elysium/doc/release-notes/omnicore-0.0.10-release-notes.md b/src/elysium/doc/release-notes/omnicore-0.0.10-release-notes.md deleted file mode 100644 index 4a349b0ea6..0000000000 --- a/src/elysium/doc/release-notes/omnicore-0.0.10-release-notes.md +++ /dev/null @@ -1,561 +0,0 @@ -Omni Core v0.0.10 -================= - -v0.0.10 is a major release and consensus critical in terms of the Omni Layer protocol rules. An upgrade is mandatory, and highly recommended. Prior releases will not be compatible with new behavior in this release. - -Please report bugs using the issue tracker on GitHub: - - https://github.com/OmniLayer/omnicore/issues - -Table of contents -================= - -- [Omni Core v0.0.10](#omni-core-v0010) -- [Upgrading and downgrading](#upgrading-and-downgrading) - - [How to upgrade](#how-to-upgrade) - - [Downgrading](#downgrading) - - [Compatibility with Bitcoin Core](#compatibility-with-bitcoin-core) -- [Imported changes and notes](#imported-changes-and-notes) - - [Upgrade to Bitcoin Core 0.10.4](#upgrade-to-bitcoin-core-0104) - - [Headers-first synchronization](#headers-first-synchronization) - - [Dust threshold values](#dust-threshold-values) - - [Transaction fee changes](#transaction-fee-changes) - - [Rebranding to Omni Core](#rebranding-to-omni-core) - - [Incompatible API changes](#incompatible-api-changes) - - [Feature and consensus rule activations](#feature-and-consensus-rule-activations) -- [Consensus affecting changes](#consensus-affecting-changes) - - [Data embedding with OP_RETURN](#data-embedding-with-op_return) - - [Distributed token exchange](#distributed-token-exchange) - - [Remove side effects of granting tokens](#remove-side-effects-of-granting-tokens) - - [Disable DEx "over-offers" and use plain integer math](#disable-dex-over-offers-and-use-plain-integer-math) - - [New "send-all" transaction type](#new-send-all-transaction-type) - - [Don't allow ecosystem crossovers for crowdsales](#dont-allow-ecosystem-crossovers-for-crowdsales) -- [Other notable changes](#other-notable-changes) - - [JSON-RPC API updates](#json-rpc-api-updates) - - [Debug logging categories](#debug-logging-categories) - - [Configuration options](#configuration-options) - - [Various performance improvements](#various-performance-improvements) - - [Built-in consensus checks](#built-in-consensus-checks) - - [Checkpoints and faster initial transaction scanning](#checkpoints-and-faster-initial-transaction-scanning) - - [Disable-wallet mode](#disable-wallet-mode) - - [CI and testing of Omni Core](#ci-and-testing-of-omni-core) -- [Change log](#change-log) -- [Credits](#credits) - -Upgrading and downgrading -========================= - -How to upgrade --------------- - -If you are running Bitcoin Core or an older version of Omni Core, shut it down. Wait until it has completely shut down, then copy the new version of `omnicored`, `omnicore-cli` and `omnicore-qt`. On Microsoft Windows the setup routine can be used to automate these steps. - -During the first startup historical Omni transactions are reprocessed and Omni Core will not be usable for approximately 15 minutes up to two hours. The progress of the initial scan is reported on the console, the GUI and written to the `debug.log`. The scan may be interrupted, but can not be resumed, and then needs to start from the beginning. - -Downgrading ------------ - -Downgrading to an Omni Core version prior 0.0.10 is generally not supported as older versions will not provide accurate information due to the changes in consensus rules. - -Compatibility with Bitcoin Core -------------------------------- - -Omni Core is based on Bitcoin Core 0.10.4 and can be used as replacement for Bitcoin Core. Switching between Omni Core and Bitcoin Core is fully supported at any time. - -Downgrading to a Bitcoin Core version prior 0.10 is not supported due to the new headers-first synchronization. - -Imported changes and notes -========================== - -Upgrade to Bitcoin Core 0.10.4 ------------------------------- - -The underlying base of Omni Core was upgraded from Bitcoin Core 0.9.5 to Bitcoin Core 0.10.4. - -Please see the following release notes for further details: - -- [Release notes for Bitcoin Core 0.10.0](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/doc/release-notes/release-notes-0.10.0.md) -- [Release notes for Bitcoin Core 0.10.1](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/doc/release-notes/release-notes-0.10.1.md) -- [Release notes for Bitcoin Core 0.10.2](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/doc/release-notes/release-notes-0.10.2.md) -- [Release notes for Bitcoin Core 0.10.3](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/doc/release-notes/release-notes-0.10.3.md) -- [Release notes for Bitcoin Core 0.10.4](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/doc/release-notes.md) - -Headers-first synchronization ------------------------------ - -With the upgrade to Bitcoin Core 0.10 headers-first synchronization is supported and blocks are downloaded in parallel. - -Blocks are no longer stored in order on disk, and as result, the block files and databases are not backwards-compatible with older versions of Bitcoin Core prior 0.10. - -Dust threshold values ---------------------- - -The default `minrelaytxfee` was raised from `0.00001` to `0.00005` in Bitcoin Core 0.10.3 as temporary measure against massive memory pool bloat. - -The minimum relay fee influences the "dust threshold", and has an impact on the output values of Omni transactions, which are chosen to be as low as possible. As per default, Omni transactions created with Master Core had output values between `0.00000546` BTC and `0.00000882` BTC, whereby the new output values are between `0.0000273` BTC and `0.0000441` BTC. - -To continue to create transactions with lower values, start Omni Core with `-minrelaytxfee=0.00001` or add the following to your `bitcoin.conf`: -``` -minrelaytxfee=0.00001 -``` - -Lowering the `minrelaytxfee` may result in higher memory consumption, and too low values can result in delayed transaction propagation. A value less than than `0.00001` is generally not recommended. - -Transaction fee changes ------------------------ - -Starting with Bitcoin Core 0.10, transaction fees, as per default, are no longer hardcoded, but estimated based on previous blocks. - -This behavior can result in significantly different fees compared to Master Core 0.0.9, and manual tweaking is recommended, if the default fee estimation doesn't yield satisfying results. - -The following fee related configuration options are available: - -- `txconfirmtarget=`: create transactions that have enough fees (or priority) so they are likely to begin confirmation within n blocks (default: `6`). This setting is overridden by the `paytxfee` option. -- `paytxfee=`: fee (in BTC/kB) to add to transactions you send. -- `sendfreetransactions=0|1`: send transactions as zero-fee transactions if possible (default: `0`). - -New RPC commands for fee estimation: - -- `estimatefee nblocks`: returns approximate fee-per-1,000-bytes needed for a transaction to begin confirmation within nblocks. Returns `-1` if not enough transactions have been observed to compute an estimate. -- `estimatepriority nblocks`: returns approximate priority needed for a zero-fee transaction to begin confirmation within nblocks. Returns `-1` if not enough free transactions have been observed to compute an estimate. - -Please note, the fee estimation is not necessarily accurate. - - -Rebranding to Omni Core ------------------------ - -Master Core was re-branded to Omni Core on all levels: - -- `mastercored`, `mastercore-cli`, `mastercore-qt`, `test_mastercore` and `test_mastercore-qt` were renamed to `omnicored`, `omnicore-cli`, `omnicore-qt`, `test_omnicore` and `test_omnicore-qt` -- the debug log file `mastercore.log` was renamed to `omnicore.log` -- the hardcoded token SP#1 was renamed from `"MasterCoin"` to `"Omni"` -- the hardcoded token SP#2 was renamed from `"Test MasterCoin"` to `"Test Omni"` -- the user interface now refers to `"Omni"`, `"OMNI"`, `"Test Omni"` or `"TOMNI"` instead of `"Mastercoin"`, `"MSC"`, `"Test Mastercoin"` or `"TMSC"` - -Incompatible API changes ------------------------- - -The field `"subaction"` in the RPC response for traditional DEx orders of `"gettransaction_MP"` as well as `"listtransaction_MP"` was renamed to `"action"`. - -The values associated with `"action"` were renamed from `"New"`, `"Update"`, `"Cancel"` to `"new"`, `"update"`, `"cancel"`. - -Feature and consensus rule activations --------------------------------------- - -Omni Core 0.0.10 introduces feature activations, a new concept that allows the Omni team to decouple the release process from the process of making new features live. - -Prior to 0.0.10, the block height that a new feature would be made live was hard coded, placing substantial limits on both the frequency of releases and the flexibility in introducing new features. The feature activations system allows to separate the release process and activation of features by allowing the Omni team to activate features with a special Omni transaction instead of with a hard coded block height within a specific release. - -The activations system imposes set limits on when and by whom new features can be activated. A minimum 2048 block notice period (roughly 2 weeks) is enforced on the main network to give users with older incompatible clients time to upgrade. - -Prior to all activations, additional notifications are published via different channels, such as: - -- [the mailing list for developers](https://groups.google.com/a/mastercoin.org/d/forum/dev) -- [the mailing list for announcements](https://groups.google.com/a/mastercoin.org/d/forum/announcements) -- http://blog.omni.foundation - -As per default Omni Core accepts activation messages from the following source: -``` -{ - "address": "3Fc5gWzEQh1YGeqVXH6E4GDEGgbZJREJQ3", - "redeemScript": "542102d797b8526701a3dfdb52d11f89377e0288b14e29b1414d64de065cd337069c3b21036a4caa95ec1d55f1b75a8b6c7345f22b4efc9e25d38ab058ef7d6f60b3b744f7410499e86235a6a98fc295d7cfe641d37409f2840ad32e0211579cae488bd86cf01daf7ad8f082d968ea4bca77e794fffd1a31583f36f37b1198e51d0651cdbcf3214104b7a3d7f7ccdf211dfd180815b87332b4773cc40bff72a4d0bb60f3a85409d19f99709331c6b11c976fe274a86d789a1cf2b3b0be29fe5fc55c93ad9e08459c4f4104e65b098558d637cfcf3194214637f8838338b141259b698d2a027b069d405b6502ad4a4e9aa75094fa431a6c9af580f5917834a6d4cec946054df33194b2967855ae" -} -``` - -The activation message must be signed by at least 4 of the 5 nominated members of the Omni team in order to be accepted. These members are as follows: - -- Zathras - Project Maintainer and Developer -- dexx - Project Maintainer and Developer -- J.R. Willett - Founder and Board Member -- Craig Sellars - Technologist and Board Member -- Adam Chamely - Project Maintainer and Developer - -The transaction format of activation messages is as follows: - -| **Field** | **Type** | **Example** | -| -------------------------- | --------------- | ---------------------------------- | -| Transaction version | 16-bit unsigned | 65535 | -| Transaction type | 16-bit unsigned | 65534 | -| Feature identifier | 16-bit unsigned | 1 (Class C activation) | -| Activation block | 32-bit unsigned | 385000 | -| Min. client version | 32-bit unsigned | 1000000 (Omni Core 0.0.10) | - -Should a particular client version not support a new feature when it is activated, the client will shut down to prevent providing potentially inaccurate data. In this case the client should be upgraded. Whilst this behavior can be overridden with the configuration option `-overrideforcedshutdown`, it is strongly recommended against. - -Senders of activation messages can be whitelisted or blacklisted with the configuration options `-omnialertallowsender=` and `-omnialertignoresender=`. Please be aware that overriding activations may cause the client to provide inaccurate data that does not reflect the rest of the network. - -The GUI displays warnings for pending activations and daemon users can view pending and completed activations via the [omni_getactivations](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_getactivations) JSON-RPC API call. - -Consensus affecting changes -=========================== - -Starting with this version, all changes of the consensus rules are enabled by activation transactions. - -Please note, while Omni Core 0.0.10 contains support for several new rules and features they are not enabled immediately and will be activated via the feature activation mechanism described above. - -It follows an overview and a description of the consensus rule changes: - -Data embedding with OP_RETURN ------------------------------ - -Omni Core 0.0.10 contains support for Class C transactions which move the data encoding from bare-multisig data outputs to an `OP_RETURN` output. `OP_RETURN` outputs carry no output value and can be immediately pruned. - -In addition to migrating data encoding to `OP_RETURN`, the requirement to send an output to the Elysium address has also been removed with Class C. Instead the bytes `0x6f6d6e69` ("omni") are prefixed to the data payload to provide marker identification. - -This helps to address a common criticism of systems that store data on the Bitcoin blockchain; "UTXO bloat". Since Class C transactions no longer store the data in spendable outputs, there is no need to store them in the UTXO set, and since the outputs are not stored in the UTXO set, Class C transactions do not contribute to its growth. - -Due to size and count restrictions of `OP_RETURN` outputs currently enforced by the Bitcoin network, the client will automatically fall back to Class B (bare-multisig) in the event that a transaction is too large to send via Class C (for example a property creation with lots of metadata). - -The configuration option `-datacarriersize=` can be used to set the maximal size of `OP_RETURN` payloads, and is set to `40` bytes as per default. A value of `0` can be used to disable Class C encoding completely. - -This change is identified by `"featureid": 1` and labeled by the GUI as `"Class C transaction encoding"`. - -Distributed token exchange --------------------------- - -The distributed token exchange, or "MetaDEx", was integrated into Omni Core, to support trading of tokens with automated order matching. - -Four new transaction types were added. - -##### Create order: - -| **Field** | **Type** | **Example** | -| -------------------------- | --------------- | ---------------------------------- | -| Transaction version | 16-bit unsigned | 0 | -| Transaction type | 16-bit unsigned | 25 | -| Tokens to list for sale | 32-bit unsigned | 2147483831 (Gold Coins) | -| Amount to list for sale | 64-bit signed | 5000000000 (50.0 divisible tokens) | -| Tokens desired in exchange | 32-bit unsigned | 2 (Test Omni) | -| Amount desired in exchange | 64-bit signed | 1000000000 (10.0 divisible tokens) | - -Transaction type 25 can be used to create a new order. - -##### Cancel all orders at price: - -| **Field** | **Type** | **Example** | -| -------------------------- | --------------- | ---------------------------------- | -| Transaction version | 16-bit unsigned | 0 | -| Transaction type | 16-bit unsigned | 26 | -| Tokens listed for sale | 32-bit unsigned | 2147483831 (Gold Coins) | -| Amount listed for sale | 64-bit signed | 2500000000 (25.0 divisible tokens) | -| Tokens desired in exchange | 32-bit unsigned | 2 (Test Omni) | -| Amount desired in exchange | 64-bit signed | 500000000 (5.0 divisible tokens) | - -Transaction type 26 cancels open orders for a given set of currencies at a given price. It is required that the token identifiers and price exactly match the order to be canceled. - -##### Cancel all orders of currency pair: - -| **Field** | **Type** | **Example** | -| -------------------------- | --------------- | ---------------------------------- | -| Transaction version | 16-bit unsigned | 0 | -| Transaction type | 16-bit unsigned | 27 | -| Tokens listed for sale | 32-bit unsigned | 2147483831 (Gold Coins) | -| Tokens desired in exchange | 32-bit unsigned | 2 (Test Omni) | - -Transaction type 27 cancels all open orders for a given set of two currencies (one side of the order book). - -##### Cancel all orders in ecosystem: - -| **Field** | **Type** | **Example** | -| -------------------------- | --------------- | ---------------------------------- | -| Transaction version | 16-bit unsigned | 0 | -| Transaction type | 16-bit unsigned | 28 | -| Ecosystem | 8-bit unsigned | 2 (test ecosystem) | - -Transaction type 28 can be used to cancel all open orders for all currencies in the specified ecosystem. - -Transactions for the distributed token exchange are enabled on testnet, in regtest mode and when trading tokens in the test ecosystem. Transactions targeting the main ecosystem are supported after the feature activation. - -See also: [omni_sendtrade](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_sendtrade), [omni_sendcanceltradesbyprice](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_sendcanceltradesbyprice), [omni_sendcanceltradesbypair](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_sendcanceltradesbypair), [omni_sendcancelalltrades](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_sendcancelalltrades), [omni_gettrade](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_gettrade), [omni_getorderbook](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_getorderbook), [omni_gettradehistoryforpair](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_gettradehistoryforpair), [omni_gettradehistoryforaddress](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_gettradehistoryforaddress) JSON-RPC API calls - -This change is identified by `"featureid": 2` and labeled by the GUI as `"Distributed Meta Token Exchange"`. - -Remove side effects of granting tokens --------------------------------------- - -The transaction type "grant tokens" may trigger crowdsale participations as secondary effect, if the recipient of granted tokens has an active crowdsale, which issues tokens in exchange for the granted tokens. - -Once this change is activated, "grant tokens" no longer triggers passive crowdsale participations. - -This change is identified by `"featureid": 4` and labeled by the GUI as `"Remove grant side effects"`. - -Disable DEx "over-offers" and use plain integer math ----------------------------------------------------- - -After this feature is enabled, it is no longer valid to create orders on the traditional distributed exchange, which offer more than the seller has available, and the amounts are no longer adjusted based on the actual balance. Previously such a transaction was valid, and the whole available amount was offered. - -Plain integer math (instead of floating point numbers) is used to determine the purchased amount. The purchased amount is rounded up, which may be in favor of the buyer, to avoid small leftovers of 1 willet. This is not exploitable due to transaction fees. - -This change is identified by `"featureid": 5` and labeled by the GUI as `"DEx integer math update"`. - -New "send-all" transaction type -------------------------------- - -A new transaction type was added to send all tokens an entity has in one single transaction. - -Transactions with type 4 transfer available balances of all tokens in the specified ecosystem from the source to the reference destination. Transactions of this type are considered valid, if at least one token was transferred, and invalid otherwise. - -The transaction format is as follows: - -| **Field** | **Type** | **Example** | -| -------------------------- | --------------- | ---------------------------------- | -| Transaction version | 16-bit unsigned | 0 | -| Transaction type | 16-bit unsigned | 4 | -| Ecosystem | 8-bit unsigned | 2 (test ecosystem) | - -"Send-all" transactions are enabled on testnet, in regtest mode and when transferring tokens in the test ecosystem. Transactions targeting the main ecosystem are supported after the feature activation. - -See also: [omni_sendall](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_sendall) JSON-RPC API call - -This change is identified by `"featureid": 6` and labeled by the GUI as `"Send All transactions"`. - -Don't allow ecosystem crossovers for crowdsales ------------------------------------------------ - -A design goal of different ecosystems was to seperate both systems cleanly. However, this was not enforced for crowdsales, and it was possible to create crowdsales, which issue test ecosystem tokens in exchange for main ecosystem tokens and vice versa. - -After the feature activation, the tokens to issue via crowdsale must be in the same ecosystem as the tokens desired. - -This change is identified by `"featureid": 7` and labeled by the GUI as `"Disable crowdsale ecosystem crossovers"`. - -Other notable changes -===================== - -JSON-RPC API updates --------------------- - -The JSON-RPC API was extended significantly, and now supports sending transactions of any transaction type, and the creation of raw Omni transactions. - -Several new API calls are available to retrieve information about unconfirmed or confirmed Omni transactions, and the state of the system. - -Please see the JSON-RPC API documentation for more details: - -- https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md - -Debug logging categories ------------------------- - -Debug logging is categorized and default logging options may be changed with the `-omnidebug` parameter. Use multiple `-omnidebug` parameters to specify multiple categories. - -The following categories are available: - -- `parser`: Log additional information when parsing -- `parser_data`: Log verbose additional information when parsing -- `parser_dex`: Log additional information about DEx payments when parsing -- `parser_readonly`: Log extra information when parsing in read only mode (e.g. via RPC interface) -- `verbose`: Log verbose information about sender identification -- `vin`: Log additional information about the inputs used when parsing -- `script`: Log additional information about the scripts used when parsing -- `dex`: Log additional information about DEx transactions -- `tokens`: Log additional information about input selection -- `spec`: Warn about non-sequential sequence numbers in Class B transactions -- `ely`: Log additional information about actions involving the Elysium address -- `tally`: Log before/after values when balances are updated -- `sp`: Log additional information about actions involving smart property updates -- `sto`: Log additional information about Send To Owners calculations -- `txdb`: Log additional information about interactions with the transaction database -- `tradedb`: Log additional information about interactions with the trades database -- `persistence`: Log additional information about interactions with the persistent state files -- `pending`: Log additional information about pending transactions -- `metadex1`: Log additional information about MetaDEx transactions -- `metadex2`: Log the state of the MetaDEx before and after each MetaDEx transaction -- `metadex3`: Log the state of the MetaDEx before and after each MetaDEx action and log each MetaDEx object during iteration of MetaDEx maps -- `packets`: Log additional information about the payload included within each Omni transaction -- `packets_readonly`: Log additional information about the payload included within each Omni transaction when parsing in read only mode (e.g. via RPC interface) -- `walletcache`: Log additional information about the wallet cache and hits/misses -- `consensus_hash`: Log additional information about each data point added to the consensus hash -- `consensus_hash_every_block`: Generate and log a consensus hash for every block processed -- `alerts`: Log additional information about alert transactions - -Special keywords: - -- `all`: Enable all logging categories (note: extremely verbose) -- `none`: Disable all logging categories - -Usage examples: -``` -omnicored -omnidebug=all -``` -``` -omnicored -omnidebug=parser -omnidebug=parser_data -omnidebug=vin -omnidebug=script -``` - -Configuration options ---------------------- - -For a listing of other Omni Core specific configuration options see: - -- https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/configuration.md - -Various performance improvements --------------------------------- - -Omni Core was improved on several levels to increase performance and responsiveness. - -Previously RPC requests were blocking, creating a bottleneck for the JSON-RPC API and the whole application. Due to much finer and more targeted locking of critical sections, threads are now only blocked when they need to be, which allows concurrent requests without immediately creating a queue. The number of threads designated to handle RPC requests can be configured with the option `-rpcthreads=`, which is set to `4` threads as per default. - -The serialization of token related database entries was previously JSON based, and the time to retrieve information about transactions, tokens or crowdsales, for example with [omni_gettransaction](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_gettransaction), [omni_getproperty](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_getproperty), [omni_getcrowdsale](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_getcrowdsale) or [omni_getactivecrowdsales](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_getactivecrowdsales), was primarily delayed by slow conversions of the data stored in the database. Entries are now stored in their raw byte representation, which allows much faster deserialization of the data. Benchmarks have shown this update provides a speed improvement of about 8x or more for these calls. - -Most notably on Microsoft Windows, many updates of the GUI, for example when connecting a new block, created the impression of a non-responsive user interface, because the client couldn't keep up with the updates. This was optimized such that no queue of update events is created in the first place, and new update requests are dropped, in case there are already events which haven't been handled. - -Built-in consensus checks -------------------------- - -It is mandatory that the state of the system is similar for all participants, and Omni Core 0.0.10 introduces the concept of "consensus hashes", which are a compact representation of the state. This allows to compare the state of the system with other participants, and to compare historical state with known reference states, to ensure consensus. - -To log consensus hashes, the configuration options `-omnidebug=consensus_hash` and `-omnidebug=consensus_hash_every_block` can be used. - -Checkpoints and faster initial transaction scanning ---------------------------------------------------- - -When Omni Core is used the very first time, or when Omni Core hasn't been used for a longer period, then historical blocks are scanned for Omni transactions. With the introduction of "consensus hashes", a significant speed improvement during the initial stage was possible by skipping known blocks without Omni transactions, and by comparing the resulting state with checkpoints. If the state of the client doesn't match the reference state, the client shuts down to prevent providing inaccurate data. - -Omni Core was intentionally not delivered with a snapshot of the most recent state, and transactions are fully verified in any case. One design goal of Omni Core has always been to minimize the role of central parties (in this case: the ones providing a snapshot or checkpoints), and to further minimize the dependency on a hardcoded list of information, the configuration option `-omniseedblockfilter=0` can be used to disable the skipping of blocks without Omni transactions. - -The configuration option `-overrideforcedshutdown` can be used to prevent Omni Core from shutting down in case of a checkpoint mismatch. Using the latter is generally not recommended, as this exposes the user to data, which isn't considered as valid by other participants. - -Disable-wallet mode -------------------- - -Since this version Omni Core can be build and used without wallet support. - -This can be handy, when using Omni Core as plain data provider, without the need to send transactions. [Data retrieval](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#data-retrieval) and [raw transaction](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#raw-transactions) API calls are enabled in this mode. - -To compile Omni Core without wallet support (illustrated for Unix): -``` -./autogen.sh -./configure --disable-wallet -make -``` - -To disable to wallet via configuration options start Omni Core with `-disablewallet`, or add the following to your `bitcoin.conf`: -``` -disablewallet=1 -``` - -CI and testing of Omni Core ---------------------------- - -As of now, Omni Core 0.10 has nearly 5000 lines of source code for unit tests in addition to the unit tests inherited from Bitcoin Core. Furthermore [OmniJ](https://github.com/OmniLayer/OmniJ#omni-integration-testing-with-spock-framework) is used for integration testing. - -To run the unit tests locally, start `test_omnicore` or `test_omnicore-qt`. On Unix, the integration tests can be started with `qa/pull-tester/omnicore-rpc-tests.sh`. Please note, the script for the integration tests is not included in the release packages. For other operating systems, or to manually run the integration tests, see the [instructions for OmniJ](https://github.com/OmniLayer/OmniJ#omni-integration-testing-with-spock-framework). - -Travis CI was integrated into the work flow, to automatically build and test Omni Core on several different platforms and operating systems. - -Change log -========== - -The following list includes relevant pull requests merged into this release: -``` -- #1, #2 Upgrade code base to Bitcoin Core 0.10.2 -- #7 Select only coins, which can be spent -- #4 Fix shutdown issue after running Boost tests -- #8, #26, #33, #35, #67 Finalize MetaDEx logic -- #5 MetaDEx user interface -- #13 Support creation of any (enabled) Omni transaction via RPC -- #13 Support Class C/OP_RETURN encoded transactions -- #17 Report initial parsing progress during startup -- #17 Handle shutdown requests during initial parsing -- #42 Integrate Travis CI and OmniJ into workflow -- #50 Allow debug levels to be specified without needing to recompile -- #34 Set `txindex=1` flag during startup, if confirmed by user -- #68 Various code cleanups and improved code documentation -- #68 Resolve and refine several `LOCKs` -- #68 Support concurrent RPC queries -- #79 Show script verification errors in `signrawtransaction` result -- #81 Enable pay-to-script-hash support in send dialog -- #86 Return all available information via `validateaddress` -- #98 Indicate "pending" status of outgoing transactions -- #109 Log every invalid processing of Omni transactions -- #91 Rebrand project to Omni Core -- #91 Rename files to `omnicore-qt`, `omnicored`, `omnicore-cli`, ... -- #102, #126 Fully support cross-platform, and deterministic, building -- #113, #118 Unify and improve RPC help descriptions -- #121 Fix shutdown issue after declining to reindex blockchain -- #126 Add images to installer icon for deterministic building -- #127 Reduce math and big numbers in crowdsale participation -- #128 Run OmniJ tests with all build targets except OS X -- #131 When closing a crowdsale, write info to debug log, not file -- #133 Report progress based on transactions, report estimated time remaining -- #132 Reduce amount of verbose logging by default -- #140 Use higher resolution program icons -- #145 Implement tally hashing for consensus testing and checkpoints -- #146 Fix trading restrictions for testnet -- #136 Skip loading unneeded blocks during initial parsing -- #150 #152 Add MetaDEx guide documentation -- #149 Update Omni Core API documentation -- #156 Move simple send logic and friends to the other logic methods -- #159 Implement and switch to Feature-Activation-By-Message -- #161 Don't spam log about non-sequential seqence numbers -- #163 Prepare deactivation of "grant tokens" side effects -- #164 Add hidden RPC command to activate features -- #158 Trigger UI updates after DEx payments and Elysium purchases -- #173 Fix/add missing fields for transaction retrieval via RPC -- #177 Sanitize RPC responses and replace non-UTF-8 compliant characters -- #178 Fix Omni transaction count value passed into block end handler -- #179 Add consensus checkpoint for block 370000 -- #180 Update seed blocks to 370000 -- #181 Update base to Bitcoin Core 0.10~ tip -- #174 Add RPC support for unconfrimed Omni transactions -- #184 Stop recording structurally-invalid transactions in txlistdb -- #167 Mostly cosmetic overhaul of traditional DEx logic -- #187 Automate state refresh on client version change when needed -- #195 Refine amount recalculations of traditional DEx via RPC -- #160 Improve wallet handling and support --disable-wallet builds -- #197 Reject DEx "over-offers" and use plain integer math -- #203 Minor cleanup of MetaDEx status and RPC output -- #207 No longer allow wildcard when cancelling all MetaDEx orders -- #209 Remove unused addresses in MetaDEx cancel dialog after update -- #210 Don't restrict number of trades and transactions in UI history -- #213 Refine RPC input parsing related to addresses -- #217 Rebrand "Mastercoin" to "Omni" -- #218 Fix/remove empty build target of Travis CI -- #220 Fix Bitcoin balance disappears from the UI on reorg -- #221 Don't call StartShutdown() after updating config -- #223 Fix calculation of crowdsale participation on Windows -- #224 Update links to moved API documentation -- #225 Rebrand token and fix links to RPC API sections -- #227 Do not save state when a block fails checkpoint validation -- #229 Minor update to MetaDEx guide -- #238 Fix crowdsale purchase detection in test ecosystem -- #231 Change icon to make Win64 installer deterministic -- #240 Various small improvements to ensure correct state -- #232 Add new RPC to list pending Omni transactions -- #243 Fix STO DB corruption on reorg -- #239 Fix "raised amount" in RPC result of crowdsales -- #234 Update documentation of configuration options -- #233 Use tables and add results to JSON-RPC API documentation -- #250 Fix missing crowdsale purchase entries in verbose "omni_getcrowdsale" -- #253 Update handling of crowdsales and missing bonus amounts -- #142 Add RPC to decode raw Omni transactions -- #176 Implement updated alerting & feature activations -- #252 Restrict ecosystem crossovers for crowdsales -- #258 Explicitly set transaction and relay fee for RPC tests -- #260 Add ARM and a no-wallet build as build target for Travis CI -- #262 Filter empty balances in omni_getall* RPC calls -- #263 Update base to Bitcoin Core 0.10.3 -- #77 Support creation of raw transactions with non-wallet inputs -- #273 Remove "Experimental UI" label GUI splash screen -- #274 Add consensus checkpoint for block 380000 -- #276 Update seed blocks for blocks 370,000 to 380,000 -- #278 Replace splashes to remove OmniWallet branding -- #269 Add release notes for Omni Core 0.0.10 -- #162 Bump version to 0.0.10.0-rc1 -- #282 Update base to Bitcoin Core 0.10.4 -- #285 Don't use "N/A" label for transactions with type 0 -- #286 Bump version to Omni Core 0.0.10-rc3 -- #288 Expose payload over RPC and add payload size -- #291 Add error handlers for "omni_getpayload" -- #292 Add API documentation for "omni_getpayload" -- #295 Fix overflow when trading divisible against divisible -- #303 Force UI update every block with Omni transactions -- #305 Change default confirm target to 6 blocks -- #307 Update release notes for 0.0.10 -- #306 Bump version to Omni Core 0.0.10-rel -``` - -Credits -======= - -Thanks to everyone who contributed to this release, and especially the Bitcoin Core developers for providing the foundation for Omni Core! diff --git a/src/elysium/doc/release-notes/omnicore-0.0.11.0-release-notes.md b/src/elysium/doc/release-notes/omnicore-0.0.11.0-release-notes.md deleted file mode 100644 index 16d0da539d..0000000000 --- a/src/elysium/doc/release-notes/omnicore-0.0.11.0-release-notes.md +++ /dev/null @@ -1,212 +0,0 @@ -Omni Core v0.0.11 -================= - -v0.0.11 is a major release and consensus critical in terms of the Omni Layer protocol rules. An upgrade is mandatory, and highly recommended. Prior releases will not be compatible with new behavior in this release. - -Please report bugs using the issue tracker on GitHub: - - https://github.com/OmniLayer/omnicore/issues - -Table of contents -================= - -- [Omni Core v0.0.11](#omni-core-v0011) -- [Upgrading and downgrading](#upgrading-and-downgrading) - - [How to upgrade](#how-to-upgrade) - - [Downgrading](#downgrading) - - [Compatibility with Bitcoin Core](#compatibility-with-bitcoin-core) -- [Consensus affecting changes](#consensus-affecting-changes) - - [Trading of all pairs on the Distributed Exchange](#trading-of-all-pairs-on-the-distributed-exchange) - - [Fee distribution system on the Distributed Exchange](#fee-distribution-system-on-the-distributed-exchange) - - [Send to Owners cross property suport](#send-to-owners-cross-property-support) -- [Other notable changes](#other-notable-changes) - - [Raw payload creation API](#raw-payload-creation-api) - - [Other API extensions](#other-api-extensions) - - [Increased OP_RETURN payload size to 80 byte](#increased-op_return-payload-size-to-80-bytes) - - [Improved consensus checks](#improved-consensus-checks) - - [Various bug fixes and clean-ups](#various-bug-fixes-and-clean-ups) -- [Change log](#change-log) -- [Credits](#credits) - -Upgrading and downgrading -========================= - -How to upgrade --------------- - -If you are running Bitcoin Core or an older version of Omni Core, shut it down. Wait until it has completely shut down, then copy the new version of `omnicored`, `omnicore-cli` and `omnicore-qt`. On Microsoft Windows the setup routine can be used to automate these steps. - -During the first startup historical Omni transactions are reprocessed and Omni Core will not be usable for approximately 15 minutes up to two hours. The progress of the initial scan is reported on the console, the GUI and written to the `debug.log`. The scan may be interrupted, but can not be resumed, and then needs to start from the beginning. - -Downgrading ------------ - -Downgrading to an Omni Core version prior 0.0.11 is generally not supported as older versions will not provide accurate information due to the changes in consensus rules. - -Compatibility with Bitcoin Core -------------------------------- - -Omni Core is based on Bitcoin Core 0.10.4 and can be used as replacement for Bitcoin Core. Switching between Omni Core and Bitcoin Core is fully supported at any time. - -Downgrading to a Bitcoin Core version prior 0.10 is not supported due to the new headers-first synchronization. - -Consensus affecting changes -=========================== - -All changes of the consensus rules are enabled by activation transactions. - -Please note, while Omni Core 0.0.11 contains support for several new rules and features they are not enabled immediately and will be activated via the feature activation mechanism described above. - -It follows an overview and a description of the consensus rule changes: - -Trading of all pairs on the Distributed Exchange ------------------------------------------------- - -Once activated trading of any property against any other (within the same ecosystem) will be permitted on the Distributed Exchange. - -Due to this change the existing trading UI in the QT version is no longer suitable and has been disabled for this release. Please use the RPC interface to interact with the Distributed Exchange in this release. The trading UI will be re-enabled in a future version to accommodate non-Omni pair trading. - -This change is identified by `"featureid": 8` and labeled by the GUI as `"Allow trading all pairs on the Distributed Exchange"`. - -Fee distribution system on the Distributed Exchange ---------------------------------------------------- - -Omni Core 0.11 contains a fee caching and distribution system. This system collects small amounts of tokens in a cache until a distribution threshold is reached. Once this distribution threshold (trigger) is reached for a property, the fees in the cache will be distributed proportionally to holders of the Omni (#1) and Test-Omni (#2) tokens based on the percentage of the total Omni tokens owned. - -Once activated fees will be collected from trading of non-Omni pairs on the Distributed Exchange (there is no fee for trading Omni pairs). The party removing liquidity from the market will incur a 0.05% fee which will be transferred to the fee cache, and subsequently distributed to holders of the Omni token. - -- Placing a trade where one side of the pair is Omni (#1) or Test-Omni (#2) incurs no fee -- Placing a trade where liquidity is added to the market (i.e. the trade does not immediately execute an existing trade) incurs no fee -- Placing a trade where liquidity is removed from the market (i.e. the trade immediately executes an existing trade) the liquidity taker incurs a 0.05% fee - -See also [fee system JSON-RPC API documentation](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#fee-system). - -This change is identified by `"featureid": 9` and labeled by the GUI as `"Fee system (inc 0.05% fee from trades of non-Omni pairs)"`. - -Send To Owners cross property support -------------------------------------- - -Once activated distributing tokens via the Send To Owners transaction will be permitted to cross properties if using version 1 of the transaction. - -Tokens of property X then may be distributed to holders of property Y. - -There is a significantly increased fee (0.00001000 per recipient) for using version 1 of the STO transaction. The fee remains the same (0.00000001) per recipient for using version 0 of the STO transaction. - -Sending an STO transaction via Omni Core that distributes tokens to holders of the same property will automatically be sent as version 0, and sending a cross-property STO will automatically be sent as version 1. - -The transaction format of new Send To Owners version is as follows: - -| **Field** | **Type** | **Example** | -| ------------------------------ | --------------- | ----------- | -| Transaction version | 16-bit unsigned | 65535 | -| Transaction type | 16-bit unsigned | 65534 | -| Tokens to transfer | 32-bit unsigned | 6 | -| Amount to transfer | 64-bit signed | 700009 | -| Token holders to distribute to | 32-bit unsigned | 23 | - -This change is identified by `"featureid": 10` and labeled by the GUI as `"Cross-property Send To Owners"`. - -Other notable changes -===================== - -Raw payload creation API ------------------------- - -Omni Core 0.0.11 adds support for payload creation via the RPC interface. - -The calls are similar to the send transactions (e.g. `omni_send`), without the requirement for an address or any of the balance checks. - -This allows integrators to build transactions via the [raw transactions interface](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#raw-transactions). - -Other API extensions --------------------- - -An optional parameter `height` can be provided, when using [omni_decodetransaction](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_decodetransaction), which is used to determine the parsing rules. If no `height` is provided, the chain height is used as default. - -When retrieving feature activation transactions with [omni_gettransaction](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_gettransaction), then additional fields are included in the result: `"featureid"`, `"activationblock"` and `"minimumversion"`. - -The Omni Core client version is now also exposed under the new key `"omnicoreversion"`, as well as inter via `"omnicoreversion_int"`, when using [omni_getinfo](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_getinfo). The old key `"mastercoreversion"` remains for compatibility in this version. - -The field `"positioninblock"` was added to RPCs retrieving or listing Omni transactions to provide visibility into the order of an Omni transaction within a block. - -Increased OP_RETURN payload size to 80 bytes --------------------------------------------- - -The maximum payload for OP_RETURN outputs was increased to 80 byte. - -At this point a majority of the network supports 80 byte payloads, so Omni Core can safely use the larger payload size. This can result in cheaper transactions, as there is no fallback to bare multisig encoding. - -Improved consensus checks -------------------------- - -Consensus hashing now covers much more of the state to provide wider coverage of the state. The state of properties, crowdsales and the Distributed Exchange are included in the new consensus hashing process. - -Checkpoints have been updated in Omni Core 0.0.11 to reflect the new consensus hashing algorithm. Seed blocks (for faster initial transaction scanning) and checkpoints are included with Omni Core 0.0.11 up to block 410,000. - -Various bug fixes and clean-ups ------------------------------- - -Various smaller improvements were added Omni Core 0.0.11, such as: - -- Grow balances to fit on "Overview" tab -- Switch to "Bitcoin" tab in "Send" page when handling Bitcoin URIs -- Improve and adjust fee warning threshold when sending transactions -- Fix missing client notification for new feature activations -- Fix Travis CI builds without cache -- Fix syntax error in walletdb key parser -- Fix too-aggressive database clean in block reorganization events - -Change log -========== - -The following list includes relevant pull requests merged into this release: -``` -- #226 Upgrade consensus hashing to cover more of the state -- #316 Support providing height for omni_decodetransaction -- #317 Expose feature activation fields when decoding transaction -- #318 Expose Omni Core client version as integer -- #321 Add consensus hash for block 390000 -- #324 Fix and update seed blocks up to block 390000 -- #325 Add capability to generate seed blocks over RPC -- #326 Grow balances to fit on overview tab -- #327 Switch to Bitcoin tab in Send page when handling Bitcoin URIs -- #328 Update and add unit tests for new consensus hashes -- #332 Remove seed blocks for structurally invalid transactions + reformat -- #333 Improve fee warning threshold in GUI -- #334 Update documentation for getseedblocks, getcurrentconsensushash, setautocommit -- #335 Disable logging on Windows to speed up CI RPC tests -- #336 Change the default maximum OP_RETURN size to 80 bytes -- #341 Add omni_getmetadexhash RPC call to hash state of MetaDEx -- #343 Remove pre-OP_RETURN legacy code -- #344 Fix missing client notification for new activations -- #349 Add positioninblock attribute to RPC output for transactions -- #358 Add payload creation to the RPC interface -- #361 Unlock trading of all pairs on the MetaDEx -- #364 Fix Travis builds without cache -- #365 Fix syntax error in walletdb key parser -- #367 Bump version to Omni Core 0.0.11-dev -- #368 Fix too-aggressive database clean in reorg event -- #371 Add consensus checkpoints for blocks 400,000 & 410,000 -- #372 Add seed blocks for 390,000 to 410,000 -- #375 Temporarily disable the trading UI -- #384 Add fee system RPC calls to API doc -- #385 Add RPC documentation for createpayload calls -- #386 Don't warn user about unknown block versions -- #377 Add release notes for Omni Core 0.0.11 -- #376 Bump version to Omni Core 0.0.11-rc1 -- #390 Add cross-property (v1) Send To Owners -- #395 Move test scripts into /src/omnicore/test -- #396 Add workaround for "bytes per sigops" limit -- #400 Change default confirm target to 15 blocks -- #398 Update release notes for 0.0.11-rc2 -- #397 Bump version to Omni Core 0.0.11-rc2 -- #402 Add seed blocks for 410,000 to 420,000 -- #403 Add consensus hash for block 420,000 -- #405 Use uint256 when calculating desired BTC for DEx 1 -- #404 Bump version to Omni Core 0.0.11-rel -``` - -Credits -======= - -Thanks to everyone who contributed to this release, and especially the Bitcoin Core developers for providing the foundation for Omni Core! diff --git a/src/elysium/doc/release-notes/omnicore-0.0.11.1-release-notes.md b/src/elysium/doc/release-notes/omnicore-0.0.11.1-release-notes.md deleted file mode 100644 index 905ed26f86..0000000000 --- a/src/elysium/doc/release-notes/omnicore-0.0.11.1-release-notes.md +++ /dev/null @@ -1,217 +0,0 @@ -Omni Core v0.0.11.1 -=================== - -v0.0.11.1 is a bugfix release which resolves a critical bug in the RPC API whereby under certain circumstances retrieving data about a sell offer may trigger a failsafe and cause the automatic shutdown of the client. - -This version is built on top of v0.0.11, which is a major release and consensus critical in terms of the Omni Layer protocol rules. An upgrade is mandatory, and highly recommended. Prior releases will not be compatible with new behavior in this release. - -Please report bugs using the issue tracker on GitHub: - - https://github.com/OmniLayer/omnicore/issues - -Table of contents -================= - -- [Omni Core v0.0.11.1](#omni-core-v00111) -- [Upgrading and downgrading](#upgrading-and-downgrading) - - [How to upgrade](#how-to-upgrade) - - [Downgrading](#downgrading) - - [Compatibility with Bitcoin Core](#compatibility-with-bitcoin-core) -- [Consensus affecting changes](#consensus-affecting-changes) - - [Trading of all pairs on the Distributed Exchange](#trading-of-all-pairs-on-the-distributed-exchange) - - [Fee distribution system on the Distributed Exchange](#fee-distribution-system-on-the-distributed-exchange) - - [Send to Owners cross property suport](#send-to-owners-cross-property-support) -- [Other notable changes](#other-notable-changes) - - [Raw payload creation API](#raw-payload-creation-api) - - [Other API extensions](#other-api-extensions) - - [Increased OP_RETURN payload size to 80 byte](#increased-op_return-payload-size-to-80-bytes) - - [Improved consensus checks](#improved-consensus-checks) - - [Various bug fixes and clean-ups](#various-bug-fixes-and-clean-ups) -- [Change log](#change-log) -- [Credits](#credits) - -Upgrading and downgrading -========================= - -How to upgrade --------------- - -If you are running Bitcoin Core or an older version of Omni Core, shut it down. Wait until it has completely shut down, then copy the new version of `omnicored`, `omnicore-cli` and `omnicore-qt`. On Microsoft Windows the setup routine can be used to automate these steps. - -During the first startup historical Omni transactions are reprocessed and Omni Core will not be usable for approximately 15 minutes up to two hours. The progress of the initial scan is reported on the console, the GUI and written to the `debug.log`. The scan may be interrupted, but can not be resumed, and then needs to start from the beginning. - -Downgrading ------------ - -Downgrading to an Omni Core version prior 0.0.11 is generally not supported as older versions will not provide accurate information due to the changes in consensus rules. - -Compatibility with Bitcoin Core -------------------------------- - -Omni Core is based on Bitcoin Core 0.10.4 and can be used as replacement for Bitcoin Core. Switching between Omni Core and Bitcoin Core is fully supported at any time. - -Downgrading to a Bitcoin Core version prior 0.10 is not supported due to the new headers-first synchronization. - -Consensus affecting changes -=========================== - -All changes of the consensus rules are enabled by activation transactions. - -Please note, while Omni Core 0.0.11 contains support for several new rules and features they are not enabled immediately and will be activated via the feature activation mechanism described above. - -It follows an overview and a description of the consensus rule changes: - -Trading of all pairs on the Distributed Exchange ------------------------------------------------- - -Once activated trading of any property against any other (within the same ecosystem) will be permitted on the Distributed Exchange. - -Due to this change the existing trading UI in the QT version is no longer suitable and has been disabled for this release. Please use the RPC interface to interact with the Distributed Exchange in this release. The trading UI will be re-enabled in a future version to accommodate non-Omni pair trading. - -This change is identified by `"featureid": 8` and labeled by the GUI as `"Allow trading all pairs on the Distributed Exchange"`. - -Fee distribution system on the Distributed Exchange ---------------------------------------------------- - -Omni Core 0.11 contains a fee caching and distribution system. This system collects small amounts of tokens in a cache until a distribution threshold is reached. Once this distribution threshold (trigger) is reached for a property, the fees in the cache will be distributed proportionally to holders of the Omni (#1) and Test-Omni (#2) tokens based on the percentage of the total Omni tokens owned. - -Once activated fees will be collected from trading of non-Omni pairs on the Distributed Exchange (there is no fee for trading Omni pairs). The party removing liquidity from the market will incur a 0.05% fee which will be transferred to the fee cache, and subsequently distributed to holders of the Omni token. - -- Placing a trade where one side of the pair is Omni (#1) or Test-Omni (#2) incurs no fee -- Placing a trade where liquidity is added to the market (i.e. the trade does not immediately execute an existing trade) incurs no fee -- Placing a trade where liquidity is removed from the market (i.e. the trade immediately executes an existing trade) the liquidity taker incurs a 0.05% fee - -See also [fee system JSON-RPC API documentation](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#fee-system). - -This change is identified by `"featureid": 9` and labeled by the GUI as `"Fee system (inc 0.05% fee from trades of non-Omni pairs)"`. - -Send To Owners cross property support -------------------------------------- - -Once activated distributing tokens via the Send To Owners transaction will be permitted to cross properties if using version 1 of the transaction. - -Tokens of property X then may be distributed to holders of property Y. - -There is a significantly increased fee (0.00001000 per recipient) for using version 1 of the STO transaction. The fee remains the same (0.00000001) per recipient for using version 0 of the STO transaction. - -Sending an STO transaction via Omni Core that distributes tokens to holders of the same property will automatically be sent as version 0, and sending a cross-property STO will automatically be sent as version 1. - -The transaction format of new Send To Owners version is as follows: - -| **Field** | **Type** | **Example** | -| ------------------------------ | --------------- | ----------- | -| Transaction version | 16-bit unsigned | 65535 | -| Transaction type | 16-bit unsigned | 65534 | -| Tokens to transfer | 32-bit unsigned | 6 | -| Amount to transfer | 64-bit signed | 700009 | -| Token holders to distribute to | 32-bit unsigned | 23 | - -This change is identified by `"featureid": 10` and labeled by the GUI as `"Cross-property Send To Owners"`. - -Other notable changes -===================== - -Raw payload creation API ------------------------- - -Omni Core 0.0.11 adds support for payload creation via the RPC interface. - -The calls are similar to the send transactions (e.g. `omni_send`), without the requirement for an address or any of the balance checks. - -This allows integrators to build transactions via the [raw transactions interface](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#raw-transactions). - -Other API extensions --------------------- - -An optional parameter `height` can be provided, when using [omni_decodetransaction](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_decodetransaction), which is used to determine the parsing rules. If no `height` is provided, the chain height is used as default. - -When retrieving feature activation transactions with [omni_gettransaction](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_gettransaction), then additional fields are included in the result: `"featureid"`, `"activationblock"` and `"minimumversion"`. - -The Omni Core client version is now also exposed under the new key `"omnicoreversion"`, as well as inter via `"omnicoreversion_int"`, when using [omni_getinfo](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_getinfo). The old key `"mastercoreversion"` remains for compatibility in this version. - -The field `"positioninblock"` was added to RPCs retrieving or listing Omni transactions to provide visibility into the order of an Omni transaction within a block. - -Increased OP_RETURN payload size to 80 bytes --------------------------------------------- - -The maximum payload for OP_RETURN outputs was increased to 80 byte. - -At this point a majority of the network supports 80 byte payloads, so Omni Core can safely use the larger payload size. This can result in cheaper transactions, as there is no fallback to bare multisig encoding. - -Improved consensus checks -------------------------- - -Consensus hashing now covers much more of the state to provide wider coverage of the state. The state of properties, crowdsales and the Distributed Exchange are included in the new consensus hashing process. - -Checkpoints have been updated in Omni Core 0.0.11 to reflect the new consensus hashing algorithm. Seed blocks (for faster initial transaction scanning) and checkpoints are included with Omni Core 0.0.11 up to block 410,000. - -Various bug fixes and clean-ups ------------------------------- - -Various smaller improvements were added Omni Core 0.0.11, such as: - -- Grow balances to fit on "Overview" tab -- Switch to "Bitcoin" tab in "Send" page when handling Bitcoin URIs -- Improve and adjust fee warning threshold when sending transactions -- Fix missing client notification for new feature activations -- Fix Travis CI builds without cache -- Fix syntax error in walletdb key parser -- Fix too-aggressive database clean in block reorganization events -- Fix issues related to `omni_gettransaction` and `getactivedexsells` - -Change log -========== - -The following list includes relevant pull requests merged into this release: -``` -- #226 Upgrade consensus hashing to cover more of the state -- #316 Support providing height for omni_decodetransaction -- #317 Expose feature activation fields when decoding transaction -- #318 Expose Omni Core client version as integer -- #321 Add consensus hash for block 390000 -- #324 Fix and update seed blocks up to block 390000 -- #325 Add capability to generate seed blocks over RPC -- #326 Grow balances to fit on overview tab -- #327 Switch to Bitcoin tab in Send page when handling Bitcoin URIs -- #328 Update and add unit tests for new consensus hashes -- #332 Remove seed blocks for structurally invalid transactions + reformat -- #333 Improve fee warning threshold in GUI -- #334 Update documentation for getseedblocks, getcurrentconsensushash, setautocommit -- #335 Disable logging on Windows to speed up CI RPC tests -- #336 Change the default maximum OP_RETURN size to 80 bytes -- #341 Add omni_getmetadexhash RPC call to hash state of MetaDEx -- #343 Remove pre-OP_RETURN legacy code -- #344 Fix missing client notification for new activations -- #349 Add positioninblock attribute to RPC output for transactions -- #358 Add payload creation to the RPC interface -- #361 Unlock trading of all pairs on the MetaDEx -- #364 Fix Travis builds without cache -- #365 Fix syntax error in walletdb key parser -- #367 Bump version to Omni Core 0.0.11-dev -- #368 Fix too-aggressive database clean in reorg event -- #371 Add consensus checkpoints for blocks 400,000 & 410,000 -- #372 Add seed blocks for 390,000 to 410,000 -- #375 Temporarily disable the trading UI -- #384 Add fee system RPC calls to API doc -- #385 Add RPC documentation for createpayload calls -- #386 Don't warn user about unknown block versions -- #377 Add release notes for Omni Core 0.0.11 -- #376 Bump version to Omni Core 0.0.11-rc1 -- #390 Add cross-property (v1) Send To Owners -- #395 Move test scripts into /src/omnicore/test -- #396 Add workaround for "bytes per sigops" limit -- #400 Change default confirm target to 15 blocks -- #398 Update release notes for 0.0.11-rc2 -- #397 Bump version to Omni Core 0.0.11-rc2 -- #402 Add seed blocks for 410,000 to 420,000 -- #403 Add consensus hash for block 420,000 -- #405 Use uint256 when calculating desired BTC for DEx 1 -- #404 Bump version to Omni Core 0.0.11-rel -- #409 Protect uint256 plain integer math -- #411 Bump version to Omni Core 0.0.11.1-rel -``` - -Credits -======= - -Thanks to everyone who contributed to this release, and especially the Bitcoin Core developers for providing the foundation for Omni Core! diff --git a/src/elysium/doc/release-notes/omnicore-0.0.11.2-release-notes.md b/src/elysium/doc/release-notes/omnicore-0.0.11.2-release-notes.md deleted file mode 100644 index 362a40d690..0000000000 --- a/src/elysium/doc/release-notes/omnicore-0.0.11.2-release-notes.md +++ /dev/null @@ -1,224 +0,0 @@ -Omni Core v0.0.11.2 -=================== - -v0.0.11.2 is a bugfix release which resolves an issue where, in the case where a buyer accepts more than available for sale on the traditional distributed exchange, the RPC API reported an amount higher than available. This release also disables the alert system as per default. - -v0.0.11.1 is a bugfix release which resolves a critical bug in the RPC API whereby under certain circumstances retrieving data about a sell offer may trigger a failsafe and cause the automatic shutdown of the client. - -This version is built on top of v0.0.11, which is a major release and consensus critical in terms of the Omni Layer protocol rules. An upgrade is mandatory, and highly recommended. Prior releases will not be compatible with new behavior in this release. - -Please report bugs using the issue tracker on GitHub: - - https://github.com/OmniLayer/omnicore/issues - -Table of contents -================= - -- [Omni Core v0.0.11.2](#omni-core-v00112) -- [Upgrading and downgrading](#upgrading-and-downgrading) - - [How to upgrade](#how-to-upgrade) - - [Downgrading](#downgrading) - - [Compatibility with Bitcoin Core](#compatibility-with-bitcoin-core) -- [Consensus affecting changes](#consensus-affecting-changes) - - [Trading of all pairs on the Distributed Exchange](#trading-of-all-pairs-on-the-distributed-exchange) - - [Fee distribution system on the Distributed Exchange](#fee-distribution-system-on-the-distributed-exchange) - - [Send to Owners cross property suport](#send-to-owners-cross-property-support) -- [Other notable changes](#other-notable-changes) - - [Raw payload creation API](#raw-payload-creation-api) - - [Other API extensions](#other-api-extensions) - - [Increased OP_RETURN payload size to 80 byte](#increased-op_return-payload-size-to-80-bytes) - - [Improved consensus checks](#improved-consensus-checks) - - [Various bug fixes and clean-ups](#various-bug-fixes-and-clean-ups) -- [Change log](#change-log) -- [Credits](#credits) - -Upgrading and downgrading -========================= - -How to upgrade --------------- - -If you are running Bitcoin Core or an older version of Omni Core, shut it down. Wait until it has completely shut down, then copy the new version of `omnicored`, `omnicore-cli` and `omnicore-qt`. On Microsoft Windows the setup routine can be used to automate these steps. - -During the first startup historical Omni transactions are reprocessed and Omni Core will not be usable for approximately 15 minutes up to two hours. The progress of the initial scan is reported on the console, the GUI and written to the `debug.log`. The scan may be interrupted, but can not be resumed, and then needs to start from the beginning. - -Downgrading ------------ - -Downgrading to an Omni Core version prior 0.0.11 is generally not supported as older versions will not provide accurate information due to the changes in consensus rules. - -Compatibility with Bitcoin Core -------------------------------- - -Omni Core is based on Bitcoin Core 0.10.4 and can be used as replacement for Bitcoin Core. Switching between Omni Core and Bitcoin Core is fully supported at any time. - -Downgrading to a Bitcoin Core version prior 0.10 is not supported due to the new headers-first synchronization. - -Consensus affecting changes -=========================== - -All changes of the consensus rules are enabled by activation transactions. - -Please note, while Omni Core 0.0.11 contains support for several new rules and features they are not enabled immediately and will be activated via the feature activation mechanism described above. - -It follows an overview and a description of the consensus rule changes: - -Trading of all pairs on the Distributed Exchange ------------------------------------------------- - -Once activated trading of any property against any other (within the same ecosystem) will be permitted on the Distributed Exchange. - -Due to this change the existing trading UI in the QT version is no longer suitable and has been disabled for this release. Please use the RPC interface to interact with the Distributed Exchange in this release. The trading UI will be re-enabled in a future version to accommodate non-Omni pair trading. - -This change is identified by `"featureid": 8` and labeled by the GUI as `"Allow trading all pairs on the Distributed Exchange"`. - -Fee distribution system on the Distributed Exchange ---------------------------------------------------- - -Omni Core 0.11 contains a fee caching and distribution system. This system collects small amounts of tokens in a cache until a distribution threshold is reached. Once this distribution threshold (trigger) is reached for a property, the fees in the cache will be distributed proportionally to holders of the Omni (#1) and Test-Omni (#2) tokens based on the percentage of the total Omni tokens owned. - -Once activated fees will be collected from trading of non-Omni pairs on the Distributed Exchange (there is no fee for trading Omni pairs). The party removing liquidity from the market will incur a 0.05% fee which will be transferred to the fee cache, and subsequently distributed to holders of the Omni token. - -- Placing a trade where one side of the pair is Omni (#1) or Test-Omni (#2) incurs no fee -- Placing a trade where liquidity is added to the market (i.e. the trade does not immediately execute an existing trade) incurs no fee -- Placing a trade where liquidity is removed from the market (i.e. the trade immediately executes an existing trade) the liquidity taker incurs a 0.05% fee - -See also [fee system JSON-RPC API documentation](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#fee-system). - -This change is identified by `"featureid": 9` and labeled by the GUI as `"Fee system (inc 0.05% fee from trades of non-Omni pairs)"`. - -Send To Owners cross property support -------------------------------------- - -Once activated distributing tokens via the Send To Owners transaction will be permitted to cross properties if using version 1 of the transaction. - -Tokens of property X then may be distributed to holders of property Y. - -There is a significantly increased fee (0.00001000 per recipient) for using version 1 of the STO transaction. The fee remains the same (0.00000001) per recipient for using version 0 of the STO transaction. - -Sending an STO transaction via Omni Core that distributes tokens to holders of the same property will automatically be sent as version 0, and sending a cross-property STO will automatically be sent as version 1. - -The transaction format of new Send To Owners version is as follows: - -| **Field** | **Type** | **Example** | -| ------------------------------ | --------------- | ----------- | -| Transaction version | 16-bit unsigned | 65535 | -| Transaction type | 16-bit unsigned | 65534 | -| Tokens to transfer | 32-bit unsigned | 6 | -| Amount to transfer | 64-bit signed | 700009 | -| Token holders to distribute to | 32-bit unsigned | 23 | - -This change is identified by `"featureid": 10` and labeled by the GUI as `"Cross-property Send To Owners"`. - -Other notable changes -===================== - -Raw payload creation API ------------------------- - -Omni Core 0.0.11 adds support for payload creation via the RPC interface. - -The calls are similar to the send transactions (e.g. `omni_send`), without the requirement for an address or any of the balance checks. - -This allows integrators to build transactions via the [raw transactions interface](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#raw-transactions). - -Other API extensions --------------------- - -An optional parameter `height` can be provided, when using [omni_decodetransaction](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_decodetransaction), which is used to determine the parsing rules. If no `height` is provided, the chain height is used as default. - -When retrieving feature activation transactions with [omni_gettransaction](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_gettransaction), then additional fields are included in the result: `"featureid"`, `"activationblock"` and `"minimumversion"`. - -The Omni Core client version is now also exposed under the new key `"omnicoreversion"`, as well as inter via `"omnicoreversion_int"`, when using [omni_getinfo](https://github.com/OmniLayer/omnicore/blob/omnicore-0.0.10/src/omnicore/doc/rpc-api.md#omni_getinfo). The old key `"mastercoreversion"` remains for compatibility in this version. - -The field `"positioninblock"` was added to RPCs retrieving or listing Omni transactions to provide visibility into the order of an Omni transaction within a block. - -Increased OP_RETURN payload size to 80 bytes --------------------------------------------- - -The maximum payload for OP_RETURN outputs was increased to 80 byte. - -At this point a majority of the network supports 80 byte payloads, so Omni Core can safely use the larger payload size. This can result in cheaper transactions, as there is no fallback to bare multisig encoding. - -Improved consensus checks -------------------------- - -Consensus hashing now covers much more of the state to provide wider coverage of the state. The state of properties, crowdsales and the Distributed Exchange are included in the new consensus hashing process. - -Checkpoints have been updated in Omni Core 0.0.11 to reflect the new consensus hashing algorithm. Seed blocks (for faster initial transaction scanning) and checkpoints are included with Omni Core 0.0.11 up to block 410,000. - -Various bug fixes and clean-ups ------------------------------- - -Various smaller improvements were added Omni Core 0.0.11, such as: - -- Grow balances to fit on "Overview" tab -- Switch to "Bitcoin" tab in "Send" page when handling Bitcoin URIs -- Improve and adjust fee warning threshold when sending transactions -- Fix missing client notification for new feature activations -- Fix Travis CI builds without cache -- Fix syntax error in walletdb key parser -- Fix too-aggressive database clean in block reorganization events -- Fix issues related to `omni_gettransaction` and `getactivedexsells` - -Change log -========== - -The following list includes relevant pull requests merged into this release: -``` -- #226 Upgrade consensus hashing to cover more of the state -- #316 Support providing height for omni_decodetransaction -- #317 Expose feature activation fields when decoding transaction -- #318 Expose Omni Core client version as integer -- #321 Add consensus hash for block 390000 -- #324 Fix and update seed blocks up to block 390000 -- #325 Add capability to generate seed blocks over RPC -- #326 Grow balances to fit on overview tab -- #327 Switch to Bitcoin tab in Send page when handling Bitcoin URIs -- #328 Update and add unit tests for new consensus hashes -- #332 Remove seed blocks for structurally invalid transactions + reformat -- #333 Improve fee warning threshold in GUI -- #334 Update documentation for getseedblocks, getcurrentconsensushash, setautocommit -- #335 Disable logging on Windows to speed up CI RPC tests -- #336 Change the default maximum OP_RETURN size to 80 bytes -- #341 Add omni_getmetadexhash RPC call to hash state of MetaDEx -- #343 Remove pre-OP_RETURN legacy code -- #344 Fix missing client notification for new activations -- #349 Add positioninblock attribute to RPC output for transactions -- #358 Add payload creation to the RPC interface -- #361 Unlock trading of all pairs on the MetaDEx -- #364 Fix Travis builds without cache -- #365 Fix syntax error in walletdb key parser -- #367 Bump version to Omni Core 0.0.11-dev -- #368 Fix too-aggressive database clean in reorg event -- #371 Add consensus checkpoints for blocks 400,000 & 410,000 -- #372 Add seed blocks for 390,000 to 410,000 -- #375 Temporarily disable the trading UI -- #384 Add fee system RPC calls to API doc -- #385 Add RPC documentation for createpayload calls -- #386 Don't warn user about unknown block versions -- #377 Add release notes for Omni Core 0.0.11 -- #376 Bump version to Omni Core 0.0.11-rc1 -- #390 Add cross-property (v1) Send To Owners -- #395 Move test scripts into /src/omnicore/test -- #396 Add workaround for "bytes per sigops" limit -- #400 Change default confirm target to 15 blocks -- #398 Update release notes for 0.0.11-rc2 -- #397 Bump version to Omni Core 0.0.11-rc2 -- #402 Add seed blocks for 410,000 to 420,000 -- #403 Add consensus hash for block 420,000 -- #405 Use uint256 when calculating desired BTC for DEx 1 -- #404 Bump version to Omni Core 0.0.11-rel -- #409 Protect uint256 plain integer math -- #411 Bump version to Omni Core 0.0.11.1-rel -- #419 Add consensus hash for block 430,000 -- #420 Add seed blocks for 420,000 to 430,000 -- #421 Fix edge case of DEx 1 over-accepts -- #422 Disable alert system as per default -- #423 Bump version to Omni Core 0.0.11.2-rel -``` - -Credits -======= - -Thanks to everyone who contributed to this release, and especially the Bitcoin Core developers for providing the foundation for Omni Core! diff --git a/src/elysium/doc/release-notes/omnicore-0.0.12-release-notes.md b/src/elysium/doc/release-notes/omnicore-0.0.12-release-notes.md deleted file mode 100644 index 61f4e1c486..0000000000 --- a/src/elysium/doc/release-notes/omnicore-0.0.12-release-notes.md +++ /dev/null @@ -1,117 +0,0 @@ -Omni Core v0.0.12 -================= - -v0.0.12 greatly improves Omni Core's performance during the initial parsing, and it includes new logic for the fee distribution system, as well as for cross-property send-to-owner transactions. - -v0.0.12 is a major release and consensus critical in terms of the Omni Layer protocol rules. An upgrade is mandatory, and highly recommended. Prior releases will not be compatible with new behavior in this release. - -Please report bugs using the issue tracker on GitHub: - - https://github.com/OmniLayer/omnicore/issues - -Table of contents -================= - -- [Omni Core v0.0.12](#omni-core-v0012) -- [Upgrading and downgrading](#upgrading-and-downgrading) - - [How to upgrade](#how-to-upgrade) - - [Downgrading](#downgrading) - - [Compatibility with Bitcoin Core](#compatibility-with-bitcoin-core) - - [Consensus affecting changes](#consensus-affecting-changes) - - [Fee distribution system on the Distributed Exchange](#fee-distribution-system-on-the-distributed-exchange) - - [Send to Owners cross property suport](#send-to-owners-cross-property-support) -- [Notable changes](#notable-changes) - - [Performance improvements during initial parsing](#performance-improvements-during-initial-parsing) -- [Change log](#change-log) -- [Credits](#credits) - -Upgrading and downgrading -========================= - -How to upgrade --------------- - -If you are running Bitcoin Core or an older version of Omni Core, shut it down. Wait until it has completely shut down, then copy the new version of `omnicored`, `omnicore-cli` and `omnicore-qt`. On Microsoft Windows the setup routine can be used to automate these steps. - -During the first startup historical Omni transactions are reprocessed and Omni Core will not be usable for approximately 15 minutes up to two hours. The progress of the initial scan is reported on the console, the GUI and written to the `debug.log`. The scan may be interrupted, but can not be resumed, and then needs to start from the beginning. - -Downgrading ------------ - -Downgrading to an Omni Core version prior 0.0.12 is generally not supported as older versions will not provide accurate information due to the changes in consensus rules. - -Compatibility with Bitcoin Core -------------------------------- - -Omni Core is based on Bitcoin Core 0.10.4 and can be used as replacement for Bitcoin Core. Switching between Omni Core and Bitcoin Core is fully supported at any time. - -Downgrading to a Bitcoin Core version prior 0.10 is not supported due to the new headers-first synchronization. - -Consensus affecting changes -=========================== - -All changes of the consensus rules are enabled by activation transactions. - -Please note, while Omni Core 0.0.12 contains support for several new rules and features they are not enabled immediately and will be activated via the feature activation mechanism described above. - -It follows an overview and a description of the consensus rule changes: - -Fee distribution system on the Distributed Exchange ---------------------------------------------------- - -Omni Core 0.0.12 contains a fee caching and distribution system. This system collects small amounts of tokens in a cache until a distribution threshold is reached. Once this distribution threshold (trigger) is reached for a property, the fees in the cache will be distributed proportionally to holders of the Omni (#1) and Test-Omni (#2) tokens based on the percentage of the total Omni tokens owned. - -Once activated fees will be collected from trading of non-Omni pairs on the Distributed Exchange (there is no fee for trading Omni pairs). The party removing liquidity from the market will incur a 0.05% fee which will be transferred to the fee cache, and subsequently distributed to holders of the Omni token. - -- Placing a trade where one side of the pair is Omni (#1) or Test-Omni (#2) incurs no fee -- Placing a trade where liquidity is added to the market (i.e. the trade does not immediately execute an existing trade) incurs no fee -- Placing a trade where liquidity is removed from the market (i.e. the trade immediately executes an existing trade) the liquidity taker incurs a 0.05% fee - -See also [fee system JSON-RPC API documentation](https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md#fee-system). - -This change is identified by `"featureid": 9` and labeled by the GUI as `"Fee system (inc 0.05% fee from trades of non-Omni pairs)"`. - -Send To Owners cross property support -------------------------------------- - -Once activated distributing tokens via the Send To Owners transaction will be permitted to cross properties if using version 1 of the transaction. - -Tokens of property X then may be distributed to holders of property Y. - -There is a significantly increased fee (0.00001000 per recipient) for using version 1 of the STO transaction. The fee remains the same (0.00000001) per recipient for using version 0 of the STO transaction. - -Sending an STO transaction via Omni Core that distributes tokens to holders of the same property will automatically be sent as version 0, and sending a cross-property STO will automatically be sent as version 1. - -The transaction format of new Send To Owners version is as follows: - -| **Field** | **Type** | **Example** | -| ------------------------------ | --------------- | ----------- | -| Transaction version | 16-bit unsigned | 65535 | -| Transaction type | 16-bit unsigned | 65534 | -| Tokens to transfer | 32-bit unsigned | 6 | -| Amount to transfer | 64-bit signed | 700009 | -| Token holders to distribute to | 32-bit unsigned | 23 | - -This change is identified by `"featureid": 10` and labeled by the GUI as `"Cross-property Send To Owners"`. - -Notable changes -=============== - -Performance improvements during initial parsing ------------------------------------------------ - -Due to various improvements and optimizations, the initial parsing process, when running Omni Core the first time, or when starting Omni Core with `-startclean` flag, is faster by a factor of up to 10x. The improvements also have a positive impact on the time, when processing a new block. - -Change log -========== - -The following list includes relevant pull requests merged into this release: -``` -- #449 Back port fixes & improvements from develop -- #455 Bump version to Omni Core 0.0.12.0-rel -``` - -Credits -======= - -Thanks to everyone who contributed to this release, and especially the Bitcoin Core developers for providing the foundation for Omni Core! diff --git a/src/elysium/doc/release-notes/omnicore-0.2.0-release-notes.md b/src/elysium/doc/release-notes/omnicore-0.2.0-release-notes.md deleted file mode 100644 index d091fb9b75..0000000000 --- a/src/elysium/doc/release-notes/omnicore-0.2.0-release-notes.md +++ /dev/null @@ -1,254 +0,0 @@ -Omni Core v0.2.0 -=================== - -v0.2.0 is a release with minor changes and improvements based on Bitcoin Core 0.13.2. - -This version is built on top of v0.0.12, which is a major release and consensus critical in terms of the Omni Layer protocol rules. If you are using an older version of Omni Core than v0.0.12, an upgrade is mandatory, and highly recommended. Prior releases will not be compatible with new behavior in this release. - -Please report bugs using the issue tracker on GitHub: - - https://github.com/OmniLayer/omnicore/issues - -Table of contents -================= - -- [Omni Core v0.2.0](#omni-core-v020) -- [Upgrading and downgrading](#upgrading-and-downgrading) - - [How to upgrade](#how-to-upgrade) - - [Downgrading](#downgrading) - - [Compatibility with Bitcoin Core](#compatibility-with-bitcoin-core) -- [Imported changes and notes](#imported-changes-and-notes) - - [Upgrade to Bitcoin Core 0.13.2](#upgrade-to-bitcoin-core-0132) - - [Important transaction fee behavior changes](#important-transaction-fee-behavior-changes) - - [API changes](#api-changes) - - [New project versioning scheme](#new-project-versioning-scheme) - - [New project branch structure](#new-project-branch-structure) -- [Consensus affecting changes](#consensus-affecting-changes) - - [Fee distribution system on the Distributed Exchange](#fee-distribution-system-on-the-distributed-exchange) - - [Send to Owners cross property suport](#send-to-owners-cross-property-support) -- [Notable changes](#notable-changes) - - [Avoid selection of uneconomic UTXO during transaction creation](#avoid-selection-of-uneconomic-utxo-during-transaction-creation) - - [Performance improvements during initial parsing](#performance-improvements-during-initial-parsing) - - [New checkpoints and seed blocks up to block 460,000](#new-checkpoints-and-seed-blocks-up-to-block-460000) - - [Easy access to specific consensus hashes when parsing](#easy-access-to-specific-consensus-hashes-when-parsing) - - [Various bug fixes and improvements](#various-bug-fixes-and-improvements) -- [Change log](#change-log) -- [Credits](#credits) - -Upgrading and downgrading -========================= - -How to upgrade --------------- - -If you are running Bitcoin Core or an older version of Omni Core, shut it down. Wait until it has completely shut down, then copy the new version of `omnicored`, `omnicore-cli` and `omnicore-qt`. On Microsoft Windows the setup routine can be used to automate these steps. - -During the first startup historical Omni transactions are reprocessed and Omni Core will not be usable for approximately 15 minutes up to two hours. The progress of the initial scan is reported on the console, the GUI and written to the `debug.log`. The scan may be interrupted, but can not be resumed, and then needs to start from the beginning. - -Downgrading ------------ - -Downgrading to an Omni Core version prior 0.0.12 is generally not supported as older versions will not provide accurate information due to the changes in consensus rules. Downgrading to Omni Core 0.0.12 can require a reindex of the blockchain, and is not recommended. - -Compatibility with Bitcoin Core -------------------------------- - -Omni Core is based on Bitcoin Core 0.13.2 and can be used as replacement for Bitcoin Core. Switching between Omni Core and Bitcoin Core is fully supported at any time. - -Downgrading to a Bitcoin Core version prior 0.12 may not be supported due to the obfuscation of the blockchain database. - -Downgrading to a Bitcoin Core version prior 0.10 is not supported due to the new headers-first synchronization. - -Imported changes and notes -========================== - -Upgrade to Bitcoin Core 0.13.2 ------------------------------- - -The underlying base of Omni Core was upgraded from Bitcoin Core 0.10.4 to Bitcoin Core 0.13.2. - -Please see the following release notes for further details: - -- [Release notes for Bitcoin Core 0.11.0](https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.11.0.md) -- [Release notes for Bitcoin Core 0.11.1](https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.11.1.md) -- [Release notes for Bitcoin Core 0.11.2](https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.11.2.md) -- [Release notes for Bitcoin Core 0.12.0](https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.12.0.md) -- [Release notes for Bitcoin Core 0.12.1](https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.12.1.md) -- [Release notes for Bitcoin Core 0.13.0](https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.13.0.md) -- [Release notes for Bitcoin Core 0.13.1](https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.13.1.md) -- [Release notes for Bitcoin Core 0.13.2](https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.13.2.md) - -Important transaction fee behavior changes ------------------------------------------- - -Earlier versions of Omni Core (prior to 0.2.0) used Bitcoin Core 0.10.x as a base. Omni Core 0.2.0 however is based on a much newer version of Bitcoin Core (0.13.2) and thus inherits various changes and improvements to the handling of fees that have been added to Bitcoin Core over time. - -It is highly recommended that users of Omni Core consider these fee changes and their chosen fee settings when upgrading to Omni Core 0.2.0, and test thoroughly to ensure that fee behavior is desirable and as expected. - -Consideration of the modified behavior for the `-paytxfee` setting is especially important. Earlier versions of Bitcoin Core (and thus earlier versions of Omni Core prior to 0.2.0) would round the size of the transaction upwards to the nearest kilobyte when calculating the fee (for example a 250 byte transaction would be rounded up to 1 kB). This issue has been resolved in newer versions of Bitcoin Core, and so Omni Core 0.2.0 will no longer perform this rounding when calculating the fee. A comparison of the behaviors can be shown in the following, where an example `paytxfee` value of 0.001 BTC/kB has been set: - -- Omni Core prior to 0.2.0: A transaction with a size of 250 bytes will be rounded up to 1 kB, and so a fee of 0.001 BTC will be used -- Omni Core 0.2.0: A transaction with a size of 250 bytes will not be rounded, and so a fee of 0.00025 BTC will be used - -It is also worth noting that the fee estimation algorithms were updated, and thus the fees chosen when using `-txconfirmtarget` (along with the output of the `estimatefee` RPC) will likely be different in Omni Core 0.2.0 when compared to prior versions. - -API changes ------------ - -The behavior of the RPC [omni_gettradehistoryforaddress](https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md#omni_gettradehistoryforaddress) was amended to return newest transactions first instead of oldest. - -New project versioning scheme ------------------------------ - -Starting with this version of Omni Core, the versioning scheme becomes more intuitive, as it uses MAJOR.MINOR.PATCH from now on, whereby MAJOR indicates consensus affecting changes or other non-backwards-compatible changes, MINOR indicates new functionality in a backwards-compatible manner, and PATCH is used to indicate backwards-compatible bug fixes. - -New project branch structure ----------------------------- - -The latest stable version of Omni Core can be found in the [master](https://github.com/OmniLayer/omnicore/tree/master) branch on GitHub, while the version under development can be found in the [develop](https://github.com/OmniLayer/omnicore/tree/develop) branch. This provides a cleaner seperation of source code. - - -Consensus affecting changes -=========================== - -All changes of the consensus rules are enabled by activation transactions. - -Please note, while Omni Core 0.2.0 contains support for several new rules and features they are not enabled immediately and will be activated via the feature activation mechanism described above. - -It follows an overview and a description of the consensus rule changes: - -Fee distribution system on the Distributed Exchange ---------------------------------------------------- - -Omni Core 0.2.0 contains a fee caching and distribution system. This system collects small amounts of tokens in a cache until a distribution threshold is reached. Once this distribution threshold (trigger) is reached for a property, the fees in the cache will be distributed proportionally to holders of the Omni (#1) and Test-Omni (#2) tokens based on the percentage of the total Omni tokens owned. - -Once activated fees will be collected from trading of non-Omni pairs on the Distributed Exchange (there is no fee for trading Omni pairs). The party removing liquidity from the market will incur a 0.05% fee which will be transferred to the fee cache, and subsequently distributed to holders of the Omni token. - -- Placing a trade where one side of the pair is Omni (#1) or Test-Omni (#2) incurs no fee -- Placing a trade where liquidity is added to the market (i.e. the trade does not immediately execute an existing trade) incurs no fee -- Placing a trade where liquidity is removed from the market (i.e. the trade immediately executes an existing trade) the liquidity taker incurs a 0.05% fee - -See also [fee system JSON-RPC API documentation](https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md#fee-system). - -This change is identified by `"featureid": 9` and labeled by the GUI as `"Fee system (inc 0.05% fee from trades of non-Omni pairs)"`. - -Send To Owners cross property support -------------------------------------- - -Once activated distributing tokens via the Send To Owners transaction will be permitted to cross properties if using version 1 of the transaction. - -Tokens of property X then may be distributed to holders of property Y. - -There is a significantly increased fee (0.00001000 per recipient) for using version 1 of the STO transaction. The fee remains the same (0.00000001) per recipient for using version 0 of the STO transaction. - -Sending an STO transaction via Omni Core that distributes tokens to holders of the same property will automatically be sent as version 0, and sending a cross-property STO will automatically be sent as version 1. - -The transaction format of new Send To Owners version is as follows: - -| **Field** | **Type** | **Example** | -| ------------------------------ | --------------- | ----------- | -| Transaction version | 16-bit unsigned | 65535 | -| Transaction type | 16-bit unsigned | 65534 | -| Tokens to transfer | 32-bit unsigned | 6 | -| Amount to transfer | 64-bit signed | 700009 | -| Token holders to distribute to | 32-bit unsigned | 23 | - -This change is identified by `"featureid": 10` and labeled by the GUI as `"Cross-property Send To Owners"`. - -Notable changes -=============== - -Avoid selection of uneconomic UTXO during transaction creation --------------------------------------------------------------- - -In earlier version of Omni Core (prior to 0.2.0), when creating transactions with the Qt UI or the JSON-RPC API (for example with `omni_send`), then the coin selection algorithm may have selected unspent outputs, which are not economic to spend. This may have caused the creation of larger and more expensive transactions than necessary. - -In Omni Core 0.2.0 this is addressed by excluding inputs during the transaction creation, which are more expensive to spend than they are worth. Please note the exclusion is directly related to the fee related configuration options of Omni Core, such as `-paytxfee` or `-txconfirmtarget`. - -Performance improvements during initial parsing ------------------------------------------------ - -Due to various improvements and optimizations, the initial parsing process, when running Omni Core the first time, or when starting Omni Core with `-startclean` flag, is faster by a factor of up to 10x. The improvements also have a positive impact on the time, when processing a new block. - -New checkpoints and seed blocks up to block 460,000 ---------------------------------------------------- - -To further speed up the inital parsing process, blocks without Omni transactions are skipped up until block 460,000. To avoid relying on a hardcoded list of seed blocks, Omni Core can be started with `-omniseedblockfilter=0`. - -Easy access to specific consensus hashes when parsing ------------------------------------------------------ - -Previously to confirm a consensus hash for a particular block it was required to enable `-omnidebug=consensus_hash_every_block` during parsing to log the hash for every block which caused a significant slow down due to the extra work involved. - -This leads to circumstances where to validate a single consensus hash it is neccessary to perform vastly more work than necessary. - -This version adds a `-omnishowblockconsensushash` startup option which can be used to generate consensus hashes for specific blocks. - -For example, to validate the checkpoint for block 450,000 without using seed block filtering we can use: - -``` -./omnicored --startclean --omniseedblockfilter=false --omnishowblockconsensushash=450000 -``` - -Which will then cause a consensus hash to be generated for the corresponding block and written to the log. Multiple instances of the parameter can be used to specify multiple blocks to generate consensus hashes for. - -Various bug fixes and improvements ----------------------------------- - -Various smaller improvements were added Omni Core 0.2.0, such as: - -- Fix incorrect value from getTotalTokens when fees are cached -- Remove forwarding of setgenerate to generate -- Reduce test time to avoid hitting Travis CI time limit -- Sanitize RPC responses and replace non-UTF-8 compliant characters -- Set minimum fee distribution threshold and protect against empty distributions -- Check for fee distribution when total number of tokens is changed -- Fix missing include of test utils header -- Fix two Omni Core related build warnings -- Automatically remove stale pending transactions -- Relax data type checks of omni_createrawtx_change -- Fix possible lock contention in omni_getactivedexsells -- Remove managed property check in Change Issuer RPC -- Hardcode activations up to block 438500 -- Fix a number of bugs in the QT UI -- Lock fetching and processing inputs while parsing -- Run RPC tests with explicitly defined datadir and minimum logging - -Change log -========== - -The following list includes relevant pull requests merged into this release: -``` -- #436 Improve parsing performance -- #439 Fix incorrect value from getTotalTokens when fees are cached -- #440 Remove forwarding of setgenerate to generate -- #441 Reduce test time to avoid hitting Travis CI time limit -- #443 Sanitize RPC responses and replace non-UTF-8 compliant characters -- #447 Set minimum fee distribution threshold and protect against empty distributions -- #448 Check for fee distribution when total number of tokens is changed -- #451 Fix missing include of test utils header -- #450 Port code base to Bitcoin Core 0.13.2 -- #453 Update splash screen to be similar to 0.0.11 -- #454 Fix two Omni Core related build warnings -- #458 Add checkpoint for block 450,000 -- #457 Add seed blocks for 440,000 to 450,000 -- #456 Provide easy access to specific consensus hashes when parsing -- #460 Show newest transactions for omni_gettradehistoryforaddress -- #463 Automatically remove stale pending transactions -- #464 Relax data type checks of omni_createrawtx_change -- #465 Fix possible lock contention in omni_getactivedexsells -- #466 Add consensus hash for block 460,000 -- #467 Add seed blocks for 450,000 to 460,000 -- #468 Remove managed property check in Change Issuer RPC -- #470 Hardcode activations up to block 438500 -- #471 Fix a number of bugs in the QT UI -- #472 Lock fetching and processing inputs while parsing -- #473 Avoid selecting uneconomic UTXO during transaction creation -- #474 Run RPC tests with explicitly defined datadir and minimum logging -- #460 Bump version to Omni Core 0.2.0 and add release notes -``` - -Credits -======= - -Thanks to everyone who contributed to this release, and especially the Bitcoin Core developers for providing the foundation for Omni Core! diff --git a/src/elysium/doc/rpc-api.md b/src/elysium/doc/rpc-api.md deleted file mode 100644 index fc379d6ddd..0000000000 --- a/src/elysium/doc/rpc-api.md +++ /dev/null @@ -1,2370 +0,0 @@ -JSON-RPC API -============ - -Omni Core is a fork of Bitcoin Core, with Omni Protocol feature support added as a new layer of functionality on top. As such interacting with the API is done in the same manner (JSON-RPC) as Bitcoin Core, simply with additional RPCs available for utilizing Omni Protocol features. - -As all existing Bitcoin Core functionality is inherent to Omni Core, the RPC port by default remains as `8332` as per Bitcoin Core. If you wish to run Omni Core in tandem with Bitcoin Core (eg. via a separate datadir) you may utilize the `-rpcport` option to nominate an alternative port number. - -All available commands can be listed with `"help"`, and information about a specific command can be retrieved with `"help "`. - -*Please note: this document may not always be up-to-date. There may be errors, omissions or inaccuracies present.* - - -## Transaction creation - -The RPCs for transaction creation can be used to create and broadcast Omni Protocol transactions. - -A hash of the broadcasted transaction is returned as result. - -### omni_send - -Create and broadcast a simple send transaction. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `toaddress` | string | required | the address of the receiver | -| `propertyid` | number | required | the identifier of the tokens to send | -| `amount` | string | required | the amount to send | -| `redeemaddress` | string | optional | an address that can spend the transaction dust (sender by default) | -| `referenceamount` | string | optional | a bitcoin amount that is sent to the receiver (minimal by default) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_send" "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY" "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa" 1 "100.0" -``` - ---- - -### omni_senddexsell - -Place, update or cancel a sell offer on the traditional distributed OMNI/BTC exchange. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `propertyidforsale` | number | required | the identifier of the tokens to list for sale (must be `1` for `OMNI` or `2`for `TOMNI`) | -| `amountforsale` | string | required | the amount of tokens to list for sale | -| `amountdesired` | string | required | the amount of bitcoins desired | -| `paymentwindow` | number | required | a time limit in blocks a buyer has to pay following a successful accepting order | -| `minacceptfee` | string | required | a minimum mining fee a buyer has to pay to accept the offer | -| `action` | number | required | the action to take (`1` for new offers, `2` to update, `3` to cancel) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_senddexsell" "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa" 1 "1.5" "0.75" 25 "0.0005" 1 -``` - ---- - -### omni_senddexaccept - -Create and broadcast an accept offer for the specified token and amount. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `toaddress` | string | required | the address of the seller | -| `propertyid` | number | required | the identifier of the token to purchase | -| `amount` | string | required | the amount to accept | -| `override` | boolean | required | override minimum accept fee and payment window checks (use with caution!) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_senddexaccept" \ - "35URq1NN3xL6GeRKUP6vzaQVcxoJiiJKd8" "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa" 1 "15.0" -``` - ---- - -### omni_sendissuancecrowdsale - -Create new tokens as crowdsale. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `ecosystem` | number | required | the ecosystem to create the tokens in (`1` for main ecosystem, `2` for test ecosystem) | -| `type` | number | required | the type of the tokens to create: (`1` for indivisible tokens, `2` for divisible tokens) | -| `previousid` | number | required | an identifier of a predecessor token (`0` for new crowdsales) | -| `category` | string | required | a category for the new tokens (can be `""`) | -| `subcategory` | string | required | a subcategory for the new tokens (can be `""`) | -| `name` | string | required | the name of the new tokens to create | -| `url` | string | required | an URL for further information about the new tokens (can be `""`) | -| `data` | string | required | a description for the new tokens (can be `""`) | -| `propertyiddesired` | number | required | the identifier of a token eligible to participate in the crowdsale | -| `tokensperunit` | string | required | the amount of tokens granted per unit invested in the crowdsale | -| `deadline` | number | required | the deadline of the crowdsale as Unix timestamp | -| `earlybonus` | number | required | an early bird bonus for participants in percent per week | -| `issuerpercentage` | number | required | a percentage of tokens that will be granted to the issuer | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendissuancecrowdsale" \ - "3JYd75REX3HXn1vAU83YuGfmiPXW7BpYXo" 2 1 0 "Companies" "Bitcoin Mining" \ - "Quantum Miner" "" "" 2 "100" 1483228800 30 2 -``` - ---- - -### omni_sendissuancefixed - -Create new tokens with fixed supply. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `ecosystem` | number | required | the ecosystem to create the tokens in (`1` for main ecosystem, `2` for test ecosystem) | -| `type` | number | required | the type of the tokens to create: (`1` for indivisible tokens, `2` for divisible tokens) | -| `previousid` | number | required | an identifier of a predecessor token (`0` for new tokens) | -| `category` | string | required | a category for the new tokens (can be `""`) | -| `subcategory` | string | required | a subcategory for the new tokens (can be `""`) | -| `name` | string | required | the name of the new tokens to create | -| `url` | string | required | an URL for further information about the new tokens (can be `""`) | -| `data` | string | required | a description for the new tokens (can be `""`) | -| `amount` | string | required | the number of tokens to create | -| `tokensperunit` | string | required | the amount of tokens granted per unit invested in the crowdsale | -| `deadline` | number | required | the deadline of the crowdsale as Unix timestamp | -| `earlybonus` | number | required | an early bird bonus for participants in percent per week | -| `issuerpercentage` | number | required | a percentage of tokens that will be granted to the issuer | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendissuancefixed" \ - "3Ck2kEGLJtZw9ENj2tameMCtS3HB7uRar3" 2 1 0 "Companies" "Bitcoin Mining" \ - "Quantum Miner" "" "" "1000000" -``` - ---- - -### omni_sendissuancemanaged - -Create new tokens with manageable supply. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `ecosystem` | number | required | the ecosystem to create the tokens in (`1` for main ecosystem, `2` for test ecosystem) | -| `type` | number | required | the type of the tokens to create: (`1` for indivisible tokens, `2` for divisible tokens) | -| `previousid` | number | required | an identifier of a predecessor token (`0` for new tokens) | -| `category` | string | required | a category for the new tokens (can be `""`) | -| `subcategory` | string | required | a subcategory for the new tokens (can be `""`) | -| `name` | string | required | the name of the new tokens to create | -| `url` | string | required | an URL for further information about the new tokens (can be `""`) | -| `data` | string | required | a description for the new tokens (can be `""`) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendissuancemanaged" \ - "3HsJvhr9qzgRe3ss97b1QHs38rmaLExLcH" 2 1 0 "Companies" "Bitcoin Mining" "Quantum Miner" "" "" -``` - ---- - -### omni_sendsto - -Create and broadcast a send-to-owners transaction. - -**Arguments:** - -| Name | Type | Presence | Description | -|------------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `propertyid` | number | required | the identifier of the tokens to distribute | -| `amount` | string | required | the amount to distribute | -| `redeemaddress` | string | optional | an address that can spend the transaction dust (sender by default) | -| `distributionproperty` | number | optional | the identifier of the property holders to distribute to | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendsto" \ - "32Z3tJccZuqQZ4PhJR2hxHC3tjgjA8cbqz" "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa" 3 "5000" -``` - ---- - -### omni_sendgrant - -Issue or grant new units of managed tokens. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `toaddress` | string | required | the receiver of the tokens (sender by default, can be `""`) | -| `propertyid` | number | required | the identifier of the tokens to grant | -| `amount` | string | required | the amount of tokens to create | -| `memo` | string | optional | a text note attached to this transaction (none by default) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendgrant" "3HsJvhr9qzgRe3ss97b1QHs38rmaLExLcH" "" 51 "7000" -``` - ---- - -### omni_sendrevoke - -Revoke units of managed tokens. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `propertyid` | number | required | the identifier of the tokens to revoke | -| `amount` | string | required | the amount of tokens to revoke | -| `memo` | string | optional | a text note attached to this transaction (none by default) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendrevoke" "3HsJvhr9qzgRe3ss97b1QHs38rmaLExLcH" "" 51 "100" -``` - ---- - -### omni_sendclosecrowdsale - -Manually close a crowdsale. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address associated with the crowdsale to close | -| `propertyid` | number | required | the identifier of the crowdsale to close | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendclosecrowdsale" "3JYd75REX3HXn1vAU83YuGfmiPXW7BpYXo" 70 -``` - ---- - -### omni_sendtrade - -Place a trade offer on the distributed token exchange. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to trade with | -| `propertyidforsale` | number | required | the identifier of the tokens to list for sale | -| `amountforsale` | string | required | the amount of tokens to list for sale | -| `propertiddesired` | number | required | the identifier of the tokens desired in exchange | -| `amountdesired` | string | required | the amount of tokens desired in exchange | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendtrade" "3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR" 31 "250.0" 1 "10.0" -``` - ---- - -### omni_sendcanceltradesbyprice - -Cancel offers on the distributed token exchange with the specified price. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to trade with | -| `propertyidforsale` | number | required | the identifier of the tokens listed for sale | -| `amountforsale` | string | required | the amount of tokens to listed for sale | -| `propertiddesired` | number | required | the identifier of the tokens desired in exchange | -| `amountdesired` | string | required | the amount of tokens desired in exchange | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendcanceltradesbyprice" "3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR" 31 "100.0" 1 "5.0" -``` - ---- - -### omni_sendcanceltradesbypair - -Cancel all offers on the distributed token exchange with the given currency pair. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to trade with | -| `propertyidforsale` | number | required | the identifier of the tokens listed for sale | -| `propertiddesired` | number | required | the identifier of the tokens desired in exchange | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendcanceltradesbypair" "3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR" 1 31 -``` - ---- - -### omni_sendcancelalltrades - -Cancel all offers on the distributed token exchange. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to trade with | -| `ecosystem` | number | required | the ecosystem of the offers to cancel (`1` for main ecosystem, `2` for test ecosystem) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendcancelalltrades" "3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR" 1 -``` - ---- - -### omni_sendchangeissuer - -Change the issuer on record of the given tokens. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address associated with the tokens | -| `toaddress ` | string | required | the address to transfer administrative control to | -| `propertyid` | number | required | the identifier of the tokens | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendchangeissuer" \ - "1ARjWDkZ7kT9fwjPrjcQyvbXDkEySzKHwu" "3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs" 3 -``` - ---- - -### omni_sendall - -Transfers all available tokens in the given ecosystem to the recipient. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `toaddress ` | string | required | the address of the receiver | -| `ecosystem` | number | required | the ecosystem of the tokens to send (`1` for main ecosystem, `2` for test ecosystem) | -| `redeemaddress` | string | optional | an address that can spend the transaction dust (sender by default) | -| `referenceamount` | string | optional | a bitcoin amount that is sent to the receiver (minimal by default) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendall" "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY" "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa" 2 -``` - ---- - -### omni_sendenablefreezing - -Enables address freezing for a centrally managed property. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from (must be issuer of a managed property) | -| `propertyid` | number | required | the identifier of the tokens | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendenablefreezing" "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY" 2 -``` - ---- - -### omni_senddisablefreezing - -Disables address freezing for a centrally managed property. - -IMPORTANT NOTE: Disabling freezing for a property will UNFREEZE all frozen addresses for that property! - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from (must be issuer of a managed property) | -| `propertyid` | number | required | the identifier of the tokens | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_senddisablefreezing" "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY" 2 -``` - ---- - -### omni_sendfreeze - -Freeze an address for a centrally managed token. - -Note: Only the issuer may freeze tokens, and only if the token is of the managed type with the freezing option enabled. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from (must be issuer of a managed property with freezing enabled | -| `toaddress` | string | required | the address to freeze | -| `propertyid` | number | required | the identifier of the tokens to freeze | -| `amount` | string | required | the amount to freeze (note: currently unused, frozen addresses cannot transact the property) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendfreeze" "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY" "3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs" 2 1000 -``` - ---- - -### omni_sendunfreeze - -Unfreeze an address for a centrally managed token. - -Note: Only the issuer may unfreeze tokens - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from (must be issuer of a managed property with freezing enabled | -| `toaddress` | string | required | the address to unfreeze | -| `propertyid` | number | required | the identifier of the tokens to unfreeze | -| `amount` | string | required | the amount to unfreeze (note: currently unused | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendunfreeze" "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY" "3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs" 2 1000 -``` - ---- - -### omni_sendrawtx - -Broadcasts a raw Omni Layer transaction. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `fromaddress` | string | required | the address to send from | -| `rawtransaction` | string | required | the hex-encoded raw transaction | -| `referenceaddress` | string | optional | a reference address (none by default) | -| `redeemaddress` | string | optional | an address that can spend the transaction dust (sender by default) | -| `referenceamount` | string | optional | a bitcoin amount that is sent to the receiver (minimal by default) | - -**Result:** -```js -"hash" // (string) the hex-encoded transaction hash -``` - -**Example:** - -```bash -$ omnicore-cli "omni_sendrawtx" \ - "1MCHESTptvd2LnNp7wmr2sGTpRomteAkq8" "000000000000000100000000017d7840" \ - "1EqTta1Rt8ixAA32DuC29oukbsSWU62qAV" -``` - ---- - - -## Data retrieval - -The RPCs for data retrieval can be used to get information about the state of the Omni ecosystem. - -### omni_getinfo - -Returns various state information of the client and protocol. - -**Arguments:** - -*None* - -**Result:** -```js -Result: -{ - "omnicoreversion_int" : xxxxxxx, // (number) client version as integer - "omnicoreversion" : "x.x.x.x-xxx", // (string) client version - "mastercoreversion" : "x.x.x.x-xxx", // (string) client version (DEPRECIATED) - "bitcoincoreversion" : "x.x.x", // (string) Bitcoin Core version - "commitinfo" : "xxxxxxx", // (string) build commit identifier - "block" : nnnnnn, // (number) index of the last processed block - "blocktime" : nnnnnnnnnn, // (number) timestamp of the last processed block - "blocktransactions" : nnnn, // (number) Omni transactions found in the last processed block - "totaltransactions" : nnnnnnnn, // (number) Omni transactions processed in total - "alerts" : [ // (array of JSON objects) active protocol alert (if any) - { - "alerttype" : n // (number) alert type as integer - "alerttype" : "xxx" // (string) alert type (can be "alertexpiringbyblock", "alertexpiringbyblocktime", "alertexpiringbyclientversion" or "error") - "alertexpiry" : "nnnnnnnnnn" // (string) expiration criteria (can refer to block height, timestamp or client verion) - "alertmessage" : "xxx" // (string) information about the alert - }, - ... - ] -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getinfo" -``` - ---- - -### omni_getbalance - -Returns the token balance for a given address and property. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `address` | string | required | the address | -| `propertyid` | number | required | the property identifier | - -**Result:** -```js -{ - "balance" : "n.nnnnnnnn", // (string) the available balance of the address - "reserved" : "n.nnnnnnnn", // (string) the amount reserved by sell offers and accepts - "frozen" : "n.nnnnnnnn" // (string) the amount frozen by the issuer (applies to managed properties only) -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getbalance", "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P" 1 -``` - ---- - -### omni_getallbalancesforid - -Returns a list of token balances for a given currency or property identifier. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the property identifier | - -**Result:** -```js -[ // (array of JSON objects) - { - "address" : "address", // (string) the address - "balance" : "n.nnnnnnnn", // (string) the available balance of the address - "reserved" : "n.nnnnnnnn" // (string) the amount reserved by sell offers and accepts - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getallbalancesforid" 1 -``` - ---- - -### omni_getallbalancesforaddress - -Returns a list of all token balances for a given address. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `address` | string | required | the address | - -**Result:** -```js -[ // (array of JSON objects) - { - "propertyid" : n, // (number) the property identifier - "balance" : "n.nnnnnnnn", // (string) the available balance of the address - "reserved" : "n.nnnnnnnn" // (string) the amount reserved by sell offers and accepts - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getallbalancesforaddress" "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P" -``` - ---- - -### omni_gettransaction - -Get detailed information about an Omni transaction. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `txid` | string | required | the hash of the transaction to lookup | - -**Result:** -```js -{ - "txid" : "hash", // (string) the hex-encoded hash of the transaction - "sendingaddress" : "address", // (string) the Bitcoin address of the sender - "referenceaddress" : "address", // (string) a Bitcoin address used as reference (if any) - "ismine" : true|false, // (boolean) whether the transaction involes an address in the wallet - "confirmations" : nnnnnnnnnn, // (number) the number of transaction confirmations - "fee" : "n.nnnnnnnn", // (string) the transaction fee in bitcoins - "blocktime" : nnnnnnnnnn, // (number) the timestamp of the block that contains the transaction - "valid" : true|false, // (boolean) whether the transaction is valid - "positioninblock" : n, // (number) the position (index) of the transaction within the block - "version" : n, // (number) the transaction version - "type_int" : n, // (number) the transaction type as number - "type" : "type", // (string) the transaction type as string - [...] // (mixed) other transaction type specific properties -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_gettransaction" "1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d" -``` - ---- - -### omni_listtransactions - -List wallet transactions, optionally filtered by an address and block boundaries. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `txid` | string | optional | address filter (default: `"*"`) | -| `count` | number | optional | show at most n transactions (default: `10`) | -| `skip` | number | optional | skip the first n transactions (default: `0`) | -| `startblock` | number | optional | first block to begin the search (default: `0`) | -| `endblock` | number | optional | last block to include in the search (default: `999999`) | - -**Result:** -```js -[ // (array of JSON objects) - { - "txid" : "hash", // (string) the hex-encoded hash of the transaction - "sendingaddress" : "address", // (string) the Bitcoin address of the sender - "referenceaddress" : "address", // (string) a Bitcoin address used as reference (if any) - "ismine" : true|false, // (boolean) whether the transaction involves an address in the wallet - "confirmations" : nnnnnnnnnn, // (number) the number of transaction confirmations - "fee" : "n.nnnnnnnn", // (string) the transaction fee in bitcoins - "blocktime" : nnnnnnnnnn, // (number) the timestamp of the block that contains the transaction - "valid" : true|false, // (boolean) whether the transaction is valid - "positioninblock" : n, // (number) the position (index) of the transaction within the block - "version" : n, // (number) the transaction version - "type_int" : n, // (number) the transaction type as number - "type" : "type", // (string) the transaction type as string - [...] // (mixed) other transaction type specific properties - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_listtransactions" -``` - ---- - -### omni_listblocktransactions - -Lists all Omni transactions in a block. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `index` | number | required | the block height or block index | - -**Result:** -```js -[ // (array of string) - "hash", // (string) the hash of the transaction - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_listblocktransactions" 279007 -``` - ---- - -### omni_listpendingtransactions - -Returns a list of unconfirmed Omni transactions, pending in the memory pool. - -Note: the validity of pending transactions is uncertain, and the state of the memory pool may change at any moment. It is recommended to check transactions after confirmation, and pending transactions should be considered as invalid. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `address` | string | optional | filter results by address (default: `""` for no filter) | - -**Result:** -```js -[ // (array of JSON objects) - { - "txid" : "hash", // (string) the hex-encoded hash of the transaction - "sendingaddress" : "address", // (string) the Bitcoin address of the sender - "referenceaddress" : "address", // (string) a Bitcoin address used as reference (if any) - "ismine" : true|false, // (boolean) whether the transaction involes an address in the wallet - "fee" : "n.nnnnnnnn", // (string) the transaction fee in bitcoins - "version" : n, // (number) the transaction version - "type_int" : n, // (number) the transaction type as number - "type" : "type", // (string) the transaction type as string - [...] // (mixed) other transaction type specific properties - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_listpendingtransactions" -``` - ---- - -### omni_getactivedexsells - -Returns currently active offers on the distributed exchange. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `address` | string | optional | address filter (default: include any) | - -**Result:** -```js -[ // (array of JSON objects) - { - "txid" : "hash", // (string) the hash of the transaction of this offer - "propertyid" : n, // (number) the identifier of the tokens for sale - "seller" : "address", // (string) the Bitcoin address of the seller - "amountavailable" : "n.nnnnnnnn", // (string) the number of tokens still listed for sale and currently available - "bitcoindesired" : "n.nnnnnnnn", // (string) the number of bitcoins desired in exchange - "unitprice" : "n.nnnnnnnn" , // (string) the unit price (BTC/token) - "timelimit" : nn, // (number) the time limit in blocks a buyer has to pay following a successful accept - "minimumfee" : "n.nnnnnnnn", // (string) the minimum mining fee a buyer has to pay to accept this offer - "amountaccepted" : "n.nnnnnnnn", // (string) the number of tokens currently reserved for pending "accept" orders - "accepts": [ // (array of JSON objects) a list of pending "accept" orders - { - "buyer" : "address", // (string) the Bitcoin address of the buyer - "block" : nnnnnn, // (number) the index of the block that contains the "accept" order - "blocksleft" : nn, // (number) the number of blocks left to pay - "amount" : "n.nnnnnnnn" // (string) the amount of tokens accepted and reserved - "amounttopay" : "n.nnnnnnnn" // (string) the amount in bitcoins needed finalize the trade - }, - ... - ] - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getactivedexsells" -``` - ---- - -### omni_listproperties - -Lists all tokens or smart properties. - -**Arguments:** - -*None* - -**Result:** -```js -[ // (array of JSON objects) - { - "propertyid" : n, // (number) the identifier of the tokens - "name" : "name", // (string) the name of the tokens - "category" : "category", // (string) the category used for the tokens - "subcategory" : "subcategory", // (string) the subcategory used for the tokens - "data" : "information", // (string) additional information or a description - "url" : "uri", // (string) an URI, for example pointing to a website - "divisible" : true|false // (boolean) whether the tokens are divisible - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_listproperties" -``` - ---- - -### omni_getproperty - -Returns details for about the tokens or smart property to lookup. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the tokens or property | - -**Result:** -```js -{ - "propertyid" : n, // (number) the identifier - "name" : "name", // (string) the name of the tokens - "category" : "category", // (string) the category used for the tokens - "subcategory" : "subcategory", // (string) the subcategory used for the tokens - "data" : "information", // (string) additional information or a description - "url" : "uri", // (string) an URI, for example pointing to a website - "divisible" : true|false, // (boolean) whether the tokens are divisible - "issuer" : "address", // (string) the Bitcoin address of the issuer on record - "creationtxid" : "hash", // (string) the hex-encoded creation transaction hash - "fixedissuance" : true|false, // (boolean) whether the token supply is fixed - "managedissuance" : true|false, // (boolean) whether the token supply is managed by the issuer - "freezingenabled" : true|false, // (boolean) whether freezing is enabled for the property (managed properties only) - "totaltokens" : "n.nnnnnnnn" // (string) the total number of tokens in existence -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getproperty" 3 -``` - ---- - -### omni_getactivecrowdsales - -Lists currently active crowdsales. - -**Arguments:** - -*None* - -**Result:** -```js -[ // (array of JSON objects) - { - "propertyid" : n, // (number) the identifier of the crowdsale - "name" : "name", // (string) the name of the tokens issued via the crowdsale - "issuer" : "address", // (string) the Bitcoin address of the issuer on record - "propertyiddesired" : n, // (number) the identifier of the tokens eligible to participate in the crowdsale - "tokensperunit" : "n.nnnnnnnn", // (string) the amount of tokens granted per unit invested in the crowdsale - "earlybonus" : n, // (number) an early bird bonus for participants in percent per week - "percenttoissuer" : n, // (number) a percentage of tokens that will be granted to the issuer - "starttime" : nnnnnnnnnn, // (number) the start time of the of the crowdsale as Unix timestamp - "deadline" : nnnnnnnnnn // (number) the deadline of the crowdsale as Unix timestamp - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getactivecrowdsales" -``` - ---- - -### omni_getcrowdsale - -Returns information about a crowdsale. - -**Arguments:**, - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the crowdsale | -| `verbose` | boolean | optional | list crowdsale participants (default: `false`) | - -**Result:** -```js -{ - "propertyid" : n, // (number) the identifier of the crowdsale - "name" : "name", // (string) the name of the tokens issued via the crowdsale - "active" : true|false, // (boolean) whether the crowdsale is still active - "issuer" : "address", // (string) the Bitcoin address of the issuer on record - "propertyiddesired" : n, // (number) the identifier of the tokens eligible to participate in the crowdsale - "tokensperunit" : "n.nnnnnnnn", // (string) the amount of tokens granted per unit invested in the crowdsale - "earlybonus" : n, // (number) an early bird bonus for participants in percent per week - "percenttoissuer" : n, // (number) a percentage of tokens that will be granted to the issuer - "starttime" : nnnnnnnnnn, // (number) the start time of the of the crowdsale as Unix timestamp - "deadline" : nnnnnnnnnn, // (number) the deadline of the crowdsale as Unix timestamp - "amountraised" : "n.nnnnnnnn", // (string) the amount of tokens invested by participants - "tokensissued" : "n.nnnnnnnn", // (string) the total number of tokens issued via the crowdsale - "addedissuertokens" : "n.nnnnnnnn", // (string) the amount of tokens granted to the issuer as bonus - "closedearly" : true|false, // (boolean) whether the crowdsale ended early (if not active) - "maxtokens" : true|false, // (boolean) whether the crowdsale ended early due to reaching the limit of max. issuable tokens (if not active) - "endedtime" : nnnnnnnnnn, // (number) the time when the crowdsale ended (if closed early) - "closetx" : "hash", // (string) the hex-encoded hash of the transaction that closed the crowdsale (if closed manually) - "participanttransactions": [ // (array of JSON objects) a list of crowdsale participations (if verbose=true) - { - "txid" : "hash", // (string) the hex-encoded hash of participation transaction - "amountsent" : "n.nnnnnnnn", // (string) the amount of tokens invested by the participant - "participanttokens" : "n.nnnnnnnn", // (string) the tokens granted to the participant - "issuertokens" : "n.nnnnnnnn" // (string) the tokens granted to the issuer as bonus - }, - ... - ] -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getcrowdsale" 3 true -``` - ---- - -### omni_getgrants - -Returns information about granted and revoked units of managed tokens. - -**Arguments:** - -*None* - -**Result:** -```js -{ - "propertyid" : n, // (number) the identifier of the managed tokens - "name" : "name", // (string) the name of the tokens - "issuer" : "address", // (string) the Bitcoin address of the issuer on record - "creationtxid" : "hash", // (string) the hex-encoded creation transaction hash - "totaltokens" : "n.nnnnnnnn", // (string) the total number of tokens in existence - "issuances": [ // (array of JSON objects) a list of the granted and revoked tokens - { - "txid" : "hash", // (string) the hash of the transaction that granted tokens - "grant" : "n.nnnnnnnn" // (string) the number of tokens granted by this transaction - }, - { - "txid" : "hash", // (string) the hash of the transaction that revoked tokens - "grant" : "n.nnnnnnnn" // (string) the number of tokens revoked by this transaction - }, - ... - ] -} -``` - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the managed tokens to lookup | - -**Example:** - -```bash -$ omnicore-cli "omni_getgrants" 31 -``` - ---- - -### omni_getsto - -Get information and recipients of a send-to-owners transaction. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `txid` | string | required | the hash of the transaction to lookup | -| `recipientfilter` | string | optional | a filter for recipients (wallet by default, `"*"` for all) | - -**Result:** -```js -{ - "txid" : "hash", // (string) the hex-encoded hash of the transaction - "sendingaddress" : "address", // (string) the Bitcoin address of the sender - "ismine" : true|false, // (boolean) whether the transaction involes an address in the wallet - "confirmations" : nnnnnnnnnn, // (number) the number of transaction confirmations - "fee" : "n.nnnnnnnn", // (string) the transaction fee in bitcoins - "blocktime" : nnnnnnnnnn, // (number) the timestamp of the block that contains the transaction - "valid" : true|false, // (boolean) whether the transaction is valid - "positioninblock" : n, // (number) the position (index) of the transaction within the block - "version" : n, // (number) the transaction version - "type_int" : n, // (number) the transaction type as number - "type" : "type", // (string) the transaction type as string - "propertyid" : n, // (number) the identifier of sent tokens - "divisible" : true|false, // (boolean) whether the sent tokens are divisible - "amount" : "n.nnnnnnnn", // (string) the number of tokens sent to owners - "totalstofee" : "n.nnnnnnnn", // (string) the fee paid by the sender, nominated in OMNI or TOMNI - "recipients": [ // (array of JSON objects) a list of recipients - { - "address" : "address", // (string) the Bitcoin address of the recipient - "amount" : "n.nnnnnnnn" // (string) the number of tokens sent to this recipient - }, - ... - ] -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getsto" "1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d" "*" -``` - ---- - -### omni_gettrade - -Get detailed information and trade matches for orders on the distributed token exchange. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `txid` | string | required | the hash of the order to lookup | - -**Result:** -```js -{ - "txid" : "hash", // (string) the hex-encoded hash of the transaction of the order - "sendingaddress" : "address", // (string) the Bitcoin address of the trader - "ismine" : true|false, // (boolean) whether the order involes an address in the wallet - "confirmations" : nnnnnnnnnn, // (number) the number of transaction confirmations - "fee" : "n.nnnnnnnn", // (string) the transaction fee in bitcoins - "blocktime" : nnnnnnnnnn, // (number) the timestamp of the block that contains the transaction - "valid" : true|false, // (boolean) whether the transaction is valid - "positioninblock" : n, // (number) the position (index) of the transaction within the block - "version" : n, // (number) the transaction version - "type_int" : n, // (number) the transaction type as number - "type" : "type", // (string) the transaction type as string - "propertyidforsale" : n, // (number) the identifier of the tokens put up for sale - "propertyidforsaleisdivisible" : true|false, // (boolean) whether the tokens for sale are divisible - "amountforsale" : "n.nnnnnnnn", // (string) the amount of tokens initially offered - "propertyiddesired" : n, // (number) the identifier of the tokens desired in exchange - "propertyiddesiredisdivisible" : true|false, // (boolean) whether the desired tokens are divisible - "amountdesired" : "n.nnnnnnnn", // (string) the amount of tokens initially desired - "unitprice" : "n.nnnnnnnnnnn..." // (string) the unit price (shown in the property desired) - "status" : "status" // (string) the status of the order ("open", "cancelled", "filled", ...) - "canceltxid" : "hash", // (string) the hash of the transaction that cancelled the order (if cancelled) - "matches": [ // (array of JSON objects) a list of matched orders and executed trades - { - "txid" : "hash", // (string) the hash of the transaction that was matched against - "block" : nnnnnn, // (number) the index of the block that contains this transaction - "address" : "address", // (string) the Bitcoin address of the other trader - "amountsold" : "n.nnnnnnnn", // (string) the number of tokens sold in this trade - "amountreceived" : "n.nnnnnnnn" // (string) the number of tokens traded in exchange - }, - ... - ] -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_gettrade" "1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d" -``` - ---- - -### omni_getorderbook - -List active offers on the distributed token exchange. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | filter orders by `propertyid` for sale | -| `propertyid` | number | optional | filter orders by `propertyid` desired | - -**Result:** -```js -[ // (array of JSON objects) - { - "address" : "address", // (string) the Bitcoin address of the trader - "txid" : "hash", // (string) the hex-encoded hash of the transaction of the order - "ecosystem" : "main"|"test", // (string) the ecosytem in which the order was made (if "cancel-ecosystem") - "propertyidforsale" : n, // (number) the identifier of the tokens put up for sale - "propertyidforsaleisdivisible" : true|false, // (boolean) whether the tokens for sale are divisible - "amountforsale" : "n.nnnnnnnn", // (string) the amount of tokens initially offered - "amountremaining" : "n.nnnnnnnn", // (string) the amount of tokens still up for sale - "propertyiddesired" : n, // (number) the identifier of the tokens desired in exchange - "propertyiddesiredisdivisible" : true|false, // (boolean) whether the desired tokens are divisible - "amountdesired" : "n.nnnnnnnn", // (string) the amount of tokens initially desired - "amounttofill" : "n.nnnnnnnn", // (string) the amount of tokens still needed to fill the offer completely - "action" : n, // (number) the action of the transaction: (1) "trade", (2) "cancel-price", (3) "cancel-pair", (4) "cancel-ecosystem" - "block" : nnnnnn, // (number) the index of the block that contains the transaction - "blocktime" : nnnnnnnnnn // (number) the timestamp of the block that contains the transaction - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getorderbook" 2 -``` - ---- - -### omni_gettradehistoryforpair - -Retrieves the history of trades on the distributed token exchange for the specified market. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the first side of the traded pair | -| `propertyid` | number | required | the second side of the traded pair | -| `count` | number | optional | number of trades to retrieve (default: `10`) | - -**Result:** -```js -[ // (array of JSON objects) - { - "block" : nnnnnn, // (number) the index of the block that contains the trade match - "unitprice" : "n.nnnnnnnnnnn..." , // (string) the unit price used to execute this trade (received/sold) - "inverseprice" : "n.nnnnnnnnnnn...", // (string) the inverse unit price (sold/received) - "sellertxid" : "hash", // (string) the hash of the transaction of the seller - "address" : "address", // (string) the Bitcoin address of the seller - "amountsold" : "n.nnnnnnnn", // (string) the number of tokens sold in this trade - "amountreceived" : "n.nnnnnnnn", // (string) the number of tokens traded in exchange - "matchingtxid" : "hash", // (string) the hash of the transaction that was matched against - "matchingaddress" : "address" // (string) the Bitcoin address of the other party of this trade - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_gettradehistoryforpair" 1 12 500 -``` - ---- - -### omni_gettradehistoryforaddress - -Retrieves the history of orders on the distributed exchange for the supplied address. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `address` | string | required | address to retrieve history for | -| `count` | number | optional | number of orders to retrieve (default: `10`) | -| `propertyid` | number | optional | filter by propertyid transacted (default: no filter) | - -**Result:** -```js -[ // (array of JSON objects) - { - "txid" : "hash", // (string) the hex-encoded hash of the transaction of the order - "sendingaddress" : "address", // (string) the Bitcoin address of the trader - "ismine" : true|false, // (boolean) whether the order involes an address in the wallet - "confirmations" : nnnnnnnnnn, // (number) the number of transaction confirmations - "fee" : "n.nnnnnnnn", // (string) the transaction fee in bitcoins - "blocktime" : nnnnnnnnnn, // (number) the timestamp of the block that contains the transaction - "valid" : true|false, // (boolean) whether the transaction is valid - "positioninblock" : n, // (number) the position (index) of the transaction within the block - "version" : n, // (number) the transaction version - "type_int" : n, // (number) the transaction type as number - "type" : "type", // (string) the transaction type as string - "propertyidforsale" : n, // (number) the identifier of the tokens put up for sale - "propertyidforsaleisdivisible" : true|false, // (boolean) whether the tokens for sale are divisible - "amountforsale" : "n.nnnnnnnn", // (string) the amount of tokens initially offered - "propertyiddesired" : n, // (number) the identifier of the tokens desired in exchange - "propertyiddesiredisdivisible" : true|false, // (boolean) whether the desired tokens are divisible - "amountdesired" : "n.nnnnnnnn", // (string) the amount of tokens initially desired - "unitprice" : "n.nnnnnnnnnnn..." // (string) the unit price (shown in the property desired) - "status" : "status" // (string) the status of the order ("open", "cancelled", "filled", ...) - "canceltxid" : "hash", // (string) the hash of the transaction that cancelled the order (if cancelled) - "matches": [ // (array of JSON objects) a list of matched orders and executed trades - { - "txid" : "hash", // (string) the hash of the transaction that was matched against - "block" : nnnnnn, // (number) the index of the block that contains this transaction - "address" : "address", // (string) the Bitcoin address of the other trader - "amountsold" : "n.nnnnnnnn", // (string) the number of tokens sold in this trade - "amountreceived" : "n.nnnnnnnn" // (string) the number of tokens traded in exchange - }, - ... - ] - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_gettradehistoryforaddress" "1MCHESTptvd2LnNp7wmr2sGTpRomteAkq8" -``` - ---- - -### omni_getactivations - -Returns pending and completed feature activations. - -**Result:** -```js -{ - "pendingactivations": [ // (array of JSON objects) a list of pending feature activations - { - "featureid" : n, // (number) the id of the feature - "featurename" : "xxxxxxxx", // (string) the name of the feature - "activationblock" : n, // (number) the block the feature will be activated - "minimumversion" : n // (number) the minimum client version needed to support this feature - }, - ... - ] - "completedactivations": [ // (array of JSON objects) a list of completed feature activations - { - "featureid" : n, // (number) the id of the feature - "featurename" : "xxxxxxxx", // (string) the name of the feature - "activationblock" : n, // (number) the block the feature will be activated - "minimumversion" : n // (number) the minimum client version needed to support this feature - }, - ... - ] -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getactivations" -``` - ---- - -### omni_getpayload - -Get the payload for an Omni transaction. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `txid` | string | required | the hash of the transaction to retrieve payload | - -**Result:** -```js -{ - "payload" : "payloadmessage", // (string) the decoded Omni payload message - "payloadsize" : n // (number) the size of the payload -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getactivations" "1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d" -``` - ---- - -### omni_getseedblocks - -Returns a list of blocks containing Omni transactions for use in seed block filtering. - -WARNING: The Elysium crowdsale is not stored in LevelDB, thus this is currently only safe to use to generate seed blocks after block 255365. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `startblock` | number | required | the first block to look for Omni transactions (inclusive) | -| `endblock` | number | required | the last block to look for Omni transactions (inclusive) | - -**Result:** -```js -[ // (array of numbers) a list of seed blocks - nnnnnnn, // the block height of the seed block - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getseedblocks" 290000 300000 -``` - ---- - -### omni_getcurrentconsensushash - -Returns the consensus hash covering the state of the current block. - -**Arguments:** - -*None* - -**Result:** -```js -{ - "block" : nnnnnn, // (number) the index of the block this consensus hash applies to - "blockhash" : "hash", // (string) the hash of the corresponding block - "consensushash" : "hash" // (string) the consensus hash for the block -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getcurrentconsensushash" -``` - ---- - -## Raw transactions - -The RPCs for raw transactions/payloads can be used to decode or create raw Omni transactions. - -### omni_decodetransaction - -Decodes an Omni transaction. - -If the inputs of the transaction are not in the chain, then they must be provided, because the transaction inputs are used to identify the sender of a transaction. - -A block height can be provided, which is used to determine the parsing rules. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `rawtx` | string | required | the raw transaction to decode | -| `prevtxs` | string | optional | a JSON array of transaction inputs (default: none) | -| `height` | number | optional | the parsing block height (default: 0 for chain height) | - -The format of `prevtxs` is as following: - -```js -[ - { - "txid" : "hash", // (string, required) the transaction hash - "vout" : n, // (number, required) the output number - "scriptPubKey" : "hex", // (string, required) the output script - "value" : n.nnnnnnnn // (number, required) the output value - } - ,... -] -``` - -**Result:** -```js -{ - "txid" : "hash", // (string) the hex-encoded hash of the transaction - "fee" : "n.nnnnnnnn", // (string) the transaction fee in bitcoins - "sendingaddress" : "address", // (string) the Bitcoin address of the sender - "referenceaddress" : "address", // (string) a Bitcoin address used as reference (if any) - "ismine" : true|false, // (boolean) whether the transaction involes an address in the wallet - "version" : n, // (number) the transaction version - "type_int" : n, // (number) the transaction type as number - "type" : "type", // (string) the transaction type as string - [...] // (mixed) other transaction type specific properties -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_decodetransaction" "010000000163af14ce6d477e1c793507e32a5b7696288fa89705c0d02a3f66beb3c \ - 5b8afee0100000000ffffffff02ac020000000000004751210261ea979f6a06f9dafe00fb1263ea0aca959875a7073556a088cdf \ - adcd494b3752102a3fd0a8a067e06941e066f78d930bfc47746f097fcd3f7ab27db8ddf37168b6b52ae22020000000000001976a \ - 914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000" \ - "[{\"txid\":\"eeafb8c5b3be663f2ad0c00597a88f2896765b2ae30735791c7e476dce14af63\",\"vout\":1, \ - \"scriptPubKey\":\"76a9149084c0bd89289bc025d0264f7f23148fb683d56c88ac\",\"value\":0.0001123}]" -``` - ---- - -### omni_createrawtx_opreturn - -Adds a payload with class C (op-return) encoding to the transaction. - -If no raw transaction is provided, a new transaction is created. - -If the data encoding fails, then the transaction is not modified. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `rawtx` | string | required | the raw transaction to extend (can be `null`) | -| `payload` | string | required | the hex-encoded payload to add | - -**Result:** -```js -"rawtx" // (string) the hex-encoded modified raw transaction -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createrawtx_opreturn" "01000000000000000000" "00000000000000020000000006dac2c0" -``` - ---- - -### omni_createrawtx_multisig - -Adds a payload with class B (bare-multisig) encoding to the transaction. - -If no raw transaction is provided, a new transaction is created. - -If the data encoding fails, then the transaction is not modified. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `rawtx` | string | required | the raw transaction to extend (can be `null`) | -| `payload` | string | required | the hex-encoded payload to add | -| `seed` | string | required | the seed for obfuscation | -| `payload` | string | required | a public key or address for dust redemption | - -**Result:** -```js -"rawtx" // (string) the hex-encoded modified raw transaction -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createrawtx_multisig" \ - "0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff01aa0a00000 \ - 00000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac00000000" \ - "00000000000000020000000000989680" - "1LifmeXYHeUe2qdKWBGVwfbUCMMrwYtoMm" \ - "0252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3" -``` - ---- - -### omni_createrawtx_input - -Adds a transaction input to the transaction. - -If no raw transaction is provided, a new transaction is created. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `rawtx` | string | required | the raw transaction to extend (can be `null`) | -| `txid` | string | required | the hash of the input transaction | -| `n` | number | required | the index of the transaction output used as input | - -**Result:** -```js -"rawtx" // (string) the hex-encoded modified raw transaction -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createrawtx_input" \ - "01000000000000000000" "b006729017df05eda586df9ad3f8ccfee5be340aadf88155b784d1fc0e8342ee" 0 -``` - ---- - -### omni_createrawtx_reference - -Adds a reference output to the transaction. - -If no raw transaction is provided, a new transaction is created. - -The output value is set to at least the dust threshold. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `rawtx` | string | required | the raw transaction to extend (can be `null`) | -| `destination` | string | required | the reference address or destination | -| `amount` | number | optional | the optional reference amount (minimal by default) | - -**Result:** -```js -"rawtx" // (string) the hex-encoded modified raw transaction -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createrawtx_reference" \ - "0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff03aa0a00000 - 00000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a - 6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a51 - 21f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000" \ - "1CE8bBr1dYZRMnpmyYsFEoexa1YoPz2mfB" \ - 0.005 -``` - ---- - -### omni_createrawtx_change - -Adds a change output to the transaction. - -The provided inputs are not added to the transaction, but only used to determine the change. It is assumed that the inputs were previously added, for example via `"createrawtransaction"`. - -Optionally a position can be provided, where the change output should be inserted, starting with `0`. If the number of outputs is smaller than the position, then the change output is added to the end. Change outputs should be inserted before reference outputs, and as per default, the change output is added to the`first position. - -If the change amount would be considered as dust, then no change output is added. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `rawtx` | string | required | the raw transaction to extend | -| `prevtxs` | string | required | a JSON array of transaction inputs | -| `destination` | string | required | the destination for the change | -| `fee` | number | required | the desired transaction fees | -| `position` | number | optional | the position of the change output (default: first position) | - -The format of `prevtxs` is as following: - -```js -[ - { - "txid" : "hash", // (string, required) the transaction hash - "vout" : n, // (number, required) the output number - "scriptPubKey" : "hex", // (string, required) the output script - "value" : n.nnnnnnnn // (number, required) the output value - } - ,... -] -``` - -**Result:** -```js -"rawtx" // (string) the hex-encoded modified raw transaction -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createrawtx_change" \ - "0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff025c0d00000 \ - 000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f \ - 08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2 \ - 339d24288ac00000000" \ - "[{\"txid\":\"6779a710fcd5f6fb0883ea3306360c3ad8c0a3c5de902768ec57ef3104e65eb1\",\"vout\":4, \ - \"scriptPubKey\":\"76a9147b25205fd98d462880a3e5b0541235831ae959e588ac\",\"value\":0.00068257}]" \ - "1CE8bBr1dYZRMnpmyYsFEoexa1YoPz2mfB" 0.000035 1 -``` - ---- - -### omni_createpayload_simplesend - -Create the payload for a simple send transaction. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the tokens to send | -| `amount` | string | required | the amount to send | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_simplesend" 1 "100.0" -``` - ---- - -### omni_createpayload_sendall - -Create the payload for a send all transaction. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `ecosystem` | number | required | the ecosystem of the tokens to send (1 for main ecosystem, 2 for test ecosystem) | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_sendall" 2 -``` - ---- - -### omni_createpayload_dexsell - -Create a payload to place, update or cancel a sell offer on the traditional distributed OMNI/BTC exchange. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyidforsale` | number | required | the identifier of the tokens to list for sale (must be 1 for OMNI or 2 for TOMNI) | -| `amountforsale` | string | required | the amount of tokens to list for sale | -| `amountdesired` | string | required | the amount of bitcoins desired | -| `paymentwindow` | number | required | a time limit in blocks a buyer has to pay following a successful accepting order | -| `minacceptfee` | string | required | a minimum mining fee a buyer has to pay to accept the offer | -| `action` | number | required | the action to take (1 for new offers, 2 to update\", 3 to cancel) | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_dexsell" 1 "1.5" "0.75" 25 "0.0005" 1 -``` - ---- - -### omni_createpayload_dexaccept - -Create the payload for an accept offer for the specified token and amount. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the token to purchase | -| `amount` | string | required | the amount to accept | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_dexaccept" 1 "15.0" -``` - ---- - -### omni_createpayload_sto - -Creates the payload for a send-to-owners transaction. - -**Arguments:** - -| Name | Type | Presence | Description | -|------------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the token to distribute | -| `amount` | string | required | the amount to distribute | -| `distributionproperty` | number | optional | the identifier of the property holders to distribute to | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_sto" 3 "5000" -``` - ---- - -### omni_createpayload_issuancefixed - -Creates the payload for a new tokens issuance with fixed supply. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `ecosystem` | number | required | the ecosystem to create the tokens in (1 for main ecosystem, 2 for test ecosystem) | -| `type` | number | required | the type of the tokens to create: (1 for indivisible tokens, 2 for divisible tokens) | -| `previousid` | number | required | an identifier of a predecessor token (use 0 for new tokens) | -| `category` | string | required | a category for the new tokens (can be "") | -| `subcategory` | string | required | a subcategory for the new tokens (can be "") | -| `name` | string | required | the name of the new tokens to create | -| `url` | string | required | an URL for further information about the new tokens (can be "") | -| `data` | string | required | a description for the new tokens (can be "") | -| `amount` | string | required | the number of tokens to create | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_issuancefixed" 2 1 0 "Companies" "Bitcoin Mining" "Quantum Miner" "" "" "1000000" -``` - ---- - -### omni_createpayload_issuancecrowdsale - -Creates the payload for a new tokens issuance with crowdsale. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `ecosystem` | number | required | the ecosystem to create the tokens in (1 for main ecosystem, 2 for test ecosystem) | -| `type` | number | required | the type of the tokens to create: (1 for indivisible tokens, 2 for divisible tokens) | -| `previousid` | number | required | an identifier of a predecessor token (use 0 for new tokens) | -| `category` | string | required | a category for the new tokens (can be "") | -| `subcategory` | string | required | a subcategory for the new tokens (can be "") | -| `name` | string | required | the name of the new tokens to create | -| `url` | string | required | an URL for further information about the new tokens (can be "") | -| `data` | string | required | a description for the new tokens (can be "") | -| `propertyiddesired` | number | required | the identifier of a token eligible to participate in the crowdsale | -| `tokensperunit` | string | required | the amount of tokens granted per unit invested in the crowdsale | -| `deadline` | number | required | the deadline of the crowdsale as Unix timestamp | -| `earlybonus` | number | required | an early bird bonus for participants in percent per week | -| `issuerpercentage` | number | required | a percentage of tokens that will be granted to the issuer | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_issuancecrowdsale" 2 1 0 "Companies" "Bitcoin Mining" "Quantum Miner" "" "" 2 "100" 1483228800 30 2 -``` - ---- - -### omni_createpayload_issuancemanaged - -Creates the payload for a new tokens issuance with manageable supply. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `ecosystem` | number | required | the ecosystem to create the tokens in (1 for main ecosystem, 2 for test ecosystem) | -| `type` | number | required | the type of the tokens to create: (1 for indivisible tokens, 2 for divisible tokens) | -| `previousid` | number | required | an identifier of a predecessor token (use 0 for new tokens) | -| `category` | string | required | a category for the new tokens (can be "") | -| `subcategory` | string | required | a subcategory for the new tokens (can be "") | -| `name` | string | required | the name of the new tokens to create | -| `url` | string | required | an URL for further information about the new tokens (can be "") | -| `data` | string | required | a description for the new tokens (can be "") | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_issuancemanaged" 2 1 0 "Companies" "Bitcoin Mining" "Quantum Miner" "" "" -``` - ---- - -### omni_createpayload_closecrowdsale - -Creates the payload to manually close a crowdsale. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the crowdsale to close | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_closecrowdsale" 70 -``` - ---- - -### omni_createpayload_grant - -Creates the payload to issue or grant new units of managed tokens. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the tokens to grant | -| `amount` | string | required | the amount of tokens to create | -| `memo` | string | optional | a text note attached to this transaction (none by default) | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_grant" 51 "7000" -``` - ---- - -### omni_createpayload_revoke - -Creates the payload to revoke units of managed tokens. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the tokens to revoke | -| `amount` | string | required | the amount of tokens to revoke | -| `memo` | string | optional | a text note attached to this transaction (none by default) | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_revoke" 51 "100" -``` - ---- - -### omni_createpayload_changeissuer - -Creates the payload to change the issuer on record of the given tokens. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the tokens | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_changeissuer" 3 -``` - ---- - -### omni_createpayload_trade - -Creates the payload to place a trade offer on the distributed token exchange. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyidforsale` | number | required | the identifier of the tokens to list for sale | -| `amountforsale` | string | required | the amount of tokens to list for sale | -| `propertyiddesired` | number | required | the identifier of the tokens desired in exchange | -| `amountdesired` | string | required | the amount of tokens desired in exchange | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_trade" 31 "250.0" 1 "10.0" -``` - ---- - -### omni_createpayload_canceltradesbyprice - -Creates the payload to cancel offers on the distributed token exchange with the specified price. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyidforsale` | number | required | the identifier of the tokens to list for sale | -| `amountforsale` | string | required | the amount of tokens to list for sale | -| `propertyiddesired` | number | required | the identifier of the tokens desired in exchange | -| `amountdesired` | string | required | the amount of tokens desired in exchange | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_canceltradesbyprice" 31 "100.0" 1 "5.0" -``` - ---- - -### omni_createpayload_canceltradesbypair - -Creates the payload to cancel all offers on the distributed token exchange with the given currency pair. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyidforsale` | number | required | the identifier of the tokens to list for sale | -| `propertyiddesired` | number | required | the identifier of the tokens desired in exchange | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_canceltradesbypair" 1 31 -``` - ---- - -### omni_createpayload_cancelalltrades - -Creates the payload to cancel all offers on the distributed token exchange with the given currency pair. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `ecosystem` | number | required | the ecosystem of the offers to cancel (1 for main ecosystem, 2 for test ecosystem) | - -**Result:** -```js -"payload" // (string) the hex-encoded payload -``` - -**Example:** - -```bash -$ omnicore-cli "omni_createpayload_cancelalltrades" 1 -``` - ---- - -## Fee system - -The RPCs for the fee system can be used to obtain data about the fee system and fee distributions. - -### omni_getfeecache - -Obtains the current amount of fees cached (pending distribution). - -If a property ID is supplied the results will be filtered to show this property ID only. If no property ID is supplied the results will contain all properties that currently have fees cached pending distribution. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | optional | the identifier of the property to filter results on | - -**Result:** -```js -[ // (array of JSON objects) - { - "propertyid" : nnnnnnn, // (number) the property id - "cachedfees" : "n.nnnnnnnn", // (string) the amount of fees cached for this property - }, -... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getfeecache" 31 -``` - ---- - -### omni_getfeetrigger - -Obtains the amount at which cached fees will be distributed. - -If a property ID is supplied the results will be filtered to show this property ID only. If no property ID is supplied the results will contain all properties. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | optional | the identifier of the property to filter results on | - -**Result:** -```js -[ // (array of JSON objects) - { - "propertyid" : nnnnnnn, // (number) the property id - "feetrigger" : "n.nnnnnnnn", // (string) the amount of fees required to trigger distribution - }, -... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getfeetrigger" 31 -``` - ---- - -### omni_getfeeshare - -Obtains the current percentage share of fees addresses would receive if a distribution were to occur. - -If an address is supplied the results will be filtered to show this address only. If no address is supplied the results will be filtered to show wallet addresses only. If a wildcard is provided (```"*"```) the results will contain all addresses that would receive a share. - -If an ecosystem is supplied the results will reflect the fee share for that ecosystem (main or test). If no ecosystem is supplied the results will reflect the main ecosystem. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `address` | string | optional | the address to filter results on | -| `ecosystem` | number | optional | the ecosystem to obtain the current percentage fee share (1 = main, 2 = test) | - -**Result:** -```js -[ // (array of JSON objects) - { - "address" : "address" // (string) the adress that would receive a share of fees - "feeshare" : "n.nnnn%", // (string) the percentage of fees this address will receive based on the current state - }, -... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getfeeshare" "1CE8bBr1dYZRMnpmyYsFEoexa1YoPz2mfB" 1 -``` - ---- - -### omni_getfeedistribution - -Obtains data for a past distribution of fees. - -A distribution ID must be supplied to identify the distribution to obtain data for. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `distributionid` | number | required | the identifier of the distribution to obtain data for | - -**Result:** -```js -{ - "distributionid" : n, // (number) the distribution id - "propertyid" : n, // (number) the property id of the distributed tokens - "block" : n, // (number) the block the distribution occurred - "amount" : "n.nnnnnnnn", // (string) the amount that was distributed - "recipients": [ // (array of JSON objects) a list of recipients - { - "address" : "address", // (string) the address of the recipient - "amount" : "n.nnnnnnnn" // (string) the amount of fees received by the recipient - }, - ... - ] -} -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getfeedistribution" 1 -``` - ---- - -### omni_getfeedistributions - -Obtains data for past distributions of fees for a property. - -A property ID must be supplied to retrieve past distributions for. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `propertyid` | number | required | the identifier of the property to retrieve past distributions for | - -**Result:** -```js -[ // (array of JSON objects) - { - "distributionid" : n, // (number) the distribution id - "propertyid" : n, // (number) the property id of the distributed tokens - "block" : n, // (number) the block the distribution occurred - "amount" : "n.nnnnnnnn", // (string) the amount that was distributed - "recipients": [ // (array of JSON objects) a list of recipients - { - "address" : "address", // (string) the address of the recipient - "amount" : "n.nnnnnnnn" // (string) the amount of fees received by the recipient - }, - ... - ] - }, - ... -] -``` - -**Example:** - -```bash -$ omnicore-cli "omni_getfeedistributions" 31 -``` - ---- - -## Configuration - -The RPCs for the configuration can be used to alter Omni Core settings. - -### omni_setautocommit - -Sets the global flag that determines whether transactions are automatically committed and broadcasted. - -**Arguments:** - -| Name | Type | Presence | Description | -|---------------------|---------|----------|----------------------------------------------------------------------------------------------| -| `flag` | boolean | required | the flag | - -**Result:** -```js -true|false // (boolean) the updated flag status -``` - -**Example:** - -```bash -$ omnicore-cli "omni_setautocommit" false -``` - ---- - -## Depreciated API calls - -To ensure backwards compatibility, depreciated RPCs are kept for at least one major version. - -The following calls are replaced in Omni Core 0.0.10, and queries with the old command are forwarded. - -- `send_MP` by `omni_send` -- `sendtoowners_MP` by `omni_sendsto` -- `sendrawtx_MP` by `omni_sendrawtx` -- `getinfo_MP` by `omni_getinfo` -- `getbalance_MP` by `omni_getbalance` -- `getallbalancesforid_MP` by `omni_getallbalancesforid` -- `getallbalancesforaddress_MP` by `omni_getallbalancesforaddress` -- `gettransaction_MP` by `omni_gettransaction` -- `listtransactions_MP` by `omni_listtransactions` -- `listblocktransactions_MP` by `omni_listblocktransactions` -- `getactivedexsells_MP` by `omni_getactivedexsells` -- `listproperties_MP` by `omni_listproperties` -- `getproperty_MP` by `omni_getproperty` -- `getactivecrowdsales_MP` by `omni_getactivecrowdsales` -- `getcrowdsale_MP` by `omni_getcrowdsale` -- `getgrants_MP` by `omni_getgrants` -- `getsto_MP` by `omni_getsto` or `omni_gettransaction` diff --git a/src/elysium/ecdsa_context.cpp b/src/elysium/ecdsa_context.cpp deleted file mode 100644 index 8ce2ad7a8a..0000000000 --- a/src/elysium/ecdsa_context.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "ecdsa_context.h" - -#include "../random.h" - -namespace elysium { - -ECDSAContext::ECDSAContext(unsigned int flags) - : context(secp256k1_context_create(flags)) -{ -} - -ECDSAContext::ECDSAContext(ECDSAContext const &context) - : context(secp256k1_context_clone(context.Get())) -{ -} - -ECDSAContext::ECDSAContext(ECDSAContext &&context) -{ - std::swap(this->context, context.context); -} - -ECDSAContext::~ECDSAContext() -{ - secp256k1_context_destroy(context); -} - -ECDSAContext& ECDSAContext::operator=(ECDSAContext const &context) -{ - return *this = ECDSAContext(context); -} - -ECDSAContext& ECDSAContext::operator=(ECDSAContext &&context) -{ - std::swap(this->context, context.context); - return *this; -} - -secp256k1_context const *ECDSAContext::Get() const -{ - return context; -} - -ECDSAContext ECDSAContext::CreateSignContext() -{ - ECDSAContext context(SECP256K1_CONTEXT_SIGN); - context.Randomize(); - - return context; -} - -ECDSAContext ECDSAContext::CreateVerifyContext() -{ - return ECDSAContext(SECP256K1_CONTEXT_VERIFY); -} - -void ECDSAContext::Randomize() -{ - std::array seed; - GetRandBytes(seed.data(), seed.size()); - if (!secp256k1_context_randomize(context, seed.data())) { - secp256k1_context_destroy(context); - throw std::runtime_error("Fail to randomize context"); - } -} - -} // elysium \ No newline at end of file diff --git a/src/elysium/ecdsa_context.h b/src/elysium/ecdsa_context.h deleted file mode 100644 index a321416e64..0000000000 --- a/src/elysium/ecdsa_context.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef FIRO_ELYSIUM_ECDSA_CONTEXT_H -#define FIRO_ELYSIUM_ECDSA_CONTEXT_H - -#include - -namespace elysium { - -class ECDSAContext -{ -public: - ECDSAContext(unsigned int flags); - ECDSAContext(ECDSAContext const &context); - ECDSAContext(ECDSAContext &&context); - ~ECDSAContext(); - -public: - ECDSAContext& operator=(ECDSAContext const &context); - ECDSAContext& operator=(ECDSAContext &&context); - - secp256k1_context const *Get() const; - - static ECDSAContext CreateSignContext(); - static ECDSAContext CreateVerifyContext(); - -private: - void Randomize(); - -private: - secp256k1_context* context; -}; - -} // elysium - -#endif // FIRO_ELYSIUM_ECDSA_CONTEXT_H \ No newline at end of file diff --git a/src/elysium/ecdsa_signature.cpp b/src/elysium/ecdsa_signature.cpp deleted file mode 100644 index 8356be5591..0000000000 --- a/src/elysium/ecdsa_signature.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "ecdsa_signature.h" - -#include - -namespace elysium { - -ECDSASignature::ECDSASignature() : valid(false) -{ -} - -ECDSASignature::ECDSASignature(secp256k1_ecdsa_signature const &sig) - : signature(sig), valid(true) -{ -} - -ECDSASignature ECDSASignature::ParseCompact(ECDSAContext const &context, unsigned char const *signature) -{ - secp256k1_ecdsa_signature sig; - - if (1 != secp256k1_ecdsa_signature_parse_compact( - context.Get(), - &sig, - signature)) { - throw std::invalid_argument("Compact Signature is invalid"); - } - - return ECDSASignature(sig); -} - -ECDSASignature ECDSASignature::ParseDER(ECDSAContext const &context, unsigned char const *signature, size_t len) -{ - secp256k1_ecdsa_signature sig; - - if (1 != secp256k1_ecdsa_signature_parse_der( - context.Get(), - &sig, - signature, - len)) { - throw std::invalid_argument("DER Signature is invalid"); - } - - return ECDSASignature(sig); -} - -std::vector ECDSASignature::GetCompact(ECDSAContext const &context) const -{ - if (!Valid()) { - throw std::logic_error("Signature is invalid."); - } - - std::vector result; - result.resize(COMPACT_SIZE); - - if (1 != secp256k1_ecdsa_signature_serialize_compact( - context.Get(), - result.data(), - &signature)) { - throw std::runtime_error("Serialized size is in valid"); - } - - return result; -} - -std::vector ECDSASignature::GetDER(ECDSAContext const &context) const -{ - if (!Valid()) { - throw std::logic_error("Signature is invalid."); - } - - std::vector result; - result.resize(DER_SIZE); - - size_t outLen = DER_SIZE; - if (1 != secp256k1_ecdsa_signature_serialize_der( - context.Get(), - result.data(), - &outLen, - &signature)) { - throw std::runtime_error("Serialized size is in valid"); - } - - return result; -} - -bool ECDSASignature::Valid() const -{ - return valid; -} - -} // namespace elysium \ No newline at end of file diff --git a/src/elysium/ecdsa_signature.h b/src/elysium/ecdsa_signature.h deleted file mode 100644 index 189ed18b28..0000000000 --- a/src/elysium/ecdsa_signature.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef FIRO_ELYSIUM_ECDSA_SIGNATURE_H -#define FIRO_ELYSIUM_ECDSA_SIGNATURE_H - -#include "ecdsa_context.h" - -#include - -#include -#include -#include - -namespace elysium { - -class ECDSASignature -{ -public: - static size_t constexpr DER_SIZE = 72; - static size_t constexpr COMPACT_SIZE = 64; - -public: - ECDSASignature(); - ECDSASignature(secp256k1_ecdsa_signature const &sig); - -public: - static ECDSASignature ParseCompact(ECDSAContext const &context, unsigned char const *signature); - static ECDSASignature ParseDER(ECDSAContext const &context, unsigned char const *signature, size_t len); - -public: - std::vector GetCompact(ECDSAContext const &context) const; - std::vector GetDER(ECDSAContext const &context) const; - bool Valid() const; - - /** serialize as compact - */ - template - void Serialize(Stream& s) const - { - if (!Valid()) { - throw std::logic_error("ECDSA Signature is invalid"); - } - - auto buffer = GetCompact(ECDSAContext::CreateSignContext()); - - s.write(reinterpret_cast(buffer.data()), buffer.size()); - } - - /** unserialize compact - */ - template - void Unserialize(Stream& s) - { - std::array buffer; - s.read(reinterpret_cast(buffer.data()), buffer.size()); - if (1 != secp256k1_ecdsa_signature_parse_compact( - ECDSAContext::CreateVerifyContext().Get(), - &signature, - reinterpret_cast(buffer.data()))) { - valid = false; - throw std::runtime_error("Fail to parse compacted serialized data"); - } - - valid = true; - } - -private: - secp256k1_ecdsa_signature signature; - bool valid; -}; - -} // namespace elysium - -#endif // FIRO_ELYSIUM_ECDSA_SIGNATURE_H \ No newline at end of file diff --git a/src/elysium/elysium.cpp b/src/elysium/elysium.cpp deleted file mode 100644 index 4d8091f491..0000000000 --- a/src/elysium/elysium.cpp +++ /dev/null @@ -1,3835 +0,0 @@ -#include "elysium.h" - -#include "activation.h" -#include "consensushash.h" -#include "convert.h" -#include "dex.h" -#include "errors.h" -#include "fees.h" -#include "log.h" -#include "mdex.h" -#include "notifications.h" -#include "packetencoder.h" -#include "pending.h" -#include "persistence.h" -#include "rules.h" -#include "script.h" -#include "sigmadb.h" -#include "sp.h" -#include "tally.h" -#include "tx.h" -#include "txprocessor.h" -#include "utils.h" -#include "utilsbitcoin.h" -#include "version.h" -#ifdef ENABLE_WALLET -#include "wallet.h" -#endif -#include "walletcache.h" -#include "wallettxs.h" - -#include "../base58.h" -#include "../chainparams.h" -#include "../wallet/coincontrol.h" -#include "../coins.h" -#include "../core_io.h" -#include "../init.h" -#include "../validation.h" -#include "../net.h" -#include "../primitives/block.h" -#include "../primitives/transaction.h" -#include "../script/script.h" -#include "../script/standard.h" -#include "../sync.h" -#include "../tinyformat.h" -#include "../uint256.h" -#include "../ui_interface.h" -#include "../util.h" -#include "../utilstrencodings.h" -#include "../utiltime.h" -#include "../sigma.h" -#ifdef ENABLE_WALLET -#include "../script/ismine.h" -#include "../wallet/wallet.h" -#endif - -#include - -#include -#include -#include -#include -#include - -#include - -#include "leveldb/db.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -using boost::algorithm::token_compress_on; -using boost::to_string; - -using leveldb::Iterator; -using leveldb::Slice; -using leveldb::Status; - -using std::endl; -using std::make_pair; -using std::map; -using std::ofstream; -using std::pair; -using std::string; -using std::vector; - -using namespace elysium; - -static int nWaterlineBlock = 0; - -//! Available balances of wallet properties -std::map global_balance_money; -//! Reserved balances of wallet propertiess -std::map global_balance_reserved; -//! Vector containing a list of properties relative to the wallet -std::set global_wallet_property_list; - -//! Set containing properties that have freezing enabled -std::set > setFreezingEnabledProperties; -//! Set containing addresses that have been frozen -std::set > setFrozenAddresses; - -/** - * Used to indicate, whether to automatically commit created transactions. - * - * Can be set with configuration "-autocommit" or RPC "setautocommit_ELYSIUM". - */ -bool autoCommit = true; - -//! Number of "Dev ELYSIUM" of the last processed block -static int64_t elysium_prev = 0; - -static boost::filesystem::path MPPersistencePath; - -static int elysiumInitialized = 0; - -static int reorgRecoveryMode = 0; -static int reorgRecoveryMaxHeight = 0; - -CMPTxList *elysium::p_txlistdb; -CMPTradeList *elysium::t_tradelistdb; -CMPSTOList *elysium::s_stolistdb; -CElysiumTransactionDB *elysium::p_ElysiumTXDB; -CElysiumFeeCache *elysium::p_feecache; -CElysiumFeeHistory *elysium::p_feehistory; - -// indicate whether persistence is enabled at this point, or not -// used to write/read files, for breakout mode, debugging, etc. -static bool writePersistence(int block_now) -{ - // if too far away from the top -- do not write - if (GetHeight() > (block_now + MAX_STATE_HISTORY)) return false; - - return true; -} - -bool isElysiumEnabled() -{ - return GetBoolArg("-elysium", false); -} - -std::string elysium::strMPProperty(uint32_t propertyId) -{ - std::string str = "*unknown*"; - - // test user-token - if (0x80000000 & propertyId) { - str = strprintf("Test token: %d : 0x%08X", 0x7FFFFFFF & propertyId, propertyId); - } else { - switch (propertyId) { - case ELYSIUM_PROPERTY_XZC: str = "FIRO"; - break; - case ELYSIUM_PROPERTY_ELYSIUM: str = "ELYSIUM"; - break; - case ELYSIUM_PROPERTY_TELYSIUM: str = "TELYSIUM"; - break; - default: - str = strprintf("SP token: %d", propertyId); - } - } - - return str; -} - -std::string FormatDivisibleShortMP(int64_t n) -{ - int64_t n_abs = (n > 0 ? n : -n); - int64_t quotient = n_abs / COIN; - int64_t remainder = n_abs % COIN; - std::string str = strprintf("%d.%08d", quotient, remainder); - // clean up trailing zeros - good for RPC not so much for UI - str.erase(str.find_last_not_of('0') + 1, std::string::npos); - if (str.length() > 0) { - std::string::iterator it = str.end() - 1; - if (*it == '.') { - str.erase(it); - } - } //get rid of trailing dot if non decimal - return str; -} - -std::string FormatDivisibleMP(int64_t n, bool fSign) -{ - // Note: not using straight sprintf here because we do NOT want - // localized number formatting. - int64_t n_abs = (n > 0 ? n : -n); - int64_t quotient = n_abs / COIN; - int64_t remainder = n_abs % COIN; - std::string str = strprintf("%d.%08d", quotient, remainder); - - if (!fSign) return str; - - if (n < 0) - str.insert((unsigned int) 0, 1, '-'); - else - str.insert((unsigned int) 0, 1, '+'); - return str; -} - -std::string elysium::FormatIndivisibleMP(int64_t n) -{ - return strprintf("%d", n); -} - -std::string FormatShortMP(uint32_t property, int64_t n) -{ - if (isPropertyDivisible(property)) { - return FormatDivisibleShortMP(n); - } else { - return FormatIndivisibleMP(n); - } -} - -std::string FormatMP(uint32_t property, int64_t n, bool fSign) -{ - if (isPropertyDivisible(property)) { - return FormatDivisibleMP(n, fSign); - } else { - return FormatIndivisibleMP(n); - } -} - -std::string FormatByType(int64_t amount, uint16_t propertyType) -{ - if (propertyType & ELYSIUM_PROPERTY_TYPE_INDIVISIBLE) { - return FormatIndivisibleMP(amount); - } else { - return FormatDivisibleMP(amount); - } -} - -OfferMap elysium::my_offers; -AcceptMap elysium::my_accepts; - -CMPSPInfo *elysium::_my_sps; -CrowdMap elysium::my_crowds; - -// this is the master list of all amounts for all addresses for all properties, map is unsorted -std::unordered_map elysium::mp_tally_map; - -CMPTally* elysium::getTally(const std::string& address) -{ - std::unordered_map::iterator it = mp_tally_map.find(address); - - if (it != mp_tally_map.end()) return &(it->second); - - return (CMPTally *) NULL; -} - -// look at balance for an address -int64_t getMPbalance(const std::string& address, uint32_t propertyId, TallyType ttype) -{ - int64_t balance = 0; - if (TALLY_TYPE_COUNT <= ttype) { - return 0; - } - if (ttype == ACCEPT_RESERVE && propertyId > ELYSIUM_PROPERTY_TELYSIUM) { - // ACCEPT_RESERVE is always empty, except for ELYSIUM and TELYSIUM - return 0; - } - - LOCK(cs_main); - const std::unordered_map::iterator my_it = mp_tally_map.find(address); - if (my_it != mp_tally_map.end()) { - balance = (my_it->second).getMoney(propertyId, ttype); - } - - return balance; -} - -int64_t getUserAvailableMPbalance(const std::string& address, uint32_t propertyId) -{ - int64_t money = getMPbalance(address, propertyId, BALANCE); - int64_t pending = getMPbalance(address, propertyId, PENDING); - - if (0 > pending) { - return (money + pending); // show the decrease in available money - } - - return money; -} - -int64_t getUserFrozenMPbalance(const std::string& address, uint32_t propertyId) -{ - int64_t frozen = 0; - - if (isAddressFrozen(address, propertyId)) { - frozen = getMPbalance(address, propertyId, BALANCE); - } - - return frozen; -} - -bool elysium::isTestEcosystemProperty(uint32_t propertyId) -{ - if ((ELYSIUM_PROPERTY_TELYSIUM == propertyId) || (TEST_ECO_PROPERTY_1 <= propertyId)) return true; - - return false; -} - -bool elysium::isMainEcosystemProperty(uint32_t propertyId) -{ - if ((ELYSIUM_PROPERTY_XZC != propertyId) && !isTestEcosystemProperty(propertyId)) return true; - - return false; -} - -void elysium::ClearFreezeState() -{ - // Should only ever be called in the event of a reorg - setFreezingEnabledProperties.clear(); - setFrozenAddresses.clear(); -} - -void elysium::PrintFreezeState() -{ - PrintToLog("setFrozenAddresses state:\n"); - for (std::set >::iterator it = setFrozenAddresses.begin(); it != setFrozenAddresses.end(); it++) { - PrintToLog(" %s:%d\n", (*it).first, (*it).second); - } - PrintToLog("setFreezingEnabledProperties state:\n"); - for (std::set >::iterator it = setFreezingEnabledProperties.begin(); it != setFreezingEnabledProperties.end(); it++) { - PrintToLog(" %d:%d\n", (*it).first, (*it).second); - } -} - -void elysium::enableFreezing(uint32_t propertyId, int liveBlock) -{ - setFreezingEnabledProperties.insert(std::make_pair(propertyId, liveBlock)); - assert(isFreezingEnabled(propertyId, liveBlock)); - PrintToLog("Freezing for property %d will be enabled at block %d.\n", propertyId, liveBlock); -} - -void elysium::disableFreezing(uint32_t propertyId) -{ - int liveBlock = 0; - for (std::set >::iterator it = setFreezingEnabledProperties.begin(); it != setFreezingEnabledProperties.end(); it++) { - if (propertyId == (*it).first) { - liveBlock = (*it).second; - } - } - assert(liveBlock > 0); - - setFreezingEnabledProperties.erase(std::make_pair(propertyId, liveBlock)); - PrintToLog("Freezing for property %d has been disabled.\n", propertyId); - - // When disabling freezing for a property, all frozen addresses for that property will be unfrozen! - for (std::set >::iterator it = setFrozenAddresses.begin(); it != setFrozenAddresses.end(); ) { - if ((*it).second == propertyId) { - PrintToLog("Address %s has been unfrozen for property %d.\n", (*it).first, propertyId); - it = setFrozenAddresses.erase(it); - assert(!isAddressFrozen((*it).first, (*it).second)); - } else { - it++; - } - } - - assert(!isFreezingEnabled(propertyId, liveBlock)); -} - -bool elysium::isFreezingEnabled(uint32_t propertyId, int block) -{ - for (std::set >::iterator it = setFreezingEnabledProperties.begin(); it != setFreezingEnabledProperties.end(); it++) { - uint32_t itemPropertyId = (*it).first; - int itemBlock = (*it).second; - if (propertyId == itemPropertyId && block >= itemBlock) { - return true; - } - } - return false; -} - -void elysium::freezeAddress(const std::string& address, uint32_t propertyId) -{ - setFrozenAddresses.insert(std::make_pair(address, propertyId)); - assert(isAddressFrozen(address, propertyId)); - PrintToLog("Address %s has been frozen for property %d.\n", address, propertyId); -} - -void elysium::unfreezeAddress(const std::string& address, uint32_t propertyId) -{ - setFrozenAddresses.erase(std::make_pair(address, propertyId)); - assert(!isAddressFrozen(address, propertyId)); - PrintToLog("Address %s has been unfrozen for property %d.\n", address, propertyId); -} - -bool elysium::isAddressFrozen(const std::string& address, uint32_t propertyId) -{ - if (setFrozenAddresses.find(std::make_pair(address, propertyId)) != setFrozenAddresses.end()) { - return true; - } - return false; -} - -std::string elysium::getTokenLabel(uint32_t propertyId) -{ - std::string tokenStr; - if (propertyId < 3) { - if (propertyId == 1) { - tokenStr = " ELYSIUM"; - } else { - tokenStr = " TELYSIUM"; - } - } else { - tokenStr = strprintf(" SPT#%d", propertyId); - } - return tokenStr; -} - -// get total tokens for a property -// optionally counts the number of addresses who own that property: n_owners_total -int64_t elysium::getTotalTokens(uint32_t propertyId, int64_t* n_owners_total) -{ - int64_t prev = 0; - int64_t owners = 0; - int64_t totalTokens = 0; - - LOCK(cs_main); - - CMPSPInfo::Entry property; - if (false == _my_sps->getSP(propertyId, property)) { - return 0; // property ID does not exist - } - - if (!property.fixed || n_owners_total) { - for (std::unordered_map::const_iterator it = mp_tally_map.begin(); it != mp_tally_map.end(); ++it) { - const CMPTally& tally = it->second; - - totalTokens += tally.getMoney(propertyId, BALANCE); - totalTokens += tally.getMoney(propertyId, SELLOFFER_RESERVE); - totalTokens += tally.getMoney(propertyId, ACCEPT_RESERVE); - totalTokens += tally.getMoney(propertyId, METADEX_RESERVE); - - if (prev != totalTokens) { - prev = totalTokens; - owners++; - } - } - int64_t cachedFee = p_feecache->GetCachedAmount(propertyId); - totalTokens += cachedFee; - } - - if (property.fixed) { - totalTokens = property.num_tokens; // only valid for TX50 - } - - if (n_owners_total) *n_owners_total = owners; - - return totalTokens; -} - -// return true if everything is ok -bool elysium::update_tally_map(const std::string& who, uint32_t propertyId, int64_t amount, TallyType ttype) -{ - if (0 == amount) { - PrintToLog("%s(%s, %u=0x%X, %+d, ttype=%d) ERROR: amount to credit or debit is zero\n", __func__, who, propertyId, propertyId, amount, ttype); - return false; - } - if (ttype >= TALLY_TYPE_COUNT) { - PrintToLog("%s(%s, %u=0x%X, %+d, ttype=%d) ERROR: invalid tally type\n", __func__, who, propertyId, propertyId, amount, ttype); - return false; - } - - bool bRet = false; - int64_t before = 0; - int64_t after = 0; - - LOCK(cs_main); - - if (ttype == BALANCE && amount < 0) { - assert(!isAddressFrozen(who, propertyId)); // for safety, this should never fail if everything else is working properly. - } - - before = getMPbalance(who, propertyId, ttype); - - std::unordered_map::iterator my_it = mp_tally_map.find(who); - if (my_it == mp_tally_map.end()) { - // insert an empty element - my_it = (mp_tally_map.insert(std::make_pair(who, CMPTally()))).first; - } - - CMPTally& tally = my_it->second; - bRet = tally.updateMoney(propertyId, amount, ttype); - - after = getMPbalance(who, propertyId, ttype); - if (!bRet) { - assert(before == after); - PrintToLog("%s(%s, %u=0x%X, %+d, ttype=%d) ERROR: insufficient balance (=%d)\n", __func__, who, propertyId, propertyId, amount, ttype, before); - } - if (elysium_debug_tally && (CBitcoinAddress(who) != GetSystemAddress() || elysium_debug_ely)) { - PrintToLog("%s(%s, %u=0x%X, %+d, ttype=%d): before=%d, after=%d\n", __func__, who, propertyId, propertyId, amount, ttype, before, after); - } - - return bRet; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// some old TODOs -// 6) verify large-number calculations (especially divisions & multiplications) -// 9) build in consesus checks with the masterchain.info & masterchest.info -- possibly run them automatically, daily (?) -// 10) need a locking mechanism between Core & Qt -- to retrieve the tally, for instance, this and similar to this: LOCK(wallet->cs_wallet); -// - -/** - * Calculates and updates the "development mastercoins". - * - * For every 10 ELYSIUM sold during the Elysium period, 1 additional "Dev ELYSIUM" was generated, - * which are being awarded to the Elysium address slowly over the years. - * - * @see The "Dev ELYSIUM" specification: - * https://github.com/ElysiumLayer/spec#development-mastercoins-dev-elysium-previously-reward-mastercoins - * - * Note: - * If timestamps are out of order, then previously vested "Dev ELYSIUM" are not voided. - * - * @param nTime The timestamp of the block to update the "Dev ELYSIUM" for - * @return The number of "Dev ELYSIUM" generated - */ -static int64_t calculate_and_update_develysium(unsigned int nTime, int block) -{ - // do nothing if before end of fundraiser - if (nTime < 1377993874) return 0; - - // taken mainly from elysium_validate.py: def get_available_reward(height, c) - int64_t develysium = 0; - int64_t elysium_delta = 0; - // spec constants: - const int64_t all_reward = 5631623576222; - const double seconds_in_one_year = 31556926; - const double seconds_passed = nTime - 1377993874; // elysium bootstrap deadline - const double years = seconds_passed / seconds_in_one_year; - const double part_available = 1 - pow(0.5, years); - const double available_reward = all_reward * part_available; - - develysium = rounduint64(available_reward); - elysium_delta = develysium - elysium_prev; - - if (elysium_debug_ely) PrintToLog("develysium=%d, elysium_prev=%d, elysium_delta=%d\n", develysium, elysium_prev, elysium_delta); - - // skip if a block's timestamp is older than that of a previous one! - if (0 > elysium_delta) return 0; - - // sanity check that develysium isn't an impossible value - if (develysium > all_reward || 0 > develysium) { - PrintToLog("%s(): ERROR: insane number of Dev ELYSIUM (nTime=%d, elysium_prev=%d, develysium=%d)\n", __func__, nTime, elysium_prev, develysium); - return 0; - } - - if (elysium_delta > 0) { - update_tally_map(GetSystemAddress().ToString(), ELYSIUM_PROPERTY_ELYSIUM, elysium_delta, BALANCE); - elysium_prev = develysium; - } - - NotifyTotalTokensChanged(ELYSIUM_PROPERTY_ELYSIUM, block); - - return elysium_delta; -} - -uint32_t elysium::GetNextPropertyId(bool maineco) -{ - if (maineco) { - return _my_sps->peekNextSPID(1); - } else { - return _my_sps->peekNextSPID(2); - } -} - -// Perform any actions that need to be taken when the total number of tokens for a property ID changes -void NotifyTotalTokensChanged(uint32_t propertyId, int block) -{ - p_feecache->UpdateDistributionThresholds(propertyId); - p_feecache->EvalCache(propertyId, block); -} - -void CheckWalletUpdate(bool forceUpdate) -{ - if (!WalletCacheUpdate()) { - // no balance changes were detected that affect wallet addresses, signal a generic change to overall Elysium state - if (!forceUpdate) { - uiInterface.ElysiumStateChanged(); - return; - } - } -#ifdef ENABLE_WALLET - LOCK(cs_main); - - // balance changes were found in the wallet, update the global totals and signal a Elysium balance change - global_balance_money.clear(); - global_balance_reserved.clear(); - - // populate global balance totals and wallet property list - note global balances do not include additional balances from watch-only addresses - for (std::unordered_map::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) { - // check if the address is a wallet address (including watched addresses) - std::string address = my_it->first; - int addressIsMine = IsMyAddress(address); - if (!addressIsMine) continue; - // iterate only those properties in the TokenMap for this address - my_it->second.init(); - uint32_t propertyId; - while (0 != (propertyId = (my_it->second).next())) { - // add to the global wallet property list - global_wallet_property_list.insert(propertyId); - // check if the address is spendable (only spendable balances are included in totals) - if (addressIsMine != ISMINE_SPENDABLE) continue; - // work out the balances and add to globals - global_balance_money[propertyId] += getUserAvailableMPbalance(address, propertyId); - global_balance_reserved[propertyId] += getMPbalance(address, propertyId, SELLOFFER_RESERVE); - global_balance_reserved[propertyId] += getMPbalance(address, propertyId, METADEX_RESERVE); - global_balance_reserved[propertyId] += getMPbalance(address, propertyId, ACCEPT_RESERVE); - } - } - // signal an Elysium balance change - uiInterface.ElysiumBalanceChanged(); -#endif -} - -// TODO: move -CCoinsView elysium::viewDummy; -CCoinsViewCache elysium::view(&viewDummy); - -//! Guards coins view cache -CCriticalSection elysium::cs_tx_cache; - -static unsigned int nCacheHits = 0; -static unsigned int nCacheMiss = 0; - -/** - * Fetches transaction inputs and adds them to the coins view cache. - * - * Note: cs_tx_cache should be locked, when adding and accessing inputs! - * - * @param tx[in] The transaction to fetch inputs for - * @return True, if all inputs were successfully added to the cache - */ -static bool FillTxInputCache(const CTransaction& tx) -{ - static unsigned int nCacheSize = GetArg("-elysiumtxcache", 500000); - - if (view.GetCacheSize() > nCacheSize) { - PrintToLog("%s(): clearing cache before insertion [size=%d, hit=%d, miss=%d]\n", - __func__, view.GetCacheSize(), nCacheHits, nCacheMiss); - view.Flush(); - } - - for (std::vector::const_iterator it = tx.vin.begin(); it != tx.vin.end(); ++it) { - const CTxIn& txIn = *it; - - if (it->scriptSig.IsSigmaSpend()) { - continue; - } - - unsigned int nOut = txIn.prevout.n; - Coin coin = view.AccessCoin(txIn.prevout); - - if (!coin.IsSpent()) { - ++nCacheHits; - continue; - } else { - ++nCacheMiss; - } - - CTransactionRef txPrev; - uint256 hashBlock; - if (!GetTransaction(txIn.prevout.hash, txPrev, Params().GetConsensus(), hashBlock, true)) { - return false; - } - - coin.out.scriptPubKey = txPrev->vout[nOut].scriptPubKey; - coin.out.nValue = txPrev->vout[nOut].nValue; - view.AddCoin(txIn.prevout, std::move(coin), true); - } - - return true; -} - -// idx is position within the block, 0-based -// int elysium_tx_push(const CTransaction &wtx, int nBlock, unsigned int idx) -// INPUT: bRPConly -- set to true to avoid moving funds; to be called from various RPC calls like this -// RETURNS: 0 if parsed a MP TX -// RETURNS: < 0 if a non-MP-TX or invalid -// RETURNS: >0 if 1 or more payments have been made -static int parseTransaction(bool bRPConly, const CTransaction& wtx, int nBlock, unsigned int idx, CMPTransaction& mp_tx, unsigned int nTime) -{ - InputMode inputMode = InputMode::NORMAL; - if (wtx.IsSigmaSpend()) { - inputMode = InputMode::SIGMA; - } - - assert(bRPConly == mp_tx.isRpcOnly()); - mp_tx.Set(wtx.GetHash(), nBlock, idx, nTime); - - // ### CLASS IDENTIFICATION AND MARKER CHECK ### - auto elysiumClass = DeterminePacketClass(wtx, nBlock); - - if (!elysiumClass) { - return -1; // No Elysium/Elysium marker, thus not a valid Elysium transaction - } - - if (!bRPConly || elysium_debug_parser_readonly) { - PrintToLog("____________________________________________________________________________________________________________________________________\n"); - PrintToLog("%s(block=%d, %s idx= %d); txid: %s\n", __FUNCTION__, nBlock, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTime), idx, wtx.GetHash().GetHex()); - } - - // ### SENDER IDENTIFICATION ### - boost::optional sender; - int64_t inAll = 0; - - { // needed to ensure the cache isn't cleared in the meantime when doing parallel queries - LOCK(cs_tx_cache); - - // Add previous transaction inputs to the cache - if (!FillTxInputCache(wtx)) { - PrintToLog("%s() ERROR: failed to get inputs for %s\n", __func__, wtx.GetHash().GetHex()); - return -101; - } - - assert(view.HaveInputs(wtx)); - - if (*elysiumClass != PacketClass::C) { - if (inputMode != InputMode::NORMAL) { - PrintToLog("%s() ERROR: other input than normal is not allowed when packet class is not C\n", __func__, wtx.GetHash().GetHex()); - return -101; - } - - // OLD LOGIC - collect input amounts and identify sender via "largest input by sum" - std::map inputs_sum_of_values; - - for (unsigned int i = 0; i < wtx.vin.size(); ++i) { - if (elysium_debug_vin) PrintToLog("vin=%d:%s\n", i, ScriptToAsmStr(wtx.vin[i].scriptSig)); - - const CTxIn& txIn = wtx.vin[i]; - const Coin& txOut = view.AccessCoin(txIn.prevout); - - CTxDestination source; - txnouttype whichType; - if (!GetOutputType(txOut.out.scriptPubKey, whichType)) { - return -104; - } - if (!IsAllowedInputType(whichType, nBlock)) { - return -105; - } - if (ExtractDestination(txOut.out.scriptPubKey, source)) { // extract the destination of the previous transaction's vout[n] and check it's allowed type - inputs_sum_of_values[CBitcoinAddress(source)] += txOut.out.nValue; - } - else return -106; - } - - int64_t nMax = 0; - for (auto it = inputs_sum_of_values.begin(); it != inputs_sum_of_values.end(); ++it) { // find largest by sum - int64_t nTemp = it->second; - if (nTemp > nMax) { - sender = it->first; - if (elysium_debug_ely) PrintToLog("looking for The Sender: %s , nMax=%lu, nTemp=%d\n", sender->ToString(), nMax, nTemp); - nMax = nTemp; - } - } - - if (!sender) { - PrintToLog("Failed to determine sender for transaction %s\n", wtx.GetHash().GetHex()); - return -5; - } - } - else if (inputMode != InputMode::SIGMA) - { - // NEW LOGIC - the sender is chosen based on the first vin - - // determine the sender, but invalidate transaction, if the input is not accepted - - // do not need to check sigma. - - unsigned int vin_n = 0; // the first input - if (elysium_debug_vin) PrintToLog("vin=%d:%s\n", vin_n, ScriptToAsmStr(wtx.vin[vin_n].scriptSig)); - - const CTxIn& txIn = wtx.vin[vin_n]; - const Coin& txOut = view.AccessCoin(txIn.prevout); - - txnouttype whichType; - if (!GetOutputType(txOut.out.scriptPubKey, whichType)) { - return -108; - } - if (!IsAllowedInputType(whichType, nBlock)) { - return -109; - } - CTxDestination source; - if (ExtractDestination(txOut.out.scriptPubKey, source)) { - sender = source; - } - else return -110; - } - - switch (inputMode) { - case InputMode::SIGMA: - inAll = sigma::GetSpendAmount(wtx); - break; - case InputMode::NORMAL: - default: - inAll = view.GetValueIn(wtx); - break; - } - - } // end of LOCK(cs_tx_cache) - - int64_t outAll = wtx.GetValueOut(); - - // ### DATA POPULATION ### - save output addresses, values and scripts - boost::optional referenceAddr; - boost::optional referenceAmount; - std::vector payload; - std::vector address_data; - std::vector value_data; - - for (unsigned int n = 0; n < wtx.vout.size(); ++n) { - txnouttype whichType; - if (!GetOutputType(wtx.vout[n].scriptPubKey, whichType)) { - continue; - } - if (!IsAllowedOutputType(whichType, nBlock)) { - continue; - } - CTxDestination dest; - if (ExtractDestination(wtx.vout[n].scriptPubKey, dest)) { - CBitcoinAddress address(dest); - if (address != GetSystemAddress()) { - // saving for reference - address_data.push_back(address); - value_data.push_back(wtx.vout[n].nValue); - if (elysium_debug_parser_data) PrintToLog("saving address_data #%d: %s:%s\n", n, address.ToString(), ScriptToAsmStr(wtx.vout[n].scriptPubKey)); - } - } - } - if (elysium_debug_parser_data) PrintToLog(" address_data.size=%lu\n value_data.size=%lu\n", address_data.size(), value_data.size()); - - // ### CLASS B / CLASS C PARSING ### - if (elysium_debug_parser_data) PrintToLog("Beginning reference identification\n"); - - bool changeRemoved = false; // bool to hold whether we've ignored the first output to sender as change - unsigned int potentialReferenceOutputs = 0; // int to hold number of potential reference outputs - for (unsigned k = 0; k < address_data.size(); ++k) { // how many potential reference outputs do we have, if just one select it right here - auto& addr = address_data[k]; - if (elysium_debug_parser_data) PrintToLog("ref? data[%d]: %s (%s)\n", k, addr.ToString(), FormatIndivisibleMP(value_data[k])); - - ++potentialReferenceOutputs; - if (1 == potentialReferenceOutputs) { - referenceAddr = addr; - referenceAmount = value_data[k]; - if (elysium_debug_parser_data) PrintToLog("Single reference potentially id'd as follows: %s \n", referenceAddr->ToString()); - } else { //as soon as potentialReferenceOutputs > 1 we need to go fishing - referenceAddr = boost::none; // avoid leaving referenceAddr populated for sanity - referenceAmount = boost::none; - if (elysium_debug_parser_data) PrintToLog("More than one potential reference candidate, blanking referenceAddr, need to go fishing\n"); - } - } - if (!referenceAddr) { // do we have a reference now? or do we need to dig deeper - if (elysium_debug_parser_data) PrintToLog("Reference has not been found yet, going fishing\n"); - for (unsigned k = 0; k < address_data.size(); ++k) { - auto& addr = address_data[k]; - - if (sender && !changeRemoved && addr == *sender) { - changeRemoved = true; // per spec ignore first output to sender as change if multiple possible ref addresses - if (elysium_debug_parser_data) PrintToLog("Removed change\n"); - } else { - referenceAddr = addr; // this may be set several times, but last time will be highest vout - referenceAmount = value_data[k]; - if (elysium_debug_parser_data) PrintToLog("Resetting referenceAddr as follows: %s \n ", referenceAddr->ToString()); - } - } - } - - if (*elysiumClass == PacketClass::B) { - // ### CLASS B SPECIFC PARSING ### - std::vector> multisig_script_data; - - // ### POPULATE MULTISIG SCRIPT DATA ### - for (unsigned int i = 0; i < wtx.vout.size(); ++i) { - txnouttype whichType; - std::vector vDest; - int nRequired; - if (elysium_debug_script) PrintToLog("scriptPubKey: %s\n", HexStr(wtx.vout[i].scriptPubKey)); - if (!ExtractDestinations(wtx.vout[i].scriptPubKey, whichType, vDest, nRequired)) { - continue; - } - if (whichType == TX_MULTISIG) { - if (elysium_debug_script) { - PrintToLog(" >> multisig: "); - BOOST_FOREACH(const CTxDestination& dest, vDest) { - PrintToLog("%s ; ", CBitcoinAddress(dest).ToString()); - } - PrintToLog("\n"); - } - // ignore first public key, as it should belong to the sender - // and it be used to avoid the creation of unspendable dust - std::vector> pushes; - - GetPushedValues(wtx.vout[i].scriptPubKey, std::back_inserter(pushes)); - - for (auto it = pushes.begin() + 1; it < pushes.end(); it++) { - multisig_script_data.push_back(std::move(*it)); - } - } - } - - // The number of packets is limited to MAX_PACKETS, - // which allows, at least in theory, to add 1 byte - // sequence numbers to each packet. - - // Transactions with more than MAX_PACKET packets - // are not invalidated, but trimmed. - - unsigned int nPackets = multisig_script_data.size(); - if (nPackets > CLASS_B_MAX_CHUNKS) { - nPackets = CLASS_B_MAX_CHUNKS; - PrintToLog("limiting number of packets to %d [extracted=%d]\n", nPackets, multisig_script_data.size()); - } - - // ### PREPARE A FEW VARS ### - PacketKeyGenerator keyGenerator(sender->ToString()); - unsigned char packets[CLASS_B_MAX_CHUNKS][32]; - unsigned int mdata_count = 0; // multisig data count - - // ### DEOBFUSCATE MULTISIG PACKETS ### - for (unsigned int k = 0; k < nPackets; ++k) { - assert(mdata_count < CLASS_B_MAX_CHUNKS); - - auto hash = keyGenerator.Next(); - std::array packet; - - std::copy_n(multisig_script_data[k].begin() + 1, CLASS_B_CHUNK_SIZE, packet.begin()); - - for (unsigned int i = 0; i < packet.size(); i++) { // this is a data packet, must deobfuscate now - packet[i] ^= hash[i]; - } - memcpy(&packets[mdata_count], packet.data(), CLASS_B_CHUNK_SIZE); - ++mdata_count; - - if (elysium_debug_parser_data) { - CPubKey key(multisig_script_data[k]); - CKeyID keyID = key.GetID(); - std::string strAddress = CBitcoinAddress(keyID).ToString(); - PrintToLog("multisig_data[%d]:%s: %s\n", k, HexStr(multisig_script_data[k]), strAddress); - } - if (elysium_debug_parser) { - std::string strPacket = HexStr(packet.begin(), packet.end()); - PrintToLog("packet #%d: %s\n", mdata_count, strPacket); - } - } - - // ### FINALIZE CLASS B ### - for (unsigned int m = 0; m < mdata_count; ++m) { // now decode mastercoin packets - if (elysium_debug_parser) PrintToLog("m=%d: %s\n", m, HexStr(packets[m], packets[m] + CLASS_B_CHUNK_SIZE, false)); - - // check to ensure the sequence numbers are sequential and begin with 01 ! - if (1 + m != packets[m][0]) { - if (elysium_debug_spec) PrintToLog("Error: non-sequential seqnum ! expected=%d, got=%d\n", 1+m, packets[m][0]); - } - - payload.insert(payload.end(), packets[m] + 1, packets[m] + CLASS_B_CHUNK_SIZE); - } - } else if (*elysiumClass == PacketClass::C) { - // ### CLASS C SPECIFIC PARSING ### - std::vector> op_return_script_data; - - // ### POPULATE OP RETURN SCRIPT DATA ### - for (unsigned int n = 0; n < wtx.vout.size(); ++n) { - txnouttype whichType; - if (!GetOutputType(wtx.vout[n].scriptPubKey, whichType)) { - continue; - } - if (!IsAllowedOutputType(whichType, nBlock)) { - continue; - } - if (whichType == TX_NULL_DATA) { - // only consider outputs, which are explicitly tagged - std::vector> pushes; - - GetPushedValues(wtx.vout[n].scriptPubKey, std::back_inserter(pushes)); - - if (pushes.empty() || pushes[0].size() < magic.size() || !std::equal(magic.begin(), magic.end(), pushes[0].begin())) { - continue; - } - - // Strip out the magic at the very beginning - pushes[0].erase(pushes[0].begin(), pushes[0].begin() + magic.size()); - - op_return_script_data.insert( - op_return_script_data.end(), - std::make_move_iterator(pushes.begin()), - std::make_move_iterator(pushes.end()) - ); - - if (elysium_debug_parser_data) { - PrintToLog("Class C transaction detected: %s parsed to %s at vout %d\n", wtx.GetHash().GetHex(), HexStr(pushes[0]), n); - } - } - } - // ### EXTRACT PAYLOAD FOR CLASS C ### - for (unsigned int n = 0; n < op_return_script_data.size(); ++n) { - if (!op_return_script_data[n].empty()) { - auto& vch = op_return_script_data[n]; - unsigned int payload_size = vch.size(); - - // Actually CLASS_B_MAX_CHUNKS * CLASS_B_CHUNK_SIZE is not right but we can't fix it due to - // it break consensus. - if (payload.size() + payload_size > CLASS_B_MAX_CHUNKS * CLASS_B_CHUNK_SIZE) { - payload_size = CLASS_B_MAX_CHUNKS * CLASS_B_CHUNK_SIZE - payload.size(); - PrintToLog("limiting payload size to %d byte\n", payload.size() + payload_size); - } - if (payload_size > 0) { - payload.insert(payload.end(), vch.begin(), vch.begin() + payload_size); - } - if (CLASS_B_MAX_CHUNKS * CLASS_B_CHUNK_SIZE == payload.size()) { - break; - } - } - } - } - - // ### SET MP TX INFO ### - if (elysium_debug_verbose) PrintToLog("single_pkt: %s\n", HexStr(payload)); - - mp_tx.Set( - sender ? sender->ToString() : "", - referenceAddr ? referenceAddr->ToString() : "", - 0, - wtx.GetHash(), - nBlock, - idx, - payload.data(), - payload.size(), - elysiumClass, - inAll - outAll, - referenceAmount - ); - - return 0; -} - -/** - * Provides access to parseTransaction in read-only mode. - */ -int ParseTransaction(const CTransaction& tx, int nBlock, unsigned int idx, CMPTransaction& mptx, unsigned int nTime) -{ - return parseTransaction(true, tx, nBlock, idx, mptx, nTime); -} - -/** - * Reports the progress of the initial transaction scanning. - * - * The progress is printed to the console, written to the debug log file, and - * the RPC status, as well as the splash screen progress label, are updated. - * - * @see elysium_initial_scan() - */ -class ProgressReporter -{ -private: - const CBlockIndex* m_pblockFirst; - const CBlockIndex* m_pblockLast; - const int64_t m_timeStart; - - /** Returns the estimated remaining time in milliseconds. */ - int64_t estimateRemainingTime(double progress) const - { - int64_t timeSinceStart = GetTimeMillis() - m_timeStart; - - double timeRemaining = 3600000.0; // 1 hour - if (progress > 0.0 && timeSinceStart > 0) { - timeRemaining = (100.0 - progress) / progress * timeSinceStart; - } - - return static_cast(timeRemaining); - } - - /** Converts a time span to a human readable string. */ - std::string remainingTimeAsString(int64_t remainingTime) const - { - int64_t secondsTotal = 0.001 * remainingTime; - int64_t hours = secondsTotal / 3600; - int64_t minutes = secondsTotal / 60; - int64_t seconds = secondsTotal % 60; - - if (hours > 0) { - return strprintf("%d:%02d:%02d hours", hours, minutes, seconds); - } else if (minutes > 0) { - return strprintf("%d:%02d minutes", minutes, seconds); - } else { - return strprintf("%d seconds", seconds); - } - } - -public: - ProgressReporter(const CBlockIndex* pblockFirst, const CBlockIndex* pblockLast) - : m_pblockFirst(pblockFirst), m_pblockLast(pblockLast), m_timeStart(GetTimeMillis()) - { - } - - /** Prints the current progress to the console and notifies the UI. */ - void update(const CBlockIndex* pblockNow) const - { - int nLastBlock = m_pblockLast->nHeight; - int nCurrentBlock = pblockNow->nHeight; - unsigned int nFirst = m_pblockFirst->nChainTx; - unsigned int nCurrent = pblockNow->nChainTx; - unsigned int nLast = m_pblockLast->nChainTx; - - double dProgress = 100.0 * (nCurrent - nFirst) / (nLast - nFirst); - int64_t nRemainingTime = estimateRemainingTime(dProgress); - - std::string strProgress = strprintf( - "Still scanning.. at block %d of %d. Progress: %.2f %%, about %s remaining..\n", - nCurrentBlock, nLastBlock, dProgress, remainingTimeAsString(nRemainingTime)); - std::string strProgressUI = strprintf( - "Still scanning.. at block %d of %d.\nProgress: %.2f %% (about %s remaining)", - nCurrentBlock, nLastBlock, dProgress, remainingTimeAsString(nRemainingTime)); - - PrintToLog(strProgress); - uiInterface.InitMessage(strProgressUI); - } -}; - -/** - * Scans the blockchain for meta transactions. - * - * It scans the blockchain, starting at the given block index, to the current - * tip, much like as if new block were arriving and being processed on the fly. - * - * Every 30 seconds the progress of the scan is reported. - * - * In case the current block being processed is not part of the active chain, or - * if a block could not be retrieved from the disk, then the scan stops early. - * Likewise, global shutdown requests are honored, and stop the scan progress. - * - * @see elysium_handler_block_begin() - * @see elysium_handler_tx() - * @see elysium_handler_block_end() - * - * @param nFirstBlock[in] The index of the first block to scan - * @return An exit code, indicating success or failure - */ -static int elysium_initial_scan(int nFirstBlock) -{ - int nTimeBetweenProgressReports = GetArg("-elysiumprogressfrequency", 30); // seconds - int64_t nNow = GetTime(); - size_t nTxsTotal = 0, nTxsFoundTotal = 0; - int nBlock = 999999; - const int nLastBlock = GetHeight(); - - // this function is useless if there are not enough blocks in the blockchain yet! - if (nFirstBlock < 0 || nLastBlock < nFirstBlock) return -1; - PrintToLog("Scanning for transactions in block %d to block %d..\n", nFirstBlock, nLastBlock); - - // used to print the progress to the console and notifies the UI - ProgressReporter progressReporter(chainActive[nFirstBlock], chainActive[nLastBlock]); - - for (nBlock = nFirstBlock; nBlock <= nLastBlock; ++nBlock) - { - if (ShutdownRequested()) { - PrintToLog("Shutdown requested, stop scan at block %d of %d\n", nBlock, nLastBlock); - break; - } - - CBlockIndex* pblockindex = chainActive[nBlock]; - if (NULL == pblockindex) break; - std::string strBlockHash = pblockindex->GetBlockHash().GetHex(); - - if (elysium_debug_ely) PrintToLog("%s(%d; max=%d):%s, line %d, file: %s\n", - __FUNCTION__, nBlock, nLastBlock, strBlockHash, __LINE__, __FILE__); - - if (GetTime() >= nNow + nTimeBetweenProgressReports) { - progressReporter.update(pblockindex); - nNow = GetTime(); - } - - // Get block to parse. - CBlock block; - - if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) { - break; - } - - // Parse block. - unsigned parsed = 0; - - elysium_handler_block_begin(nBlock, pblockindex); - - for (unsigned i = 0; i < block.vtx.size(); i++) { - if (elysium_handler_tx(*block.vtx[i], nBlock, i, pblockindex)) { - parsed++; - } - } - - elysium_handler_block_end(nBlock, pblockindex, parsed); - - // Sum total parsed. - nTxsFoundTotal += parsed; - nTxsTotal += block.vtx.size(); - } - - if (nBlock < nLastBlock) { - PrintToLog("Scan stopped early at block %d of block %d\n", nBlock, nLastBlock); - } - - PrintToLog("%zu transactions processed, %zu meta transactions found\n", nTxsTotal, nTxsFoundTotal); - - return 0; -} - -int input_elysium_balances_string(const std::string& s) -{ - // "address=propertybalancedata" - std::vector addrData; - boost::split(addrData, s, boost::is_any_of("="), boost::token_compress_on); - if (addrData.size() != 2) return -1; - - std::string strAddress = addrData[0]; - - // split the tuples of properties - std::vector vProperties; - boost::split(vProperties, addrData[1], boost::is_any_of(";"), boost::token_compress_on); - - std::vector::const_iterator iter; - for (iter = vProperties.begin(); iter != vProperties.end(); ++iter) { - if ((*iter).empty()) { - continue; - } - - // "propertyid:balancedata" - std::vector curProperty; - boost::split(curProperty, *iter, boost::is_any_of(":"), boost::token_compress_on); - if (curProperty.size() != 2) return -1; - - // "balance,sellreserved,acceptreserved,metadexreserved" - std::vector curBalance; - boost::split(curBalance, curProperty[1], boost::is_any_of(","), boost::token_compress_on); - if (curBalance.size() != 4) return -1; - - uint32_t propertyId = boost::lexical_cast(curProperty[0]); - - int64_t balance = boost::lexical_cast(curBalance[0]); - int64_t sellReserved = boost::lexical_cast(curBalance[1]); - int64_t acceptReserved = boost::lexical_cast(curBalance[2]); - int64_t metadexReserved = boost::lexical_cast(curBalance[3]); - - if (balance) update_tally_map(strAddress, propertyId, balance, BALANCE); - if (sellReserved) update_tally_map(strAddress, propertyId, sellReserved, SELLOFFER_RESERVE); - if (acceptReserved) update_tally_map(strAddress, propertyId, acceptReserved, ACCEPT_RESERVE); - if (metadexReserved) update_tally_map(strAddress, propertyId, metadexReserved, METADEX_RESERVE); - } - - return 0; -} - -// seller-address, offer_block, amount, property, desired BTC , property_desired, fee, blocktimelimit -// 13z1JFtDMGTYQvtMq5gs4LmCztK3rmEZga,299076,76375000,1,6415500,0,10000,6 -int input_mp_offers_string(const std::string& s) -{ - std::vector vstr; - boost::split(vstr, s, boost::is_any_of(" ,="), boost::token_compress_on); - - if (9 != vstr.size()) return -1; - - int i = 0; - - std::string sellerAddr = vstr[i++]; - int offerBlock = boost::lexical_cast(vstr[i++]); - int64_t amountOriginal = boost::lexical_cast(vstr[i++]); - uint32_t prop = boost::lexical_cast(vstr[i++]); - int64_t btcDesired = boost::lexical_cast(vstr[i++]); - uint32_t prop_desired = boost::lexical_cast(vstr[i++]); - int64_t minFee = boost::lexical_cast(vstr[i++]); - uint8_t blocktimelimit = boost::lexical_cast(vstr[i++]); // lexical_cast can't handle char! - uint256 txid = uint256S(vstr[i++]); - - // TODO: should this be here? There are usually no sanity checks.. - if (ELYSIUM_PROPERTY_XZC != prop_desired) return -1; - - const std::string combo = STR_SELLOFFER_ADDR_PROP_COMBO(sellerAddr, prop); - CMPOffer newOffer(offerBlock, amountOriginal, prop, btcDesired, minFee, blocktimelimit, txid); - - if (!my_offers.insert(std::make_pair(combo, newOffer)).second) return -1; - - return 0; -} - -// seller-address, property, buyer-address, amount, fee, block -// 13z1JFtDMGTYQvtMq5gs4LmCztK3rmEZga,1, 148EFCFXbk2LrUhEHDfs9y3A5dJ4tttKVd,100000,11000,299126 -// 13z1JFtDMGTYQvtMq5gs4LmCztK3rmEZga,1,1Md8GwMtWpiobRnjRabMT98EW6Jh4rEUNy,50000000,11000,299132 -int input_mp_accepts_string(const string &s) -{ - int nBlock; - unsigned char blocktimelimit; - std::vector vstr; - boost::split(vstr, s, boost::is_any_of(" ,="), token_compress_on); - uint64_t amountRemaining, amountOriginal, offerOriginal, btcDesired; - unsigned int prop; - string sellerAddr, buyerAddr, txidStr; - int i = 0; - - if (10 != vstr.size()) return -1; - - sellerAddr = vstr[i++]; - prop = boost::lexical_cast(vstr[i++]); - buyerAddr = vstr[i++]; - nBlock = atoi(vstr[i++]); - amountRemaining = boost::lexical_cast(vstr[i++]); - amountOriginal = boost::lexical_cast(vstr[i++]); - blocktimelimit = atoi(vstr[i++]); - offerOriginal = boost::lexical_cast(vstr[i++]); - btcDesired = boost::lexical_cast(vstr[i++]); - txidStr = vstr[i++]; - - const string combo = STR_ACCEPT_ADDR_PROP_ADDR_COMBO(sellerAddr, buyerAddr, prop); - CMPAccept newAccept(amountOriginal, amountRemaining, nBlock, blocktimelimit, prop, offerOriginal, btcDesired, uint256S(txidStr)); - if (my_accepts.insert(std::make_pair(combo, newAccept)).second) { - return 0; - } else { - return -1; - } -} - -// elysium_prev -int input_globals_state_string(const string &s) -{ - uint64_t elysiumPrev; - unsigned int nextSPID, nextTestSPID; - std::vector vstr; - boost::split(vstr, s, boost::is_any_of(" ,="), token_compress_on); - if (3 != vstr.size()) return -1; - - int i = 0; - elysiumPrev = boost::lexical_cast(vstr[i++]); - nextSPID = boost::lexical_cast(vstr[i++]); - nextTestSPID = boost::lexical_cast(vstr[i++]); - - elysium_prev = elysiumPrev; - _my_sps->init(nextSPID, nextTestSPID); - return 0; -} - -// addr,propertyId,nValue,property_desired,deadline,early_bird,percentage,txid -int input_mp_crowdsale_string(const std::string& s) -{ - std::vector vstr; - boost::split(vstr, s, boost::is_any_of(" ,"), boost::token_compress_on); - - if (9 > vstr.size()) return -1; - - unsigned int i = 0; - - std::string sellerAddr = vstr[i++]; - uint32_t propertyId = boost::lexical_cast(vstr[i++]); - int64_t nValue = boost::lexical_cast(vstr[i++]); - uint32_t property_desired = boost::lexical_cast(vstr[i++]); - int64_t deadline = boost::lexical_cast(vstr[i++]); - uint8_t early_bird = boost::lexical_cast(vstr[i++]); // lexical_cast can't handle char! - uint8_t percentage = boost::lexical_cast(vstr[i++]); // lexical_cast can't handle char! - int64_t u_created = boost::lexical_cast(vstr[i++]); - int64_t i_created = boost::lexical_cast(vstr[i++]); - - CMPCrowd newCrowdsale(propertyId, nValue, property_desired, deadline, early_bird, percentage, u_created, i_created); - - // load the remaining as database pairs - while (i < vstr.size()) { - std::vector entryData; - boost::split(entryData, vstr[i++], boost::is_any_of("="), boost::token_compress_on); - if (2 != entryData.size()) return -1; - - std::vector valueData; - boost::split(valueData, entryData[1], boost::is_any_of(";"), boost::token_compress_on); - - std::vector vals; - for (std::vector::const_iterator it = valueData.begin(); it != valueData.end(); ++it) { - vals.push_back(boost::lexical_cast(*it)); - } - - uint256 txHash = uint256S(entryData[0]); - newCrowdsale.insertDatabase(txHash, vals); - } - - if (!my_crowds.insert(std::make_pair(sellerAddr, newCrowdsale)).second) { - return -1; - } - - return 0; -} - -// address, block, amount for sale, property, amount desired, property desired, subaction, idx, txid, amount remaining -int input_mp_mdexorder_string(const std::string& s) -{ - std::vector vstr; - boost::split(vstr, s, boost::is_any_of(" ,="), boost::token_compress_on); - - if (10 != vstr.size()) return -1; - - int i = 0; - - std::string addr = vstr[i++]; - int block = boost::lexical_cast(vstr[i++]); - int64_t amount_forsale = boost::lexical_cast(vstr[i++]); - uint32_t property = boost::lexical_cast(vstr[i++]); - int64_t amount_desired = boost::lexical_cast(vstr[i++]); - uint32_t desired_property = boost::lexical_cast(vstr[i++]); - uint8_t subaction = boost::lexical_cast(vstr[i++]); // lexical_cast can't handle char! - unsigned int idx = boost::lexical_cast(vstr[i++]); - uint256 txid = uint256S(vstr[i++]); - int64_t amount_remaining = boost::lexical_cast(vstr[i++]); - - CMPMetaDEx mdexObj(addr, block, property, amount_forsale, desired_property, - amount_desired, txid, idx, subaction, amount_remaining); - - if (!MetaDEx_INSERT(mdexObj)) return -1; - - return 0; -} - -static int elysium_file_load(const string &filename, int what, bool verifyHash = false) -{ - int lines = 0; - int (*inputLineFunc)(const string &) = NULL; - - SHA256_CTX shaCtx; - SHA256_Init(&shaCtx); - - switch (what) - { - case FILETYPE_BALANCES: - mp_tally_map.clear(); - inputLineFunc = input_elysium_balances_string; - break; - - case FILETYPE_OFFERS: - my_offers.clear(); - inputLineFunc = input_mp_offers_string; - break; - - case FILETYPE_ACCEPTS: - my_accepts.clear(); - inputLineFunc = input_mp_accepts_string; - break; - - case FILETYPE_GLOBALS: - inputLineFunc = input_globals_state_string; - break; - - case FILETYPE_CROWDSALES: - my_crowds.clear(); - inputLineFunc = input_mp_crowdsale_string; - break; - - case FILETYPE_MDEXORDERS: - // FIXME - // memory leak ... gotta unallocate inner layers first.... - // TODO - // ... - metadex.clear(); - inputLineFunc = input_mp_mdexorder_string; - break; - - default: - return -1; - } - - if (elysium_debug_persistence) - { - LogPrintf("Loading %s ... \n", filename); - PrintToLog("%s(%s), line %d, file: %s\n", __FUNCTION__, filename, __LINE__, __FILE__); - } - - std::ifstream file; - file.open(filename.c_str()); - if (!file.is_open()) - { - if (elysium_debug_persistence) LogPrintf("%s(%s): file not found, line %d, file: %s\n", __FUNCTION__, filename, __LINE__, __FILE__); - return -1; - } - - int res = 0; - - std::string fileHash; - while (file.good()) - { - std::string line; - std::getline(file, line); - if (line.empty() || line[0] == '#') continue; - - // remove \r if the file came from Windows - line.erase( std::remove( line.begin(), line.end(), '\r' ), line.end() ) ; - - // record and skip hashes in the file - if (line[0] == '!') { - fileHash = line.substr(1); - continue; - } - - // update hash? - if (verifyHash) { - SHA256_Update(&shaCtx, line.c_str(), line.length()); - } - - if (inputLineFunc) { - if (inputLineFunc(line) < 0) { - res = -1; - break; - } - } - - ++lines; - } - - file.close(); - - if (verifyHash && res == 0) { - // generate and wite the double hash of all the contents written - uint256 hash1; - SHA256_Final((unsigned char*)&hash1, &shaCtx); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - - if (false == boost::iequals(hash2.ToString(), fileHash)) { - PrintToLog("File %s loaded, but failed hash validation!\n", filename); - res = -1; - } - } - - PrintToLog("%s(%s), loaded lines= %d, res= %d\n", __FUNCTION__, filename, lines, res); - LogPrintf("%s(): file: %s , loaded lines= %d, res= %d\n", __FUNCTION__, filename, lines, res); - - return res; -} - -static char const * const statePrefix[NUM_FILETYPES] = { - "balances", - "offers", - "accepts", - "globals", - "crowdsales", - "mdexorders", -}; - -// returns the height of the state loaded -static int load_most_relevant_state() -{ - int res = -1; - // check the SP database and roll it back to its latest valid state - // according to the active chain - uint256 spWatermark; - if (!_my_sps->getWatermark(spWatermark)) { - //trigger a full reparse, if the SP database has no watermark - return -1; - } - - CBlockIndex const *spBlockIndex = GetBlockIndex(spWatermark); - if (NULL == spBlockIndex) { - //trigger a full reparse, if the watermark isn't a real block - return -1; - } - - while (NULL != spBlockIndex && false == chainActive.Contains(spBlockIndex)) { - int remainingSPs = _my_sps->popBlock(spBlockIndex->GetBlockHash()); - if (remainingSPs < 0) { - // trigger a full reparse, if the levelDB cannot roll back - return -1; - } /*else if (remainingSPs == 0) { - // potential optimization here? - }*/ - spBlockIndex = spBlockIndex->pprev; - if (spBlockIndex != NULL) { - _my_sps->setWatermark(spBlockIndex->GetBlockHash()); - } - } - - // prepare a set of available files by block hash pruning any that are - // not in the active chain - std::set persistedBlocks; - boost::filesystem::directory_iterator dIter(MPPersistencePath); - boost::filesystem::directory_iterator endIter; - for (; dIter != endIter; ++dIter) { - if (false == boost::filesystem::is_regular_file(dIter->status()) || dIter->path().empty()) { - // skip funny business - continue; - } - - std::string fName = (*--dIter->path().end()).string(); - std::vector vstr; - boost::split(vstr, fName, boost::is_any_of("-."), token_compress_on); - if ( vstr.size() == 3 && - boost::equals(vstr[2], "dat")) { - uint256 blockHash; - blockHash.SetHex(vstr[1]); - CBlockIndex *pBlockIndex = GetBlockIndex(blockHash); - if (pBlockIndex == NULL || false == chainActive.Contains(pBlockIndex)) { - continue; - } - - // this is a valid block in the active chain, store it - persistedBlocks.insert(blockHash); - } - } - - // using the SP's watermark after its fixed-up as the tip - // walk backwards until we find a valid and full set of persisted state files - // for each block we discard, roll back the SP database - // Note: to avoid rolling back all the way to the genesis block (which appears as if client is hung) abort after MAX_STATE_HISTORY attempts - CBlockIndex const *curTip = spBlockIndex; - int abortRollBackBlock; - if (curTip != NULL) abortRollBackBlock = curTip->nHeight - (MAX_STATE_HISTORY+1); - while (NULL != curTip && persistedBlocks.size() > 0 && curTip->nHeight > abortRollBackBlock) { - if (persistedBlocks.find(spBlockIndex->GetBlockHash()) != persistedBlocks.end()) { - int success = -1; - for (int i = 0; i < NUM_FILETYPES; ++i) { - boost::filesystem::path path = MPPersistencePath / strprintf("%s-%s.dat", statePrefix[i], curTip->GetBlockHash().ToString()); - const std::string strFile = path.string(); - success = elysium_file_load(strFile, i, true); - if (success < 0) { - break; - } - } - - if (success >= 0) { - res = curTip->nHeight; - break; - } - - // remove this from the persistedBlock Set - persistedBlocks.erase(spBlockIndex->GetBlockHash()); - } - - // go to the previous block - if (0 > _my_sps->popBlock(curTip->GetBlockHash())) { - // trigger a full reparse, if the levelDB cannot roll back - return -1; - } - curTip = curTip->pprev; - if (curTip != NULL) { - _my_sps->setWatermark(curTip->GetBlockHash()); - } - } - - if (persistedBlocks.size() == 0) { - // trigger a reparse if we exhausted the persistence files without success - return -1; - } - - // return the height of the block we settled at - return res; -} - -static int write_elysium_balances(std::ofstream& file, SHA256_CTX* shaCtx) -{ - std::unordered_map::iterator iter; - for (iter = mp_tally_map.begin(); iter != mp_tally_map.end(); ++iter) { - bool emptyWallet = true; - - std::string lineOut = (*iter).first; - lineOut.append("="); - CMPTally& curAddr = (*iter).second; - curAddr.init(); - uint32_t propertyId = 0; - while (0 != (propertyId = curAddr.next())) { - int64_t balance = (*iter).second.getMoney(propertyId, BALANCE); - int64_t sellReserved = (*iter).second.getMoney(propertyId, SELLOFFER_RESERVE); - int64_t acceptReserved = (*iter).second.getMoney(propertyId, ACCEPT_RESERVE); - int64_t metadexReserved = (*iter).second.getMoney(propertyId, METADEX_RESERVE); - - // we don't allow 0 balances to read in, so if we don't write them - // it makes things match up better between persisted state and processed state - if (0 == balance && 0 == sellReserved && 0 == acceptReserved && 0 == metadexReserved) { - continue; - } - - emptyWallet = false; - - lineOut.append(strprintf("%d:%d,%d,%d,%d;", - propertyId, - balance, - sellReserved, - acceptReserved, - metadexReserved)); - } - - if (false == emptyWallet) { - // add the line to the hash - SHA256_Update(shaCtx, lineOut.c_str(), lineOut.length()); - - // write the line - file << lineOut << endl; - } - } - - return 0; -} - -static int write_mp_offers(ofstream &file, SHA256_CTX *shaCtx) -{ - OfferMap::const_iterator iter; - for (iter = my_offers.begin(); iter != my_offers.end(); ++iter) { - // decompose the key for address - std::vector vstr; - boost::split(vstr, (*iter).first, boost::is_any_of("-"), token_compress_on); - CMPOffer const &offer = (*iter).second; - offer.saveOffer(file, shaCtx, vstr[0]); - } - - - return 0; -} - -static int write_mp_metadex(ofstream &file, SHA256_CTX *shaCtx) -{ - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) - { - md_PricesMap & prices = my_it->second; - for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it) - { - md_Set & indexes = (it->second); - for (md_Set::iterator it = indexes.begin(); it != indexes.end(); ++it) - { - CMPMetaDEx meta = *it; - meta.saveOffer(file, shaCtx); - } - } - } - - return 0; -} - -static int write_mp_accepts(ofstream &file, SHA256_CTX *shaCtx) -{ - AcceptMap::const_iterator iter; - for (iter = my_accepts.begin(); iter != my_accepts.end(); ++iter) { - // decompose the key for address - std::vector vstr; - boost::split(vstr, (*iter).first, boost::is_any_of("-+"), token_compress_on); - CMPAccept const &accept = (*iter).second; - accept.saveAccept(file, shaCtx, vstr[0], vstr[1]); - } - - return 0; -} - -static int write_globals_state(ofstream &file, SHA256_CTX *shaCtx) -{ - unsigned int nextSPID = _my_sps->peekNextSPID(ELYSIUM_PROPERTY_ELYSIUM); - unsigned int nextTestSPID = _my_sps->peekNextSPID(ELYSIUM_PROPERTY_TELYSIUM); - std::string lineOut = strprintf("%d,%d,%d", - elysium_prev, - nextSPID, - nextTestSPID); - - // add the line to the hash - SHA256_Update(shaCtx, lineOut.c_str(), lineOut.length()); - - // write the line - file << lineOut << endl; - - return 0; -} - -static int write_mp_crowdsales(std::ofstream& file, SHA256_CTX* shaCtx) -{ - for (CrowdMap::const_iterator it = my_crowds.begin(); it != my_crowds.end(); ++it) { - // decompose the key for address - const CMPCrowd& crowd = it->second; - crowd.saveCrowdSale(file, shaCtx, it->first); - } - - return 0; -} - -static int write_state_file( CBlockIndex const *pBlockIndex, int what ) -{ - boost::filesystem::path path = MPPersistencePath / strprintf("%s-%s.dat", statePrefix[what], pBlockIndex->GetBlockHash().ToString()); - const std::string strFile = path.string(); - - std::ofstream file; - file.open(strFile.c_str()); - - SHA256_CTX shaCtx; - SHA256_Init(&shaCtx); - - int result = 0; - - switch(what) { - case FILETYPE_BALANCES: - result = write_elysium_balances(file, &shaCtx); - break; - - case FILETYPE_OFFERS: - result = write_mp_offers(file, &shaCtx); - break; - - case FILETYPE_ACCEPTS: - result = write_mp_accepts(file, &shaCtx); - break; - - case FILETYPE_GLOBALS: - result = write_globals_state(file, &shaCtx); - break; - - case FILETYPE_CROWDSALES: - result = write_mp_crowdsales(file, &shaCtx); - break; - - case FILETYPE_MDEXORDERS: - result = write_mp_metadex(file, &shaCtx); - break; - } - - // generate and wite the double hash of all the contents written - uint256 hash1; - SHA256_Final((unsigned char*)&hash1, &shaCtx); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - file << "!" << hash2.ToString() << endl; - - file.flush(); - file.close(); - return result; -} - -static bool is_state_prefix( std::string const &str ) -{ - for (int i = 0; i < NUM_FILETYPES; ++i) { - if (boost::equals(str, statePrefix[i])) { - return true; - } - } - - return false; -} - -static void prune_state_files( CBlockIndex const *topIndex ) -{ - // build a set of blockHashes for which we have any state files - std::set statefulBlockHashes; - - boost::filesystem::directory_iterator dIter(MPPersistencePath); - boost::filesystem::directory_iterator endIter; - for (; dIter != endIter; ++dIter) { - std::string fName = dIter->path().empty() ? "" : (*--dIter->path().end()).string(); - if (false == boost::filesystem::is_regular_file(dIter->status())) { - // skip funny business - PrintToLog("Non-regular file found in persistence directory : %s\n", fName); - continue; - } - - std::vector vstr; - boost::split(vstr, fName, boost::is_any_of("-."), token_compress_on); - if ( vstr.size() == 3 && - is_state_prefix(vstr[0]) && - boost::equals(vstr[2], "dat")) { - uint256 blockHash; - blockHash.SetHex(vstr[1]); - statefulBlockHashes.insert(blockHash); - } else { - PrintToLog("None state file found in persistence directory : %s\n", fName); - } - } - - // for each blockHash in the set, determine the distance from the given block - std::set::const_iterator iter; - for (iter = statefulBlockHashes.begin(); iter != statefulBlockHashes.end(); ++iter) { - // look up the CBlockIndex for height info - CBlockIndex const *curIndex = GetBlockIndex(*iter); - - // if we have nothing int the index, or this block is too old.. - if (NULL == curIndex || (topIndex->nHeight - curIndex->nHeight) > MAX_STATE_HISTORY ) { - if (elysium_debug_persistence) - { - if (curIndex) { - PrintToLog("State from Block:%s is no longer need, removing files (age-from-tip: %d)\n", (*iter).ToString(), topIndex->nHeight - curIndex->nHeight); - } else { - PrintToLog("State from Block:%s is no longer need, removing files (not in index)\n", (*iter).ToString()); - } - } - - // destroy the associated files! - std::string strBlockHash = iter->ToString(); - for (int i = 0; i < NUM_FILETYPES; ++i) { - boost::filesystem::path path = MPPersistencePath / strprintf("%s-%s.dat", statePrefix[i], strBlockHash); - boost::filesystem::remove(path); - } - } - } -} - -int elysium_save_state( CBlockIndex const *pBlockIndex ) -{ - // write the new state as of the given block - write_state_file(pBlockIndex, FILETYPE_BALANCES); - write_state_file(pBlockIndex, FILETYPE_OFFERS); - write_state_file(pBlockIndex, FILETYPE_ACCEPTS); - write_state_file(pBlockIndex, FILETYPE_GLOBALS); - write_state_file(pBlockIndex, FILETYPE_CROWDSALES); - write_state_file(pBlockIndex, FILETYPE_MDEXORDERS); - - // clean-up the directory - prune_state_files(pBlockIndex); - - _my_sps->setWatermark(pBlockIndex->GetBlockHash()); - - return 0; -} - -/** - * Clears the state of the system. - */ -void clear_all_state() -{ - LOCK(cs_main); - - // Memory based storage - mp_tally_map.clear(); - my_offers.clear(); - my_accepts.clear(); - my_crowds.clear(); - metadex.clear(); - my_pending.clear(); - ResetConsensusParams(); - ClearActivations(); - ClearAlerts(); - ClearFreezeState(); - - // LevelDB based storage - _my_sps->Clear(); - p_txlistdb->Clear(); - sigmaDb->Clear(); - s_stolistdb->Clear(); - t_tradelistdb->Clear(); - p_ElysiumTXDB->Clear(); - p_feecache->Clear(); - p_feehistory->Clear(); - assert(p_txlistdb->setDBVersion() == DB_VERSION); // new set of databases, set DB version - elysium_prev = 0; - - // Clear wallet state -#ifdef ENABLE_WALLET - if (wallet) { - wallet->ClearAllChainState(); - } -#endif -} - -/** - * Global handler to initialize Elysium Core. - * - * @return An exit code, indicating success or failure - */ -int elysium_init() -{ - LOCK(cs_main); - - if (elysiumInitialized) { - // nothing to do - return 0; - } - - PrintToLog("\nInitializing Elysium v%s [%s]\n", ElysiumVersion(), Params().NetworkIDString()); - PrintToLog("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime())); - - InitDebugLogLevels(); - ShrinkDebugLog(); - - // check for --autocommit option and set transaction commit flag accordingly - if (!GetBoolArg("-autocommit", true)) { - PrintToLog("Process was started with --autocommit set to false. " - "Created Elysium transactions will not be committed to wallet or broadcast.\n"); - autoCommit = false; - } - - // check for --startclean option and delete MP_ folders if present - bool startClean = false; - if (GetBoolArg("-startclean", false)) { - PrintToLog("Process was started with --startclean option, attempting to clear persistence files..\n"); - try { - boost::filesystem::path persistPath = GetDataDir() / "MP_persist"; - boost::filesystem::path txlistPath = GetDataDir() / "MP_txlist"; - boost::filesystem::path tradePath = GetDataDir() / "MP_tradelist"; - boost::filesystem::path spPath = GetDataDir() / "MP_spinfo"; - boost::filesystem::path stoPath = GetDataDir() / "MP_stolist"; - boost::filesystem::path elysiumTXDBPath = GetDataDir() / "Exodus_TXDB"; - boost::filesystem::path feesPath = GetDataDir() / "EXODUS_feecache"; - boost::filesystem::path feeHistoryPath = GetDataDir() / "EXODUS_feehistory"; - if (boost::filesystem::exists(persistPath)) boost::filesystem::remove_all(persistPath); - if (boost::filesystem::exists(txlistPath)) boost::filesystem::remove_all(txlistPath); - if (boost::filesystem::exists(tradePath)) boost::filesystem::remove_all(tradePath); - if (boost::filesystem::exists(spPath)) boost::filesystem::remove_all(spPath); - if (boost::filesystem::exists(stoPath)) boost::filesystem::remove_all(stoPath); - if (boost::filesystem::exists(elysiumTXDBPath)) boost::filesystem::remove_all(elysiumTXDBPath); - if (boost::filesystem::exists(feesPath)) boost::filesystem::remove_all(feesPath); - if (boost::filesystem::exists(feeHistoryPath)) boost::filesystem::remove_all(feeHistoryPath); - PrintToLog("Success clearing persistence files in datadir %s\n", GetDataDir().string()); - startClean = true; - } catch (const boost::filesystem::filesystem_error& e) { - PrintToLog("Failed to delete persistence folders: %s\n", e.what()); - } - } - - t_tradelistdb = new CMPTradeList(GetDataDir() / "MP_tradelist", fReindex); - s_stolistdb = new CMPSTOList(GetDataDir() / "MP_stolist", fReindex); - p_txlistdb = new CMPTxList(GetDataDir() / "MP_txlist", fReindex); - sigmaDb = new SigmaDatabase(GetDataDir() / "MP_sigma", fReindex); - _my_sps = new CMPSPInfo(GetDataDir() / "MP_spinfo", fReindex); - p_ElysiumTXDB = new CElysiumTransactionDB(GetDataDir() / "Exodus_TXDB", fReindex); - p_feecache = new CElysiumFeeCache(GetDataDir() / "EXODUS_feecache", fReindex); - p_feehistory = new CElysiumFeeHistory(GetDataDir() / "EXODUS_feehistory", fReindex); - - MPPersistencePath = GetDataDir() / "MP_persist"; - TryCreateDirectory(MPPersistencePath); - - txProcessor = new TxProcessor(); - -#ifdef ENABLE_WALLET - if (pwalletMain) { - wallet = new Wallet(pwalletMain->strWalletFile); - - if (!pwalletMain->IsLocked()) { - wallet->ReloadMasterKey(); - } - } else { - wallet = nullptr; - } -#endif - - bool wrongDBVersion = (p_txlistdb->getDBVersion() != DB_VERSION); - - ++elysiumInitialized; - - nWaterlineBlock = load_most_relevant_state(); - bool noPreviousState = (nWaterlineBlock <= 0); - - if (startClean) { - assert(p_txlistdb->setDBVersion() == DB_VERSION); // new set of databases, set DB version - } else if (wrongDBVersion) { - nWaterlineBlock = -1; // force a clear_all_state and parse from start - } - - if (nWaterlineBlock > 0) { - PrintToLog("Loading persistent state: OK [block %d]\n", nWaterlineBlock); - } else { - std::string strReason = "unknown"; - if (wrongDBVersion) strReason = "client version changed"; - if (noPreviousState) strReason = "no usable previous state found"; - if (startClean) strReason = "-startclean parameter used"; - PrintToLog("Loading persistent state: NONE (%s)\n", strReason); - } - - if (nWaterlineBlock < 0) { - // persistence says we reparse!, nuke some stuff in case the partial loads left stale bits - clear_all_state(); - } - - // legacy code, setting to pre-genesis-block - int snapshotHeight = ConsensusParams().GENESIS_BLOCK - 1; - - if (nWaterlineBlock < snapshotHeight) { - nWaterlineBlock = snapshotHeight; - elysium_prev = 0; - } - - // advance the waterline so that we start on the next unaccounted for block - nWaterlineBlock += 1; - - // collect the real Elysium balances available at the snapshot time - // redundant? do we need to show it both pre-parse and post-parse? if so let's label the printfs accordingly - if (elysium_debug_ely) { - int64_t elysium_balance = getMPbalance(GetSystemAddress().ToString(), ELYSIUM_PROPERTY_ELYSIUM, BALANCE); - PrintToLog("Elysium balance at start: %s\n", FormatDivisibleMP(elysium_balance)); - } - - // load feature activation messages from txlistdb and process them accordingly - p_txlistdb->LoadActivations(nWaterlineBlock); - - // load all alerts from levelDB (and immediately expire old ones) - p_txlistdb->LoadAlerts(nWaterlineBlock); - - // load the state of any freeable properties and frozen addresses from levelDB - if (!p_txlistdb->LoadFreezeState(nWaterlineBlock)) { - std::string strShutdownReason = "Failed to load freeze state from levelDB. It is unsafe to continue.\n"; - PrintToLog(strShutdownReason); - if (!GetBoolArg("-overrideforcedshutdown", false)) { - AbortNode(strShutdownReason, strShutdownReason); - } - } - - // initial scan - elysium_initial_scan(nWaterlineBlock); - - // display Elysium balance - int64_t elysium_balance = getMPbalance(GetSystemAddress().ToString(), ELYSIUM_PROPERTY_ELYSIUM, BALANCE); - - PrintToLog("Elysium balance after initialization: %s\n", FormatDivisibleMP(elysium_balance)); - PrintToLog("Elysium initialization completed\n"); - - return 0; -} - -/** - * Global handler to shut down Elysium Core. - * - * In particular, the LevelDB databases of the global state objects are closed - * properly. - * - * @return An exit code, indicating success or failure - */ -int elysium_shutdown() -{ - LOCK(cs_main); - -#ifdef ENABLE_WALLET - delete wallet; wallet = nullptr; -#endif - delete txProcessor; txProcessor = nullptr; - delete sigmaDb; sigmaDb = nullptr; - delete p_txlistdb; p_txlistdb = nullptr; - delete t_tradelistdb; t_tradelistdb = nullptr; - delete s_stolistdb; s_stolistdb = nullptr; - delete _my_sps; _my_sps = nullptr; - delete p_ElysiumTXDB; p_ElysiumTXDB = nullptr; - delete p_feecache; p_feecache = nullptr; - delete p_feehistory; p_feehistory = nullptr; - - elysiumInitialized = 0; - - PrintToLog("\nElysium Core shutdown completed\n"); - PrintToLog("Shutdown time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime())); - - return 0; -} - -/** - * This handler is called for every new transaction that comes in (actually in block parsing loop). - * - * @return True, if the transaction was an Elysium purchase, DEx payment or a valid Elysium transaction - */ -bool elysium_handler_tx(const CTransaction& tx, int nBlock, unsigned int idx, const CBlockIndex* pBlockIndex) -{ - LOCK(cs_main); - - if (!elysiumInitialized) { - elysium_init(); - } - - // clear pending, if any - // NOTE1: Every incoming TX is checked, not just MP-ones because: - // if for some reason the incoming TX doesn't pass our parser validation steps successfuly, I'd still want to clear pending amounts for that TX. - // NOTE2: Plus I wanna clear the amount before that TX is parsed by our protocol, in case we ever consider pending amounts in internal calculations. - PendingDelete(tx.GetHash()); - - // we do not care about parsing blocks prior to our waterline (empty blockchain defense) - if (nBlock < nWaterlineBlock) return false; - int64_t nBlockTime = pBlockIndex->GetBlockTime(); - - CMPTransaction mp_obj; - mp_obj.unlockLogic(); - - bool fFoundTx = false; - int pop_ret = parseTransaction(false, tx, nBlock, idx, mp_obj, nBlockTime); - - if (0 == pop_ret) { - int interp_ret = txProcessor->ProcessTx(mp_obj); - if (interp_ret) { - PrintToLog("!!! interpretPacket() returned %d !!!\n", interp_ret); - } - - // Only structurally valid transactions get recorded in levelDB - // PKT_ERROR - 2 = interpret_Transaction failed, structurally invalid payload - if (interp_ret != PKT_ERROR - 2) { - bool bValid = (0 <= interp_ret); - p_txlistdb->recordTX(tx.GetHash(), bValid, nBlock, mp_obj.getType(), mp_obj.getNewAmount()); - p_ElysiumTXDB->RecordTransaction(tx.GetHash(), idx, interp_ret); - } - fFoundTx |= (interp_ret == 0); - } - - if (fFoundTx && elysium_debug_consensus_hash_every_transaction) { - uint256 consensusHash = GetConsensusHash(); - PrintToLog("Consensus hash for transaction %s: %s\n", tx.GetHash().GetHex(), consensusHash.GetHex()); - } - - return fFoundTx; -} - -/** - * Determines, whether it is valid to use a Class C transaction for a given payload size. - * - * @param nDataSize The length of the payload - * @return True, if Class C is enabled and the payload is small enough - */ -bool elysium::UseEncodingClassC(size_t nDataSize) -{ - size_t nTotalSize = nDataSize + magic.size(); // Marker "exodus" - bool fDataEnabled = GetBoolArg("-datacarrier", true); - int nBlockNow = GetHeight(); - if (!IsAllowedOutputType(TX_NULL_DATA, nBlockNow)) { - fDataEnabled = false; - } - return nTotalSize <= nMaxDatacarrierBytes && fDataEnabled; -} - -// This function requests the wallet create an Elysium transaction using the supplied parameters and payload -int elysium::WalletTxBuilder( - const std::string& senderAddress, - const std::string& receiverAddress, - const std::string& redemptionAddress, - int64_t referenceAmount, - const std::vector& data, - uint256& txid, - std::string& rawHex, - bool commit, - InputMode inputMode) -{ -#ifdef ENABLE_WALLET - if (pwalletMain == NULL) return MP_ERR_WALLET_ACCESS; - - // Determine the class to send the transaction via - default is Class C - bool useClassC = (inputMode == InputMode::NORMAL && !UseEncodingClassC(data.size())) ? false : true; - - // Prepare the transaction - first setup some vars - CCoinControl coinControl; - CWalletTx wtxNew; - int64_t nFeeRet = 0; - int nChangePosInOut = -1; - std::string strFailReason; - std::vector vecSend; - CReserveKey reserveKey(pwalletMain); - - // Next, we set the change address to the sender - CBitcoinAddress addr = CBitcoinAddress(senderAddress); - coinControl.destChange = addr.Get(); - - // Select the inputs - if (0 >= SelectCoins(senderAddress, coinControl, referenceAmount, inputMode)) { - return inputMode == InputMode::SIGMA ? MP_SIGMA_INPUTS_INVALID : MP_INPUTS_INVALID; - } - - // Encode the data outputs - if (useClassC) { - try { - vecSend.push_back(EncodeClassC(data.begin(), data.end())); - } catch (std::exception& e) { - PrintToLog("Fail to encode packet with class C: %s\n", e.what()); - return MP_ENCODING_ERROR; - } - } else { - CPubKey redeemingPubKey; - - if (inputMode != InputMode::NORMAL) { - return MP_INPUTS_INVALID; - } - - if (!AddressToPubKey(redemptionAddress.empty() ? senderAddress : redemptionAddress, redeemingPubKey)) { - return MP_REDEMP_BAD_VALIDATION; - } - - try { - EncodeClassB(senderAddress, redeemingPubKey, data.begin(), data.end(), std::back_inserter(vecSend)); - } catch (std::exception &e) { - PrintToLog("Fail to encode packet with class B: %s\n", e.what()); - return MP_ENCODING_ERROR; - } - } - - // Then add a paytopubkeyhash output for the recipient (if needed) - note we do this last as we want this to be the highest vout - if (!receiverAddress.empty()) { - CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(receiverAddress).Get()); - vecSend.push_back(CTxOut(referenceAmount > 0 ? referenceAmount : GetDustThreshold(scriptPubKey), scriptPubKey)); - } - - // Now we have what we need to pass to the wallet to create the transaction, perform some checks first - - if (!coinControl.HasSelected()) return MP_ERR_INPUTSELECT_FAIL; - - std::vector vecRecipients; - for (size_t i = 0; i < vecSend.size(); ++i) { - auto& output = vecSend[i]; - CRecipient recipient = {output.scriptPubKey, output.nValue, false}; - vecRecipients.push_back(recipient); - } - - std::vector sigmaSelected; - std::vector sigmaChanges; - - switch (inputMode) { - case InputMode::NORMAL: - // Ask the wallet to create the transaction (note mining fee determined by Bitcoin Core params) - if (!pwalletMain->CreateTransaction(vecRecipients, wtxNew, reserveKey, nFeeRet, nChangePosInOut, strFailReason, &coinControl)) { - PrintToLog("%s: ERROR: wallet transaction creation failed: %s\n", __func__, strFailReason); - return MP_ERR_CREATE_TX; - } - break; - case InputMode::SIGMA: - CAmount fee; - try { - bool changeAddedToFee; - wtxNew = pwalletMain->CreateSigmaSpendTransaction( - vecRecipients, fee, sigmaSelected, sigmaChanges, changeAddedToFee, &coinControl); - } catch (std::exception const &err) { - PrintToLog("%s: ERROR: wallet transaction creation failed: %s\n", __func__, err.what()); - return MP_ERR_CREATE_SIGMA_TX; - } - break; - default: - PrintToLog("%s: ERROR: wallet transaction creation failed: input mode is invalid\n", __func__); - return MP_ERR_CREATE_TX; - } - - // If this request is only to create, but not commit the transaction then display it and exit - if (!commit) { - rawHex = EncodeHexTx(wtxNew); - return 0; - } else { - // Commit the transaction to the wallet and broadcast) - PrintToLog("%s: %s; nFeeRet = %d\n", __func__, wtxNew.tx->ToString(), nFeeRet); - switch (inputMode) { - case InputMode::NORMAL: - { - CValidationState state; - if (!pwalletMain->CommitTransaction(wtxNew, reserveKey, g_connman.get(), state)) return MP_ERR_COMMIT_TX; - } - break; - case InputMode::SIGMA: - try { - if (!pwalletMain->CommitSigmaTransaction(wtxNew, sigmaSelected, sigmaChanges)) return MP_ERR_COMMIT_TX; - } catch (const std::exception &) { - return MP_ERR_COMMIT_TX; - } - break; - default: - return MP_ERR_COMMIT_TX; - } - txid = wtxNew.GetHash(); - return 0; - } -#else - return MP_ERR_WALLET_ACCESS; -#endif - -} - -void CElysiumTransactionDB::RecordTransaction(const uint256& txid, uint32_t posInBlock, int processingResult) -{ - assert(pdb); - - const std::string key = txid.ToString(); - const std::string value = strprintf("%d:%d", posInBlock, processingResult); - - Status status = pdb->Put(writeoptions, key, value); - ++nWritten; -} - -std::vector CElysiumTransactionDB::FetchTransactionDetails(const uint256& txid) -{ - assert(pdb); - std::string strValue; - std::vector vTransactionDetails; - - Status status = pdb->Get(readoptions, txid.ToString(), &strValue); - if (status.ok()) { - std::vector vStr; - boost::split(vStr, strValue, boost::is_any_of(":"), boost::token_compress_on); - if (vStr.size() == 2) { - vTransactionDetails.push_back(vStr[0]); - vTransactionDetails.push_back(vStr[1]); - } else { - PrintToLog("ERROR: Entry (%s) found in ElysiumTXDB with unexpected number of attributes!\n", txid.GetHex()); - } - } else { - PrintToLog("ERROR: Entry (%s) could not be loaded from ElysiumTXDB!\n", txid.GetHex()); - } - - return vTransactionDetails; -} - -uint32_t CElysiumTransactionDB::FetchTransactionPosition(const uint256& txid) -{ - uint32_t posInBlock = 999999; // setting an initial arbitrarily high value will ensure transaction is always "last" in event of bug/exploit - - std::vector vTransactionDetails = FetchTransactionDetails(txid); - if (vTransactionDetails.size() == 2) { - posInBlock = boost::lexical_cast(vTransactionDetails[0]); - } - - return posInBlock; -} - -std::string CElysiumTransactionDB::FetchInvalidReason(const uint256& txid) -{ - int processingResult = -999999; - - std::vector vTransactionDetails = FetchTransactionDetails(txid); - if (vTransactionDetails.size() == 2) { - processingResult = boost::lexical_cast(vTransactionDetails[1]); - } - - return error_str(processingResult); -} - -std::set CMPTxList::GetSeedBlocks(int startHeight, int endHeight) -{ - std::set setSeedBlocks; - - if (!pdb) return setSeedBlocks; - - Iterator* it = NewIterator(); - - for (it->SeekToFirst(); it->Valid(); it->Next()) { - std::string itData = it->value().ToString(); - std::vector vstr; - boost::split(vstr, itData, boost::is_any_of(":"), boost::token_compress_on); - if (4 != vstr.size()) continue; // unexpected number of tokens - int block = atoi(vstr[1]); - if (block >= startHeight && block <= endHeight) { - setSeedBlocks.insert(block); - } - } - - delete it; - - return setSeedBlocks; -} - -bool CMPTxList::CheckForFreezeTxs(int blockHeight) -{ - assert(pdb); - Iterator* it = NewIterator(); - - for (it->SeekToFirst(); it->Valid(); it->Next()) { - std::string itData = it->value().ToString(); - std::vector vstr; - boost::split(vstr, itData, boost::is_any_of(":"), token_compress_on); - if (4 != vstr.size()) continue; - int block = atoi(vstr[1]); - if (block < blockHeight) continue; - uint16_t txtype = atoi(vstr[2]); - if (txtype == ELYSIUM_TYPE_FREEZE_PROPERTY_TOKENS || txtype == ELYSIUM_TYPE_UNFREEZE_PROPERTY_TOKENS || - txtype == ELYSIUM_TYPE_ENABLE_FREEZING || txtype == ELYSIUM_TYPE_DISABLE_FREEZING) { - delete it; - return true; - } - } - - delete it; - return false; -} - -bool CMPTxList::LoadFreezeState(int blockHeight) -{ - assert(pdb); - std::vector > loadOrder; - int txnsLoaded = 0; - Iterator* it = NewIterator(); - PrintToLog("Loading freeze state from levelDB\n"); - - for (it->SeekToFirst(); it->Valid(); it->Next()) { - std::string itData = it->value().ToString(); - std::vector vstr; - boost::split(vstr, itData, boost::is_any_of(":"), token_compress_on); - if (4 != vstr.size()) continue; - uint16_t txtype = atoi(vstr[2]); - if (txtype != ELYSIUM_TYPE_FREEZE_PROPERTY_TOKENS && txtype != ELYSIUM_TYPE_UNFREEZE_PROPERTY_TOKENS && - txtype != ELYSIUM_TYPE_ENABLE_FREEZING && txtype != ELYSIUM_TYPE_DISABLE_FREEZING) continue; - if (atoi(vstr[0]) != 1) continue; // invalid, ignore - uint256 txid = uint256S(it->key().ToString()); - int txPosition = p_ElysiumTXDB->FetchTransactionPosition(txid); - std::string sortKey = strprintf("%06d%010d", atoi(vstr[1]), txPosition); - loadOrder.push_back(std::make_pair(sortKey, txid)); - } - - delete it; - - std::sort (loadOrder.begin(), loadOrder.end()); - - for (std::vector >::iterator it = loadOrder.begin(); it != loadOrder.end(); ++it) { - uint256 hash = (*it).second; - uint256 blockHash; - CTransactionRef wtx; - CMPTransaction mp_obj; - if (!GetTransaction(hash, wtx, Params().GetConsensus(), blockHash, true)) { - PrintToLog("ERROR: While loading freeze transaction %s: tx in levelDB but does not exist.\n", hash.GetHex()); - return false; - } - if (blockHash.IsNull() || (NULL == GetBlockIndex(blockHash))) { - PrintToLog("ERROR: While loading freeze transaction %s: failed to retrieve block hash.\n", hash.GetHex()); - return false; - } - CBlockIndex* pBlockIndex = GetBlockIndex(blockHash); - if (NULL == pBlockIndex) { - PrintToLog("ERROR: While loading freeze transaction %s: failed to retrieve block index.\n", hash.GetHex()); - return false; - } - int txBlockHeight = pBlockIndex->nHeight; - if (txBlockHeight > blockHeight) { - PrintToLog("ERROR: While loading freeze transaction %s: transaction is in the future.\n", hash.GetHex()); - return false; - } - if (0 != ParseTransaction(*wtx, txBlockHeight, 0, mp_obj)) { - PrintToLog("ERROR: While loading freeze transaction %s: failed ParseTransaction.\n", hash.GetHex()); - return false; - } - if (!mp_obj.interpret_Transaction()) { - PrintToLog("ERROR: While loading freeze transaction %s: failed interpret_Transaction.\n", hash.GetHex()); - return false; - } - if (ELYSIUM_TYPE_FREEZE_PROPERTY_TOKENS != mp_obj.getType() && ELYSIUM_TYPE_UNFREEZE_PROPERTY_TOKENS != mp_obj.getType() && - ELYSIUM_TYPE_ENABLE_FREEZING != mp_obj.getType() && ELYSIUM_TYPE_DISABLE_FREEZING != mp_obj.getType()) { - PrintToLog("ERROR: While loading freeze transaction %s: levelDB type mismatch, not a freeze transaction.\n", hash.GetHex()); - return false; - } - - if (0 != txProcessor->ProcessTx(mp_obj)) { - PrintToLog("ERROR: While loading freeze transaction %s: non-zero return from interpretPacket\n", hash.GetHex()); - return false; - } - - txnsLoaded++; - } - - if (blockHeight > 497000 && !isNonMainNet()) { - assert(txnsLoaded >= 2); // sanity check against a failure to properly load the freeze state - } - - return true; -} - -void CMPTxList::LoadActivations(int blockHeight) -{ - if (!pdb) return; - - Slice skey, svalue; - Iterator* it = NewIterator(); - - PrintToLog("Loading feature activations from levelDB\n"); - - std::vector > loadOrder; - - for (it->SeekToFirst(); it->Valid(); it->Next()) { - std::string itData = it->value().ToString(); - std::vector vstr; - boost::split(vstr, itData, boost::is_any_of(":"), token_compress_on); - if (4 != vstr.size()) continue; // unexpected number of tokens - if (atoi(vstr[2]) != ELYSIUM_MESSAGE_TYPE_ACTIVATION || atoi(vstr[0]) != 1) continue; // we only care about valid activations - uint256 txid = uint256S(it->key().ToString());; - loadOrder.push_back(std::make_pair(atoi(vstr[1]), txid)); - } - - std::sort (loadOrder.begin(), loadOrder.end()); - - for (std::vector >::iterator it = loadOrder.begin(); it != loadOrder.end(); ++it) { - uint256 hash = (*it).second; - uint256 blockHash; - CTransactionRef wtx; - CMPTransaction mp_obj; - - if (!GetTransaction(hash, wtx, Params().GetConsensus(), blockHash, true)) { - PrintToLog("ERROR: While loading activation transaction %s: tx in levelDB but does not exist.\n", hash.GetHex()); - continue; - } - if (blockHash.IsNull() || (NULL == GetBlockIndex(blockHash))) { - PrintToLog("ERROR: While loading activation transaction %s: failed to retrieve block hash.\n", hash.GetHex()); - continue; - } - CBlockIndex* pBlockIndex = GetBlockIndex(blockHash); - if (NULL == pBlockIndex) { - PrintToLog("ERROR: While loading activation transaction %s: failed to retrieve block index.\n", hash.GetHex()); - continue; - } - int blockHeight = pBlockIndex->nHeight; - if (0 != ParseTransaction(*wtx, blockHeight, 0, mp_obj)) { - PrintToLog("ERROR: While loading activation transaction %s: failed ParseTransaction.\n", hash.GetHex()); - continue; - } - if (!mp_obj.interpret_Transaction()) { - PrintToLog("ERROR: While loading activation transaction %s: failed interpret_Transaction.\n", hash.GetHex()); - continue; - } - if (ELYSIUM_MESSAGE_TYPE_ACTIVATION != mp_obj.getType()) { - PrintToLog("ERROR: While loading activation transaction %s: levelDB type mismatch, not an activation.\n", hash.GetHex()); - continue; - } - - if (0 != txProcessor->ProcessTx(mp_obj)) { - PrintToLog("ERROR: While loading activation transaction %s: non-zero return from interpretPacket\n", hash.GetHex()); - continue; - } - } - delete it; - CheckLiveActivations(blockHeight); - - // This alert never expires as long as custom activations are used - if (IsArgSet("-elysiumactivationallowsender") || IsArgSet("-elysiumactivationignoresender")) { - AddAlert("elysium", ALERT_CLIENT_VERSION_EXPIRY, std::numeric_limits::max(), - "Authorization for feature activation has been modified. Data provided by this client should not be trusted."); - } -} - -void CMPTxList::LoadAlerts(int blockHeight) -{ - if (!pdb) return; - Slice skey, svalue; - Iterator* it = NewIterator(); - - std::vector > loadOrder; - - for (it->SeekToFirst(); it->Valid(); it->Next()) { - std::string itData = it->value().ToString(); - std::vector vstr; - boost::split(vstr, itData, boost::is_any_of(":"), token_compress_on); - if (4 != vstr.size()) continue; // unexpected number of tokens - if (atoi(vstr[2]) != ELYSIUM_MESSAGE_TYPE_ALERT || atoi(vstr[0]) != 1) continue; // not a valid alert - uint256 txid = uint256S(it->key().ToString());; - loadOrder.push_back(std::make_pair(atoi(vstr[1]), txid)); - } - - std::sort (loadOrder.begin(), loadOrder.end()); - - for (std::vector >::iterator it = loadOrder.begin(); it != loadOrder.end(); ++it) { - uint256 txid = (*it).second; - uint256 blockHash; - CTransactionRef wtx; - CMPTransaction mp_obj; - if (!GetTransaction(txid, wtx, Params().GetConsensus(), blockHash, true)) { - PrintToLog("ERROR: While loading alert %s: tx in levelDB but does not exist.\n", txid.GetHex()); - continue; - } - if (0 != ParseTransaction(*wtx, blockHeight, 0, mp_obj)) { - PrintToLog("ERROR: While loading alert %s: failed ParseTransaction.\n", txid.GetHex()); - continue; - } - if (!mp_obj.interpret_Transaction()) { - PrintToLog("ERROR: While loading alert %s: failed interpret_Transaction.\n", txid.GetHex()); - continue; - } - if (ELYSIUM_MESSAGE_TYPE_ALERT != mp_obj.getType()) { - PrintToLog("ERROR: While loading alert %s: levelDB type mismatch, not an alert.\n", txid.GetHex()); - continue; - } - if (!CheckAlertAuthorization(mp_obj.getSender())) { - PrintToLog("ERROR: While loading alert %s: sender is not authorized to send alerts.\n", txid.GetHex()); - continue; - } - - if (mp_obj.getAlertType() == 65535) { // set alert type to FFFF to clear previously sent alerts - DeleteAlerts(mp_obj.getSender()); - } else { - AddAlert(mp_obj.getSender(), mp_obj.getAlertType(), mp_obj.getAlertExpiry(), mp_obj.getAlertMessage()); - } - } - - delete it; - int64_t blockTime = 0; - CBlockIndex* pBlockIndex = chainActive[blockHeight-1]; - if (pBlockIndex != NULL) { - blockTime = pBlockIndex->GetBlockTime(); - } - if (blockTime > 0) { - CheckExpiredAlerts(blockHeight, blockTime); - } -} - -uint256 CMPTxList::findMetaDExCancel(const uint256 txid) -{ - std::vector vstr; - string txidStr = txid.ToString(); - Slice skey, svalue; - uint256 cancelTxid; - Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - skey = it->key(); - svalue = it->value(); - string svalueStr = svalue.ToString(); - boost::split(vstr, svalueStr, boost::is_any_of(":"), token_compress_on); - // obtain the existing affected tx count - if (3 <= vstr.size()) - { - if (vstr[0] == txidStr) { delete it; cancelTxid.SetHex(skey.ToString()); return cancelTxid; } - } - } - - delete it; - return uint256(); -} - -/* - * Gets the DB version from txlistdb - * - * Returns the current version - */ -int CMPTxList::getDBVersion() -{ - std::string strValue; - int verDB = 0; - - Status status = pdb->Get(readoptions, "dbversion", &strValue); - if (status.ok()) { - verDB = boost::lexical_cast(strValue); - } - - if (elysium_debug_txdb) PrintToLog("%s(): dbversion %s status %s, line %d, file: %s\n", __FUNCTION__, strValue, status.ToString(), __LINE__, __FILE__); - - return verDB; -} - -/* - * Sets the DB version for txlistdb - * - * Returns the current version after update - */ -int CMPTxList::setDBVersion() -{ - std::string verStr = boost::lexical_cast(DB_VERSION); - Status status = pdb->Put(writeoptions, "dbversion", verStr); - - if (elysium_debug_txdb) PrintToLog("%s(): dbversion %s status %s, line %d, file: %s\n", __FUNCTION__, verStr, status.ToString(), __LINE__, __FILE__); - - return getDBVersion(); -} - -int CMPTxList::getNumberOfMetaDExCancels(const uint256 txid) -{ - if (!pdb) return 0; - int numberOfCancels = 0; - std::vector vstr; - string strValue; - Status status = pdb->Get(readoptions, txid.ToString() + "-C", &strValue); - if (status.ok()) - { - // parse the string returned - boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); - // obtain the number of cancels - if (4 <= vstr.size()) - { - numberOfCancels = atoi(vstr[3]); - } - } - return numberOfCancels; -} - -/** - * Returns the number of sub records. - */ -int CMPTxList::getNumberOfSubRecords(const uint256& txid) -{ - int numberOfSubRecords = 0; - - std::string strValue; - Status status = pdb->Get(readoptions, txid.ToString(), &strValue); - if (status.ok()) { - std::vector vstr; - boost::split(vstr, strValue, boost::is_any_of(":"), boost::token_compress_on); - if (4 <= vstr.size()) { - numberOfSubRecords = boost::lexical_cast(vstr[3]); - } - } - - return numberOfSubRecords; -} - -int CMPTxList::getMPTransactionCountTotal() -{ - int count = 0; - Slice skey, svalue; - Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - skey = it->key(); - if (skey.ToString().length() == 64) { ++count; } //extra entries for cancels and purchases are more than 64 chars long - } - delete it; - return count; -} - -int CMPTxList::getMPTransactionCountBlock(int block) -{ - int count = 0; - Slice skey, svalue; - Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - skey = it->key(); - svalue = it->value(); - if (skey.ToString().length() == 64) - { - string strValue = svalue.ToString(); - std::vector vstr; - boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); - if (4 == vstr.size()) - { - if (atoi(vstr[1]) == block) { ++count; } - } - } - } - delete it; - return count; -} - -string CMPTxList::getKeyValue(string key) -{ - if (!pdb) return ""; - string strValue; - Status status = pdb->Get(readoptions, key, &strValue); - if (status.ok()) { return strValue; } else { return ""; } -} - -/** - * Retrieves details about a "send all" record. - */ -bool CMPTxList::getSendAllDetails(const uint256& txid, int subSend, uint32_t& propertyId, int64_t& amount) -{ - std::string strKey = strprintf("%s-%d", txid.ToString(), subSend); - std::string strValue; - leveldb::Status status = pdb->Get(readoptions, strKey, &strValue); - if (status.ok()) { - std::vector vstr; - boost::split(vstr, strValue, boost::is_any_of(":"), boost::token_compress_on); - if (2 == vstr.size()) { - propertyId = boost::lexical_cast(vstr[0]); - amount = boost::lexical_cast(vstr[1]); - return true; - } - } - return false; -} - -bool CMPTxList::getPurchaseDetails(const uint256 txid, int purchaseNumber, string *buyer, string *seller, uint64_t *vout, uint64_t *propertyId, uint64_t *nValue) -{ - if (!pdb) return 0; - std::vector vstr; - string strValue; - Status status = pdb->Get(readoptions, txid.ToString()+"-"+to_string(purchaseNumber), &strValue); - if (status.ok()) - { - // parse the string returned - boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); - // obtain the requisite details - if (5 == vstr.size()) - { - *vout = atoi(vstr[0]); - *buyer = vstr[1]; - *seller = vstr[2]; - *propertyId = atoi(vstr[3]); - *nValue = boost::lexical_cast(vstr[4]);; - return true; - } - } - return false; -} - -void CMPTxList::recordMetaDExCancelTX(const uint256 &txidMaster, const uint256 &txidSub, bool fValid, int nBlock, unsigned int propertyId, uint64_t nValue) -{ - if (!pdb) return; - - // Prep - setup vars - unsigned int type = 99992104; - unsigned int refNumber = 1; - uint64_t existingAffectedTXCount = 0; - string txidMasterStr = txidMaster.ToString() + "-C"; - - // Step 1 - Check TXList to see if this cancel TXID exists - // Step 2a - If doesn't exist leave number of affected txs & ref set to 1 - // Step 2b - If does exist add +1 to existing ref and set this ref as new number of affected - std::vector vstr; - string strValue; - Status status = pdb->Get(readoptions, txidMasterStr, &strValue); - if (status.ok()) - { - // parse the string returned - boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); - - // obtain the existing affected tx count - if (4 <= vstr.size()) - { - existingAffectedTXCount = atoi(vstr[3]); - refNumber = existingAffectedTXCount + 1; - } - } - - // Step 3 - Create new/update master record for cancel tx in TXList - const string key = txidMasterStr; - const string value = strprintf("%u:%d:%u:%lu", fValid ? 1:0, nBlock, type, refNumber); - PrintToLog("METADEXCANCELDEBUG : Writing master record %s(%s, valid=%s, block= %d, type= %d, number of affected transactions= %d)\n", __FUNCTION__, txidMaster.ToString(), fValid ? "YES":"NO", nBlock, type, refNumber); - if (pdb) - { - status = pdb->Put(writeoptions, key, value); - PrintToLog("METADEXCANCELDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString(), __LINE__, __FILE__); - } - - // Step 4 - Write sub-record with cancel details - const string txidStr = txidMaster.ToString() + "-C"; - const string subKey = STR_REF_SUBKEY_TXID_REF_COMBO(txidStr, refNumber); - const string subValue = strprintf("%s:%d:%lu", txidSub.ToString(), propertyId, nValue); - Status subStatus; - PrintToLog("METADEXCANCELDEBUG : Writing sub-record %s with value %s\n", subKey, subValue); - if (pdb) - { - subStatus = pdb->Put(writeoptions, subKey, subValue); - PrintToLog("METADEXCANCELDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, subStatus.ToString(), __LINE__, __FILE__); - } -} - -/** - * Records a "send all" sub record. - */ -void CMPTxList::recordSendAllSubRecord(const uint256& txid, int subRecordNumber, uint32_t propertyId, int64_t nValue) -{ - std::string strKey = strprintf("%s-%d", txid.ToString(), subRecordNumber); - std::string strValue = strprintf("%d:%d", propertyId, nValue); - - leveldb::Status status = pdb->Put(writeoptions, strKey, strValue); - ++nWritten; - if (elysium_debug_txdb) PrintToLog("%s(): store: %s=%s, status: %s\n", __func__, strKey, strValue, status.ToString()); -} - -void CMPTxList::recordPaymentTX(const uint256 &txid, bool fValid, int nBlock, unsigned int vout, unsigned int propertyId, uint64_t nValue, string buyer, string seller) -{ - if (!pdb) return; - - // Prep - setup vars - unsigned int type = 99999999; - uint64_t numberOfPayments = 1; - unsigned int paymentNumber = 1; - uint64_t existingNumberOfPayments = 0; - - // Step 1 - Check TXList to see if this payment TXID exists - bool paymentEntryExists = p_txlistdb->exists(txid); - - // Step 2a - If doesn't exist leave number of payments & paymentNumber set to 1 - // Step 2b - If does exist add +1 to existing number of payments and set this paymentNumber as new numberOfPayments - if (paymentEntryExists) - { - //retrieve old numberOfPayments - std::vector vstr; - string strValue; - Status status = pdb->Get(readoptions, txid.ToString(), &strValue); - if (status.ok()) - { - // parse the string returned - boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); - - // obtain the existing number of payments - if (4 <= vstr.size()) - { - existingNumberOfPayments = atoi(vstr[3]); - paymentNumber = existingNumberOfPayments + 1; - numberOfPayments = existingNumberOfPayments + 1; - } - } - } - - // Step 3 - Create new/update master record for payment tx in TXList - const string key = txid.ToString(); - const string value = strprintf("%u:%d:%u:%lu", fValid ? 1:0, nBlock, type, numberOfPayments); - Status status; - PrintToLog("DEXPAYDEBUG : Writing master record %s(%s, valid=%s, block= %d, type= %d, number of payments= %lu)\n", __FUNCTION__, txid.ToString(), fValid ? "YES":"NO", nBlock, type, numberOfPayments); - if (pdb) - { - status = pdb->Put(writeoptions, key, value); - PrintToLog("DEXPAYDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString(), __LINE__, __FILE__); - } - - // Step 4 - Write sub-record with payment details - const string txidStr = txid.ToString(); - const string subKey = STR_PAYMENT_SUBKEY_TXID_PAYMENT_COMBO(txidStr, paymentNumber); - const string subValue = strprintf("%d:%s:%s:%d:%lu", vout, buyer, seller, propertyId, nValue); - Status subStatus; - PrintToLog("DEXPAYDEBUG : Writing sub-record %s with value %s\n", subKey, subValue); - if (pdb) - { - subStatus = pdb->Put(writeoptions, subKey, subValue); - PrintToLog("DEXPAYDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, subStatus.ToString(), __LINE__, __FILE__); - } -} - -void CMPTxList::recordTX(const uint256 &txid, bool fValid, int nBlock, unsigned int type, uint64_t nValue) -{ - if (!pdb) return; - - // overwrite detection, we should never be overwriting a tx, as that means we have redone something a second time - // reorgs delete all txs from levelDB above reorg_chain_height - if (p_txlistdb->exists(txid)) PrintToLog("LEVELDB TX OVERWRITE DETECTION - %s\n", txid.ToString()); - -const string key = txid.ToString(); -const string value = strprintf("%u:%d:%u:%lu", fValid ? 1:0, nBlock, type, nValue); -Status status; - - PrintToLog("%s(%s, valid=%s, block= %d, type= %d, value= %lu)\n", - __FUNCTION__, txid.ToString(), fValid ? "YES":"NO", nBlock, type, nValue); - - if (pdb) - { - status = pdb->Put(writeoptions, key, value); - ++nWritten; - if (elysium_debug_txdb) PrintToLog("%s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString(), __LINE__, __FILE__); - } -} - -bool CMPTxList::exists(const uint256 &txid) -{ - if (!pdb) return false; - -string strValue; -Status status = pdb->Get(readoptions, txid.ToString(), &strValue); - - if (!status.ok()) - { - if (status.IsNotFound()) return false; - } - - return true; -} - -bool CMPTxList::getTX(const uint256 &txid, string &value) -{ -Status status = pdb->Get(readoptions, txid.ToString(), &value); - - ++nRead; - - if (status.ok()) - { - return true; - } - - return false; -} - -void CMPTxList::printStats() -{ - PrintToLog("CMPTxList stats: nWritten= %d , nRead= %d\n", nWritten, nRead); -} - -void CMPTxList::printAll() -{ -int count = 0; -Slice skey, svalue; - Iterator* it = NewIterator(); - - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - skey = it->key(); - svalue = it->value(); - ++count; - PrintToLog("entry #%8d= %s:%s\n", count, skey.ToString(), svalue.ToString()); - } - - delete it; -} - -// figure out if there was at least 1 Master Protocol transaction within the block range, or a block if starting equals ending -// block numbers are inclusive -// pass in bDeleteFound = true to erase each entry found within the block range -bool CMPTxList::isMPinBlockRange(int starting_block, int ending_block, bool bDeleteFound) -{ -leveldb::Slice skey, svalue; -unsigned int count = 0; -std::vector vstr; -int block; -unsigned int n_found = 0; - - leveldb::Iterator* it = NewIterator(); - - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - skey = it->key(); - svalue = it->value(); - - ++count; - - string strvalue = it->value().ToString(); - - // parse the string returned, find the validity flag/bit & other parameters - boost::split(vstr, strvalue, boost::is_any_of(":"), token_compress_on); - - // only care about the block number/height here - if (2 <= vstr.size()) - { - block = atoi(vstr[1]); - - if ((starting_block <= block) && (block <= ending_block)) - { - ++n_found; - PrintToLog("%s() DELETING: %s=%s\n", __FUNCTION__, skey.ToString(), svalue.ToString()); - if (bDeleteFound) pdb->Delete(writeoptions, skey); - } - } - } - - PrintToLog("%s(%d, %d); n_found= %d\n", __FUNCTION__, starting_block, ending_block, n_found); - - delete it; - - return (n_found); -} - -// MPSTOList here -std::string CMPSTOList::getMySTOReceipts(string filterAddress) -{ - if (!pdb) return ""; - string mySTOReceipts = ""; - Slice skey, svalue; - Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) { - skey = it->key(); - string recipientAddress = skey.ToString(); - if(!IsMyAddress(recipientAddress)) continue; // not ours, not interested - if((!filterAddress.empty()) && (filterAddress != recipientAddress)) continue; // not the filtered address - // ours, get info - svalue = it->value(); - string strValue = svalue.ToString(); - // break into individual receipts - std::vector vstr; - boost::split(vstr, strValue, boost::is_any_of(","), token_compress_on); - for(uint32_t i = 0; i svstr; - boost::split(svstr, vstr[i], boost::is_any_of(":"), token_compress_on); - if(4 == svstr.size()) { - size_t txidMatch = mySTOReceipts.find(svstr[0]); - if(txidMatch==std::string::npos) mySTOReceipts += svstr[0]+":"+svstr[1]+":"+recipientAddress+":"+svstr[2]+","; - } - } - } - delete it; - // above code will leave a trailing comma - strip it - if (mySTOReceipts.size() > 0) mySTOReceipts.resize(mySTOReceipts.size()-1); - return mySTOReceipts; -} - -void CMPSTOList::getRecipients(const uint256 txid, string filterAddress, UniValue *recipientArray, uint64_t *total, uint64_t *numRecipients) -{ - if (!pdb) return; - - bool filter = true; //default - bool filterByWallet = true; //default - bool filterByAddress = false; //default - - if (filterAddress == "*") filter = false; - if ((filterAddress != "") && (filterAddress != "*")) { filterByWallet = false; filterByAddress = true; } - - // iterate through SDB, dropping all records where key is not filterAddress (if filtering) - int count = 0; - - // the fee is variable based on version of STO - provide number of recipients and allow calling function to work out fee - *numRecipients = 0; - - Slice skey, svalue; - Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - skey = it->key(); - string recipientAddress = skey.ToString(); - svalue = it->value(); - string strValue = svalue.ToString(); - // see if txid is in the data - size_t txidMatch = strValue.find(txid.ToString()); - if(txidMatch!=std::string::npos) - { - ++*numRecipients; - // the txid exists inside the data, this address was a recipient of this STO, check filter and add the details - if(filter) - { - if( ( (filterByAddress) && (filterAddress == recipientAddress) ) || ( (filterByWallet) && (IsMyAddress(recipientAddress)) ) ) - { } else { continue; } // move on if no filter match (but counter still increased for fee) - } - std::vector vstr; - boost::split(vstr, strValue, boost::is_any_of(","), token_compress_on); - for(uint32_t i = 0; i svstr; - boost::split(svstr, vstr[i], boost::is_any_of(":"), token_compress_on); - if(4 == svstr.size()) - { - if(svstr[0] == txid.ToString()) - { - //add data to array - uint64_t amount = 0; - uint64_t propertyId = 0; - try - { - amount = boost::lexical_cast(svstr[3]); - propertyId = boost::lexical_cast(svstr[2]); - } catch (const boost::bad_lexical_cast &e) - { - PrintToLog("DEBUG STO - error in converting values from leveldb\n"); - delete it; - return; //(something went wrong) - } - UniValue recipient(UniValue::VOBJ); - recipient.push_back(Pair("address", recipientAddress)); - if(isPropertyDivisible(propertyId)) - { - recipient.push_back(Pair("amount", FormatDivisibleMP(amount))); - } - else - { - recipient.push_back(Pair("amount", FormatIndivisibleMP(amount))); - } - *total += amount; - recipientArray->push_back(recipient); - ++count; - } - } - } - } - } - - delete it; - return; -} - -bool CMPSTOList::exists(string address) -{ - if (!pdb) return false; - - string strValue; - Status status = pdb->Get(readoptions, address, &strValue); - - if (!status.ok()) - { - if (status.IsNotFound()) return false; - } - - return true; -} - -void CMPSTOList::recordSTOReceive(string address, const uint256 &txid, int nBlock, unsigned int propertyId, uint64_t amount) -{ - if (!pdb) return; - - bool addressExists = s_stolistdb->exists(address); - if (addressExists) - { - //retrieve existing record - std::vector vstr; - string strValue; - Status status = pdb->Get(readoptions, address, &strValue); - if (status.ok()) - { - // add details to record - // see if we are overwriting (check) - size_t txidMatch = strValue.find(txid.ToString()); - if(txidMatch!=std::string::npos) PrintToLog("STODEBUG : Duplicating entry for %s : %s\n",address,txid.ToString()); - - const string key = address; - const string newValue = strprintf("%s:%d:%u:%lu,", txid.ToString(), nBlock, propertyId, amount); - strValue += newValue; - // write updated record - Status status; - if (pdb) - { - status = pdb->Put(writeoptions, key, strValue); - PrintToLog("STODBDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString(), __LINE__, __FILE__); - } - } - } - else - { - const string key = address; - const string value = strprintf("%s:%d:%u:%lu,", txid.ToString(), nBlock, propertyId, amount); - Status status; - if (pdb) - { - status = pdb->Put(writeoptions, key, value); - PrintToLog("STODBDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString(), __LINE__, __FILE__); - } - } -} - -void CMPSTOList::printAll() -{ - int count = 0; - Slice skey, svalue; - Iterator* it = NewIterator(); - - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - skey = it->key(); - svalue = it->value(); - ++count; - PrintToLog("entry #%8d= %s:%s\n", count, skey.ToString(), svalue.ToString()); - } - - delete it; -} - -void CMPSTOList::printStats() -{ - PrintToLog("CMPSTOList stats: tWritten= %d , tRead= %d\n", nWritten, nRead); -} - -/** - * This function deletes records of STO receivers above/equal to a specific block from the STO database. - * - * Returns the number of records changed. - */ -int CMPSTOList::deleteAboveBlock(int blockNum) -{ - unsigned int n_found = 0; - std::vector vecSTORecords; - leveldb::Iterator* it = NewIterator(); - for (it->SeekToFirst(); it->Valid(); it->Next()) { - std::string newValue; - std::string oldValue = it->value().ToString(); - bool needsUpdate = false; - boost::split(vecSTORecords, oldValue, boost::is_any_of(","), boost::token_compress_on); - for (uint32_t i = 0; i vecSTORecordFields; - boost::split(vecSTORecordFields, vecSTORecords[i], boost::is_any_of(":"), boost::token_compress_on); - if (4 != vecSTORecordFields.size()) continue; - if (atoi(vecSTORecordFields[1]) < blockNum) { - newValue += vecSTORecords[i].append(","); // STO before the reorg, add data back to new value string - } else { - needsUpdate = true; - } - } - if (needsUpdate) { // rewrite record with existing key and new value - ++n_found; - leveldb::Status status = pdb->Put(writeoptions, it->key().ToString(), newValue); - PrintToLog("DEBUG STO - rewriting STO data after reorg\n"); - PrintToLog("STODBDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString(), __LINE__, __FILE__); - } - } - - PrintToLog("%s(%d); stodb updated records= %d\n", __FUNCTION__, blockNum, n_found); - - delete it; - - return (n_found); -} - -// MPTradeList here -bool CMPTradeList::getMatchingTrades(const uint256& txid, uint32_t propertyId, UniValue& tradeArray, int64_t& totalSold, int64_t& totalReceived) -{ - if (!pdb) return false; - - int count = 0; - totalReceived = 0; - totalSold = 0; - - std::vector vstr; - string txidStr = txid.ToString(); - leveldb::Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) { - // search key to see if this is a matching trade - std::string strKey = it->key().ToString(); - std::string strValue = it->value().ToString(); - std::string matchTxid; - size_t txidMatch = strKey.find(txidStr); - if (txidMatch == std::string::npos) continue; // no match - - // sanity check key is the correct length for a matched trade - if (strKey.length() != 129) continue; - - // obtain the txid of the match - if (txidMatch==0) { matchTxid = strKey.substr(65,64); } else { matchTxid = strKey.substr(0,64); } - - // ensure correct amount of tokens in value string - boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); - if (vstr.size() != 8) { - PrintToLog("TRADEDB error - unexpected number of tokens in value (%s)\n", strValue); - continue; - } - - // decode the details from the value string - std::string address1 = vstr[0]; - std::string address2 = vstr[1]; - uint32_t prop1 = boost::lexical_cast(vstr[2]); - uint32_t prop2 = boost::lexical_cast(vstr[3]); - int64_t amount1 = boost::lexical_cast(vstr[4]); - int64_t amount2 = boost::lexical_cast(vstr[5]); - int blockNum = atoi(vstr[6]); - int64_t tradingFee = boost::lexical_cast(vstr[7]); - - std::string strAmount1 = FormatMP(prop1, amount1); - std::string strAmount2 = FormatMP(prop2, amount2); - std::string strTradingFee = FormatMP(prop2, tradingFee); - std::string strAmount2PlusFee = FormatMP(prop2, amount2+tradingFee); - - // populate trade object and add to the trade array, correcting for orientation of trade - UniValue trade(UniValue::VOBJ); - trade.push_back(Pair("txid", matchTxid)); - trade.push_back(Pair("block", blockNum)); - if (prop1 == propertyId) { - trade.push_back(Pair("address", address1)); - trade.push_back(Pair("amountsold", strAmount1)); - trade.push_back(Pair("amountreceived", strAmount2)); - trade.push_back(Pair("tradingfee", strTradingFee)); - totalReceived += amount2; - totalSold += amount1; - } else { - trade.push_back(Pair("address", address2)); - trade.push_back(Pair("amountsold", strAmount2PlusFee)); - trade.push_back(Pair("amountreceived", strAmount1)); - trade.push_back(Pair("tradingfee", FormatMP(prop1, 0))); // not the liquidity taker so no fee for this participant - include attribute for standardness - totalReceived += amount1; - totalSold += amount2; - } - tradeArray.push_back(trade); - ++count; - } - - // clean up - delete it; - if (count) { return true; } else { return false; } -} - -bool CompareTradePair(const std::pair& firstJSONObj, const std::pair& secondJSONObj) -{ - return firstJSONObj.first > secondJSONObj.first; -} - -// obtains an array of matching trades with pricing and volume details for a pair sorted by blocknumber -void CMPTradeList::getTradesForPair(uint32_t propertyIdSideA, uint32_t propertyIdSideB, UniValue& responseArray, uint64_t count) -{ - if (!pdb) return; - leveldb::Iterator* it = NewIterator(); - std::vector > vecResponse; - bool propertyIdSideAIsDivisible = isPropertyDivisible(propertyIdSideA); - bool propertyIdSideBIsDivisible = isPropertyDivisible(propertyIdSideB); - for(it->SeekToFirst(); it->Valid(); it->Next()) { - std::string strKey = it->key().ToString(); - std::string strValue = it->value().ToString(); - std::vector vecKeys; - std::vector vecValues; - uint256 sellerTxid, matchingTxid; - std::string sellerAddress, matchingAddress; - int64_t amountReceived = 0, amountSold = 0; - if (strKey.size() != 129) continue; // only interested in matches - boost::split(vecKeys, strKey, boost::is_any_of("+"), boost::token_compress_on); - boost::split(vecValues, strValue, boost::is_any_of(":"), boost::token_compress_on); - if (vecKeys.size() != 2 || vecValues.size() != 8) { - PrintToLog("TRADEDB error - unexpected number of tokens (%s:%s)\n", strKey, strValue); - continue; - } - uint32_t tradePropertyIdSideA = boost::lexical_cast(vecValues[2]); - uint32_t tradePropertyIdSideB = boost::lexical_cast(vecValues[3]); - if (tradePropertyIdSideA == propertyIdSideA && tradePropertyIdSideB == propertyIdSideB) { - sellerTxid.SetHex(vecKeys[1]); - sellerAddress = vecValues[1]; - amountSold = boost::lexical_cast(vecValues[4]); - matchingTxid.SetHex(vecKeys[0]); - matchingAddress = vecValues[0]; - amountReceived = boost::lexical_cast(vecValues[5]); - } else if (tradePropertyIdSideB == propertyIdSideA && tradePropertyIdSideA == propertyIdSideB) { - sellerTxid.SetHex(vecKeys[0]); - sellerAddress = vecValues[0]; - amountSold = boost::lexical_cast(vecValues[5]); - matchingTxid.SetHex(vecKeys[1]); - matchingAddress = vecValues[1]; - amountReceived = boost::lexical_cast(vecValues[4]); - } else { - continue; - } - - rational_t unitPrice(amountReceived, amountSold); - rational_t inversePrice(amountSold, amountReceived); - if (!propertyIdSideAIsDivisible) unitPrice = unitPrice / COIN; - if (!propertyIdSideBIsDivisible) inversePrice = inversePrice / COIN; - std::string unitPriceStr = xToString(unitPrice); // TODO: not here! - std::string inversePriceStr = xToString(inversePrice); - - int64_t blockNum = boost::lexical_cast(vecValues[6]); - - UniValue trade(UniValue::VOBJ); - trade.push_back(Pair("block", blockNum)); - trade.push_back(Pair("unitprice", unitPriceStr)); - trade.push_back(Pair("inverseprice", inversePriceStr)); - trade.push_back(Pair("sellertxid", sellerTxid.GetHex())); - trade.push_back(Pair("selleraddress", sellerAddress)); - if (propertyIdSideAIsDivisible) { - trade.push_back(Pair("amountsold", FormatDivisibleMP(amountSold))); - } else { - trade.push_back(Pair("amountsold", FormatIndivisibleMP(amountSold))); - } - if (propertyIdSideBIsDivisible) { - trade.push_back(Pair("amountreceived", FormatDivisibleMP(amountReceived))); - } else { - trade.push_back(Pair("amountreceived", FormatIndivisibleMP(amountReceived))); - } - trade.push_back(Pair("matchingtxid", matchingTxid.GetHex())); - trade.push_back(Pair("matchingaddress", matchingAddress)); - vecResponse.push_back(make_pair(blockNum, trade)); - } - - // sort the response most recent first before adding to the array - std::sort(vecResponse.begin(), vecResponse.end(), CompareTradePair); - uint64_t processed = 0; - for (std::vector >::iterator it = vecResponse.begin(); it != vecResponse.end(); ++it) { - responseArray.push_back(it->second); - processed++; - if (processed >= count) break; - } - - std::vector responseArrayValues = responseArray.getValues(); - std::reverse(responseArrayValues.begin(), responseArrayValues.end()); - responseArray.clear(); - for (std::vector::iterator it = responseArrayValues.begin(); it != responseArrayValues.end(); ++it) { - responseArray.push_back(*it); - } - - delete it; -} - -// obtains a vector of txids where the supplied address participated in a trade (needed for gettradehistory_MP) -// optional property ID parameter will filter on propertyId transacted if supplied -// sorted by block then index -void CMPTradeList::getTradesForAddress(std::string address, std::vector& vecTransactions, uint32_t propertyIdFilter) -{ - if (!pdb) return; - std::map mapTrades; - leveldb::Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) { - std::string strKey = it->key().ToString(); - std::string strValue = it->value().ToString(); - std::vector vecValues; - if (strKey.size() != 64) continue; // only interested in trades - uint256 txid = uint256S(strKey); - size_t addressMatch = strValue.find(address); - if (addressMatch == std::string::npos) continue; - boost::split(vecValues, strValue, boost::is_any_of(":"), token_compress_on); - if (vecValues.size() != 5) { - PrintToLog("TRADEDB error - unexpected number of tokens in value (%s)\n", strValue); - continue; - } - uint32_t propertyIdForSale = boost::lexical_cast(vecValues[1]); - uint32_t propertyIdDesired = boost::lexical_cast(vecValues[2]); - int64_t blockNum = boost::lexical_cast(vecValues[3]); - int64_t txIndex = boost::lexical_cast(vecValues[4]); - if (propertyIdFilter != 0 && propertyIdFilter != propertyIdForSale && propertyIdFilter != propertyIdDesired) continue; - std::string sortKey = strprintf("%06d%010d", blockNum, txIndex); - mapTrades.insert(std::make_pair(sortKey, txid)); - } - delete it; - for (std::map::iterator it = mapTrades.begin(); it != mapTrades.end(); it++) { - vecTransactions.push_back(it->second); - } -} - -void CMPTradeList::recordNewTrade(const uint256& txid, const std::string& address, uint32_t propertyIdForSale, uint32_t propertyIdDesired, int blockNum, int blockIndex) -{ - if (!pdb) return; - std::string strValue = strprintf("%s:%d:%d:%d:%d", address, propertyIdForSale, propertyIdDesired, blockNum, blockIndex); - Status status = pdb->Put(writeoptions, txid.ToString(), strValue); - ++nWritten; - if (elysium_debug_tradedb) PrintToLog("%s(): %s\n", __FUNCTION__, status.ToString()); -} - -void CMPTradeList::recordMatchedTrade(const uint256 txid1, const uint256 txid2, string address1, string address2, unsigned int prop1, unsigned int prop2, uint64_t amount1, uint64_t amount2, int blockNum, int64_t fee) -{ - if (!pdb) return; - const string key = txid1.ToString() + "+" + txid2.ToString(); - const string value = strprintf("%s:%s:%u:%u:%lu:%lu:%d:%d", address1, address2, prop1, prop2, amount1, amount2, blockNum, fee); - Status status; - if (pdb) - { - status = pdb->Put(writeoptions, key, value); - ++nWritten; - if (elysium_debug_tradedb) PrintToLog("%s(): %s\n", __FUNCTION__, status.ToString()); - } -} - -/** - * This function deletes records of trades above/equal to a specific block from the trade database. - * - * Returns the number of records changed. - */ -int CMPTradeList::deleteAboveBlock(int blockNum) -{ - leveldb::Slice skey, svalue; - unsigned int count = 0; - std::vector vstr; - int block = 0; - unsigned int n_found = 0; - leveldb::Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - skey = it->key(); - svalue = it->value(); - ++count; - string strvalue = it->value().ToString(); - boost::split(vstr, strvalue, boost::is_any_of(":"), token_compress_on); - if (7 == vstr.size()) block = atoi(vstr[6]); // trade matches have 7 tokens, key is txid+txid, only care about block - if (5 == vstr.size()) block = atoi(vstr[3]); // trades have 5 tokens, key is txid, only care about block - if (block >= blockNum) { - ++n_found; - PrintToLog("%s() DELETING FROM TRADEDB: %s=%s\n", __FUNCTION__, skey.ToString(), svalue.ToString()); - pdb->Delete(writeoptions, skey); - } - } - - PrintToLog("%s(%d); tradedb n_found= %d\n", __FUNCTION__, blockNum, n_found); - - delete it; - - return (n_found); -} - -void CMPTradeList::printStats() -{ - PrintToLog("CMPTradeList stats: tWritten= %d , tRead= %d\n", nWritten, nRead); -} - -int CMPTradeList::getMPTradeCountTotal() -{ - int count = 0; - Slice skey, svalue; - Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - ++count; - } - delete it; - return count; -} - -void CMPTradeList::printAll() -{ - int count = 0; - Slice skey, svalue; - Iterator* it = NewIterator(); - - for(it->SeekToFirst(); it->Valid(); it->Next()) - { - skey = it->key(); - svalue = it->value(); - ++count; - PrintToLog("entry #%8d= %s:%s\n", count, skey.ToString(), svalue.ToString()); - } - - delete it; -} - -// global wrapper, block numbers are inclusive, if ending_block is 0 top of the chain will be used -bool elysium::isMPinBlockRange(int starting_block, int ending_block, bool bDeleteFound) -{ - if (!p_txlistdb) return false; - - if (0 == ending_block) ending_block = GetHeight(); // will scan 'til the end - - return p_txlistdb->isMPinBlockRange(starting_block, ending_block, bDeleteFound); -} - -// call it like so (variable # of parameters): -// int block = 0; -// ... -// uint64_t nNew = 0; -// -// if (getValidMPTX(txid, &block, &type, &nNew)) // if true -- the TX is a valid MP TX -// -bool elysium::getValidMPTX(const uint256 &txid, int *block, unsigned int *type, uint64_t *nAmended) -{ -string result; -int validity = 0; - - if (elysium_debug_txdb) PrintToLog("%s()\n", __FUNCTION__); - - if (!p_txlistdb) return false; - - if (!p_txlistdb->getTX(txid, result)) return false; - - // parse the string returned, find the validity flag/bit & other parameters - std::vector vstr; - boost::split(vstr, result, boost::is_any_of(":"), token_compress_on); - - if (elysium_debug_txdb) PrintToLog("%s() size=%lu : %s\n", __FUNCTION__, vstr.size(), result); - - if (1 <= vstr.size()) validity = atoi(vstr[0]); - - if (block) - { - if (2 <= vstr.size()) *block = atoi(vstr[1]); - else *block = 0; - } - - if (type) - { - if (3 <= vstr.size()) *type = atoi(vstr[2]); - else *type = 0; - } - - if (nAmended) - { - if (4 <= vstr.size()) *nAmended = boost::lexical_cast(vstr[3]); - else nAmended = 0; - } - - if (elysium_debug_txdb) p_txlistdb->printStats(); - - if ((int)0 == validity) return false; - - return true; -} - -int elysium_handler_block_begin(int nBlockPrev, CBlockIndex const * pBlockIndex) -{ - LOCK(cs_main); - - if (reorgRecoveryMode > 0) { - reorgRecoveryMode = 0; // clear reorgRecovery here as this is likely re-entrant - - // Check if any freeze related transactions would be rolled back - if so wipe the state and startclean - bool reorgContainsFreeze = p_txlistdb->CheckForFreezeTxs(pBlockIndex->nHeight); - - // NOTE: The blockNum parameter is inclusive, so deleteAboveBlock(1000) will delete records in block 1000 and above. - p_txlistdb->isMPinBlockRange(pBlockIndex->nHeight, reorgRecoveryMaxHeight, true); - t_tradelistdb->deleteAboveBlock(pBlockIndex->nHeight); - s_stolistdb->deleteAboveBlock(pBlockIndex->nHeight); - p_feecache->RollBackCache(pBlockIndex->nHeight); - p_feehistory->RollBackHistory(pBlockIndex->nHeight); - sigmaDb->DeleteAll(pBlockIndex->nHeight); - reorgRecoveryMaxHeight = 0; - - nWaterlineBlock = ConsensusParams().GENESIS_BLOCK - 1; - - if (reorgContainsFreeze) { - PrintToLog("Reorganization containing freeze related transactions detected, forcing a reparse...\n"); - clear_all_state(); // unable to reorg freezes safely, clear state and reparse - } else { - int best_state_block = load_most_relevant_state(); - if (best_state_block < 0) { - // unable to recover easily, remove stale stale state bits and reparse from the beginning. - clear_all_state(); - } else { - nWaterlineBlock = best_state_block; - } - } - - // clear the global wallet property list, perform a forced wallet update and tell the UI that state is no longer valid, and UI views need to be reinit - global_wallet_property_list.clear(); - CheckWalletUpdate(true); - uiInterface.ElysiumStateInvalidated(); - - if (nWaterlineBlock < nBlockPrev) { - // scan from the block after the best active block to catch up to the active chain - elysium_initial_scan(nWaterlineBlock + 1); - } - } - - // handle any features that go live with this block - CheckLiveActivations(pBlockIndex->nHeight); - - eraseExpiredCrowdsale(pBlockIndex); - - return 0; -} - -// called once per block, after the block has been processed -// TODO: consolidate into *handler_block_begin() << need to adjust Accept expiry check............. -// it performs cleanup and other functions -int elysium_handler_block_end(int nBlockNow, CBlockIndex const * pBlockIndex, - unsigned int countMP) -{ - LOCK(cs_main); - - if (!elysiumInitialized) { - elysium_init(); - } - - // for every new received block must do: - // 1) remove expired entries from the accept list (per spec accept entries are - // valid until their blocklimit expiration; because the customer can keep - // paying BTC for the offer in several installments) - // 2) update the amount in the Elysium address - int64_t develysium = 0; - unsigned int how_many_erased = eraseExpiredAccepts(nBlockNow); - - if (how_many_erased) { - PrintToLog("%s(%d); erased %u accepts this block, line %d, file: %s\n", - __FUNCTION__, how_many_erased, nBlockNow, __LINE__, __FILE__); - } - - // calculate develysium as of this block and update the Elysium' balance - develysium = calculate_and_update_develysium(pBlockIndex->GetBlockTime(), nBlockNow); - - if (elysium_debug_ely) { - int64_t balance = getMPbalance(GetSystemAddress().ToString(), ELYSIUM_PROPERTY_ELYSIUM, BALANCE); - PrintToLog("develysium for block %d: %d, Elysium balance: %d\n", nBlockNow, develysium, FormatDivisibleMP(balance)); - } - - // check the alert status, do we need to do anything else here? - CheckExpiredAlerts(nBlockNow, pBlockIndex->GetBlockTime()); - - // check that pending transactions are still in the mempool - PendingCheck(); - - // transactions were found in the block, signal the UI accordingly - if (countMP > 0) CheckWalletUpdate(true); - - // calculate and print a consensus hash if required - if (ShouldConsensusHashBlock(nBlockNow)) { - uint256 consensusHash = GetConsensusHash(); - PrintToLog("Consensus hash for block %d: %s\n", nBlockNow, consensusHash.GetHex()); - } - - // request checkpoint verification - bool checkpointValid = VerifyCheckpoint(nBlockNow, pBlockIndex->GetBlockHash()); - if (!checkpointValid) { - // failed checkpoint, can't be trusted to provide valid data - shutdown client - const std::string& msg = strprintf("Shutting down due to failed checkpoint for block %d (hash %s)\n", nBlockNow, pBlockIndex->GetBlockHash().GetHex()); - PrintToLog(msg); - if (!GetBoolArg("-overrideforcedshutdown", false)) { - boost::filesystem::path persistPath = GetDataDir() / "MP_persist"; - if (boost::filesystem::exists(persistPath)) boost::filesystem::remove_all(persistPath); // prevent the node being restarted without a reparse after forced shutdown - AbortNode(msg, msg); - } - } else { - // save out the state after this block - if (writePersistence(nBlockNow)) { - elysium_save_state(pBlockIndex); - } - } - - return 0; -} - -int elysium_handler_disc_begin(int nBlockNow, CBlockIndex const * pBlockIndex) -{ - LOCK(cs_main); - - reorgRecoveryMode = 1; - reorgRecoveryMaxHeight = (pBlockIndex->nHeight > reorgRecoveryMaxHeight) ? pBlockIndex->nHeight: reorgRecoveryMaxHeight; - return 0; -} - -int elysium_handler_disc_end(int nBlockNow, CBlockIndex const * pBlockIndex) -{ - return 0; -} diff --git a/src/elysium/elysium.h b/src/elysium/elysium.h deleted file mode 100644 index 319306d129..0000000000 --- a/src/elysium/elysium.h +++ /dev/null @@ -1,340 +0,0 @@ -#ifndef FIRO_ELYSIUM_ELYSIUM_H -#define FIRO_ELYSIUM_ELYSIUM_H - -class CBlockIndex; -class CCoinsView; -class CCoinsViewCache; -class CTransaction; - -#include "log.h" -#include "persistence.h" -#include "tally.h" -#include "sigma.h" -#include "sigmadb.h" - -#include "../base58.h" -#include "../sync.h" -#include "../uint256.h" -#include "../util.h" - -#include - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -using std::string; - -int const MAX_STATE_HISTORY = 50; - -constexpr size_t ELYSIUM_MAX_SIMPLE_MINTS = std::numeric_limits::max(); - -// increment this value to force a refresh of the state (similar to --startclean) -#define DB_VERSION 6 - -// maximum size of string fields -#define SP_STRING_FIELD_LEN 256 - -// Elysium Transaction (Packet) Version -#define MP_TX_PKT_V0 0 -#define MP_TX_PKT_V1 1 - -#define MIN_PAYLOAD_SIZE 5 - -#define ELYSIUM_PROPERTY_TYPE_INDIVISIBLE 1 -#define ELYSIUM_PROPERTY_TYPE_DIVISIBLE 2 -#define ELYSIUM_PROPERTY_TYPE_INDIVISIBLE_REPLACING 65 -#define ELYSIUM_PROPERTY_TYPE_DIVISIBLE_REPLACING 66 -#define ELYSIUM_PROPERTY_TYPE_INDIVISIBLE_APPENDING 129 -#define ELYSIUM_PROPERTY_TYPE_DIVISIBLE_APPENDING 130 - -enum FILETYPES { - FILETYPE_BALANCES = 0, - FILETYPE_OFFERS, - FILETYPE_ACCEPTS, - FILETYPE_GLOBALS, - FILETYPE_CROWDSALES, - FILETYPE_MDEXORDERS, - NUM_FILETYPES -}; - -#define PKT_RETURNED_OBJECT (1000) - -#define PKT_ERROR ( -9000) -#define DEX_ERROR_SELLOFFER (-10000) -#define DEX_ERROR_ACCEPT (-20000) -#define DEX_ERROR_PAYMENT (-30000) -// Smart Properties -#define PKT_ERROR_SP (-40000) -#define PKT_ERROR_CROWD (-45000) -// Send To Owners -#define PKT_ERROR_STO (-50000) -#define PKT_ERROR_SEND (-60000) -#define PKT_ERROR_TRADEOFFER (-70000) -#define PKT_ERROR_METADEX (-80000) -#define METADEX_ERROR (-81000) -#define PKT_ERROR_TOKENS (-82000) -#define PKT_ERROR_SEND_ALL (-83000) -#define PKT_ERROR_SIGMA (-84000) - -#define ELYSIUM_PROPERTY_XZC 0 -#define ELYSIUM_PROPERTY_ELYSIUM 1 -#define ELYSIUM_PROPERTY_TELYSIUM 2 - -// forward declarations -std::string FormatDivisibleMP(int64_t amount, bool fSign = false); -std::string FormatDivisibleShortMP(int64_t amount); -std::string FormatMP(uint32_t propertyId, int64_t amount, bool fSign = false); -std::string FormatShortMP(uint32_t propertyId, int64_t amount); -std::string FormatByType(int64_t amount, uint16_t propertyType); - -//! Used to indicate, whether to automatically commit created transactions -extern bool autoCommit; - -/** LevelDB based storage for storing Elysium transaction data. This will become the new master database, holding serialized Elysium transactions. - * Note, intention is to consolidate and clean up data storage - */ -class CElysiumTransactionDB : public CDBBase -{ -public: - CElysiumTransactionDB(const boost::filesystem::path& path, bool fWipe) - { - leveldb::Status status = Open(path, fWipe); - PrintToLog("Loading master transactions database: %s\n", status.ToString()); - } - - virtual ~CElysiumTransactionDB() - { - if (elysium_debug_persistence) PrintToLog("CElysiumTransactionDB closed\n"); - } - - /* These functions would be expanded upon to store a serialized version of the transaction and associated state data - * - * void RecordTransaction(const uint256& txid, uint32_t posInBlock, various, other, data); - * int FetchTransactionPosition(const uint256& txid); - * bool FetchTransactionValidity(const uint256& txid); - * - * and so on... - */ - void RecordTransaction(const uint256& txid, uint32_t posInBlock, int processingResult); - std::vector FetchTransactionDetails(const uint256& txid); - uint32_t FetchTransactionPosition(const uint256& txid); - std::string FetchInvalidReason(const uint256& txid); -}; - -/** LevelDB based storage for STO recipients. - */ -class CMPSTOList : public CDBBase -{ -public: - CMPSTOList(const boost::filesystem::path& path, bool fWipe) - { - leveldb::Status status = Open(path, fWipe); - PrintToLog("Loading send-to-owners database: %s\n", status.ToString()); - } - - virtual ~CMPSTOList() - { - if (elysium_debug_persistence) PrintToLog("CMPSTOList closed\n"); - } - - void getRecipients(const uint256 txid, string filterAddress, UniValue *recipientArray, uint64_t *total, uint64_t *numRecipients); - std::string getMySTOReceipts(string filterAddress); - int deleteAboveBlock(int blockNum); - void printStats(); - void printAll(); - bool exists(string address); - void recordSTOReceive(std::string, const uint256&, int, unsigned int, uint64_t); -}; - -/** LevelDB based storage for the trade history. Trades are listed with key "txid1+txid2". - */ -class CMPTradeList : public CDBBase -{ -public: - CMPTradeList(const boost::filesystem::path& path, bool fWipe) - { - leveldb::Status status = Open(path, fWipe); - PrintToLog("Loading trades database: %s\n", status.ToString()); - } - - virtual ~CMPTradeList() - { - if (elysium_debug_persistence) PrintToLog("CMPTradeList closed\n"); - } - - void recordMatchedTrade(const uint256 txid1, const uint256 txid2, string address1, string address2, unsigned int prop1, unsigned int prop2, uint64_t amount1, uint64_t amount2, int blockNum, int64_t fee); - void recordNewTrade(const uint256& txid, const std::string& address, uint32_t propertyIdForSale, uint32_t propertyIdDesired, int blockNum, int blockIndex); - int deleteAboveBlock(int blockNum); - bool exists(const uint256 &txid); - void printStats(); - void printAll(); - bool getMatchingTrades(const uint256& txid, uint32_t propertyId, UniValue& tradeArray, int64_t& totalSold, int64_t& totalBought); - void getTradesForAddress(std::string address, std::vector& vecTransactions, uint32_t propertyIdFilter = 0); - void getTradesForPair(uint32_t propertyIdSideA, uint32_t propertyIdSideB, UniValue& response, uint64_t count); - int getMPTradeCountTotal(); -}; - -/** LevelDB based storage for transactions, with txid as key and validity bit, and other data as value. - */ -class CMPTxList : public CDBBase -{ -public: - CMPTxList(const boost::filesystem::path& path, bool fWipe) - { - leveldb::Status status = Open(path, fWipe); - PrintToLog("Loading tx meta-info database: %s\n", status.ToString()); - } - - virtual ~CMPTxList() - { - if (elysium_debug_persistence) PrintToLog("CMPTxList closed\n"); - } - - void recordTX(const uint256 &txid, bool fValid, int nBlock, unsigned int type, uint64_t nValue); - void recordPaymentTX(const uint256 &txid, bool fValid, int nBlock, unsigned int vout, unsigned int propertyId, uint64_t nValue, string buyer, string seller); - void recordMetaDExCancelTX(const uint256 &txidMaster, const uint256 &txidSub, bool fValid, int nBlock, unsigned int propertyId, uint64_t nValue); - /** Records a "send all" sub record. */ - void recordSendAllSubRecord(const uint256& txid, int subRecordNumber, uint32_t propertyId, int64_t nvalue); - - string getKeyValue(string key); - uint256 findMetaDExCancel(const uint256 txid); - /** Returns the number of sub records. */ - int getNumberOfSubRecords(const uint256& txid); - int getNumberOfMetaDExCancels(const uint256 txid); - bool getPurchaseDetails(const uint256 txid, int purchaseNumber, string *buyer, string *seller, uint64_t *vout, uint64_t *propertyId, uint64_t *nValue); - /** Retrieves details about a "send all" record. */ - bool getSendAllDetails(const uint256& txid, int subSend, uint32_t& propertyId, int64_t& amount); - int getMPTransactionCountTotal(); - int getMPTransactionCountBlock(int block); - - int getDBVersion(); - int setDBVersion(); - - bool exists(const uint256 &txid); - bool getTX(const uint256 &txid, string &value); - - std::set GetSeedBlocks(int startHeight, int endHeight); - void LoadAlerts(int blockHeight); - void LoadActivations(int blockHeight); - bool LoadFreezeState(int blockHeight); - bool CheckForFreezeTxs(int blockHeight); - - void printStats(); - void printAll(); - - bool isMPinBlockRange(int, int, bool); -}; - -//! Available balances of wallet properties -extern std::map global_balance_money; -//! Reserved balances of wallet propertiess -extern std::map global_balance_reserved; -//! Vector containing a list of properties relative to the wallet -extern std::set global_wallet_property_list; - -int64_t getMPbalance(const std::string& address, uint32_t propertyId, TallyType ttype); -int64_t getUserAvailableMPbalance(const std::string& address, uint32_t propertyId); -int64_t getUserFrozenMPbalance(const std::string& address, uint32_t propertyId); - -bool isElysiumEnabled(); - -/** Global handler to initialize Elysium Core. */ -int elysium_init(); - -/** Global handler to shut down Elysium Core. */ -int elysium_shutdown(); - -/** Global handler to total wallet balances. */ -void CheckWalletUpdate(bool forceUpdate = false); - -/** Used to notify that the number of tokens for a property has changed. */ -void NotifyTotalTokensChanged(uint32_t propertyId, int block); - -int elysium_handler_disc_begin(int nBlockNow, CBlockIndex const * pBlockIndex); -int elysium_handler_disc_end(int nBlockNow, CBlockIndex const * pBlockIndex); -int elysium_handler_block_begin(int nBlockNow, CBlockIndex const * pBlockIndex); -int elysium_handler_block_end(int nBlockNow, CBlockIndex const * pBlockIndex, unsigned int); -bool elysium_handler_tx(const CTransaction& tx, int nBlock, unsigned int idx, const CBlockIndex* pBlockIndex); -int elysium_save_state( CBlockIndex const *pBlockIndex ); - -namespace elysium -{ -extern std::unordered_map mp_tally_map; -extern CMPTxList *p_txlistdb; -extern CMPTradeList *t_tradelistdb; -extern CMPSTOList *s_stolistdb; -extern CElysiumTransactionDB *p_ElysiumTXDB; - -// TODO: move, rename -extern CCoinsView viewDummy; -extern CCoinsViewCache view; -//! Guards coins view cache -extern CCriticalSection cs_tx_cache; - -std::string strMPProperty(uint32_t propertyId); - -bool isMPinBlockRange(int starting_block, int ending_block, bool bDeleteFound); - -std::string FormatIndivisibleMP(int64_t n); - -enum class InputMode { - NORMAL, - SIGMA -}; - -int WalletTxBuilder(const std::string& senderAddress, const std::string& receiverAddress, const std::string& redemptionAddress, - int64_t referenceAmount, const std::vector& data, uint256& txid, std::string& rawHex, bool commit, - InputMode inputMode = InputMode::NORMAL); - -bool isTestEcosystemProperty(uint32_t propertyId); -bool isMainEcosystemProperty(uint32_t propertyId); -uint32_t GetNextPropertyId(bool maineco); // maybe move into sp - -CMPTally* getTally(const std::string& address); - -int64_t getTotalTokens(uint32_t propertyId, int64_t* n_owners_total = NULL); - -std::string strTransactionType(uint16_t txType); - -/** Determines, whether it is valid to use a Class C transaction for a given payload size. */ -bool UseEncodingClassC(size_t nDataSize); - -bool getValidMPTX(const uint256 &txid, int *block = NULL, unsigned int *type = NULL, uint64_t *nAmended = NULL); - -bool update_tally_map(const std::string& who, uint32_t propertyId, int64_t amount, TallyType ttype); - -std::string getTokenLabel(uint32_t propertyId); - -/** - NOTE: The following functions are only permitted for properties - managed by a central issuer that have enabled freezing. - **/ -/** Adds an address and property to the frozenMap **/ -void freezeAddress(const std::string& address, uint32_t propertyId); -/** Removes an address and property from the frozenMap **/ -void unfreezeAddress(const std::string& address, uint32_t propertyId); -/** Checks whether an address and property are frozen **/ -bool isAddressFrozen(const std::string& address, uint32_t propertyId); -/** Adds a property to the freezingEnabledMap **/ -void enableFreezing(uint32_t propertyId, int liveBlock); -/** Removes a property from the freezingEnabledMap **/ -void disableFreezing(uint32_t propertyId); -/** Checks whether a property has freezing enabled **/ -bool isFreezingEnabled(uint32_t propertyId, int block); -/** Clears the freeze state in the event of a reorg **/ -void ClearFreezeState(); -/** Prints the freeze state **/ -void PrintFreezeState(); - -} - -#endif // FIRO_ELYSIUM_ELYSIUM_H diff --git a/src/elysium/errors.h b/src/elysium/errors.h deleted file mode 100644 index c2c069fa15..0000000000 --- a/src/elysium/errors.h +++ /dev/null @@ -1,359 +0,0 @@ -#ifndef ELYSIUM_ERRORS_H -#define ELYSIUM_ERRORS_H - -#include - -#include "elysium/elysium.h" - -enum MPRPCErrorCode -{ - //INTERNAL_1packet - MP_INSUF_FUNDS_BPENDI = -1, // balance before pending - MP_INSUF_FUNDS_APENDI = -2, // balance after pending - MP_INPUT_NOT_IN_RANGE = -11, // input value larger than supported - - //ClassAgnosticWalletTXBuilder( - MP_INPUTS_INVALID = -212, - MP_SIGMA_INPUTS_INVALID = -214, - MP_ENCODING_ERROR = -250, - MP_REDEMP_ILLEGAL = -233, - MP_REDEMP_BAD_KEYID = -220, - MP_REDEMP_FETCH_ERR_PUBKEY = -221, - MP_REDEMP_INVALID_PUBKEY = -222, - MP_REDEMP_BAD_VALIDATION = -223, - MP_ERR_WALLET_ACCESS = -205, - MP_ERR_INPUTSELECT_FAIL = -206, - MP_ERR_CREATE_TX = -211, - MP_ERR_CREATE_SIGMA_TX = -215, - MP_ERR_COMMIT_TX = -213, - - //gettransaction_MP, listtransactions_MP - MP_TX_NOT_FOUND = -3331, // No information available about transaction. (GetTransaction failed) - MP_TX_UNCONFIRMED = -3332, // Unconfirmed transactions are not supported. (blockHash is 0) - MP_BLOCK_NOT_IN_CHAIN = -3333, // Transaction not part of the active chain. (pBlockIndex is NULL) - MP_CROWDSALE_WITHOUT_PROPERTY = -3334, // Potential database corruption: "Crowdsale Purchase" without valid property identifier. - MP_INVALID_TX_IN_DB_FOUND = -3335, // Potential database corruption: Invalid transaction found. - MP_TX_IS_NOT_ELYSIUM_PROTOCOL = -3336, // Not a Elysium Protocol transaction. -}; - -inline std::string error_str(int ec) { - std::string ec_str; - - switch (ec) - { - case MP_INSUF_FUNDS_BPENDI: - ec_str = "Not enough funds in user address"; - break; - case MP_INSUF_FUNDS_APENDI: - ec_str = "Not enough funds in user address due to PENDING/UNCONFIRMED transactions"; - break; - case MP_INPUT_NOT_IN_RANGE: - ec_str = "Input value supplied larger than supported in Master Protocol"; - break; - case MP_INPUTS_INVALID: - ec_str = "Error choosing inputs for the send transaction"; - break; - case MP_SIGMA_INPUTS_INVALID: - ec_str = "Error no sigma mints to pay as transaction fee"; - break; - case MP_ENCODING_ERROR: - ec_str = "Packet too large"; - break; - case MP_REDEMP_ILLEGAL: - ec_str = "Error with redemption address"; - break; - case MP_REDEMP_BAD_KEYID: - ec_str = "Error with redemption address key ID"; - break; - case MP_REDEMP_FETCH_ERR_PUBKEY: - ec_str = "Error obtaining public key for redemption address"; - break; - case MP_REDEMP_INVALID_PUBKEY: - ec_str = "Error public key for redemption address is not valid"; - break; - case MP_REDEMP_BAD_VALIDATION: - ec_str = "Error validating redemption address"; - break; - case MP_ERR_WALLET_ACCESS: - ec_str = "Error with wallet object"; - break; - case MP_ERR_INPUTSELECT_FAIL: - ec_str = "Error with selected inputs for the send transaction"; - break; - case MP_ERR_CREATE_TX: - ec_str = "Error creating transaction (wallet may be locked or fees may not be sufficient)"; - break; - case MP_ERR_CREATE_SIGMA_TX: - ec_str = "Error creating sigma spend transaction (wallet may be locked or sigma fees may not be sufficient)"; - break; - case MP_ERR_COMMIT_TX: - ec_str = "Error committing transaction"; - break; - - case PKT_ERROR -1: - ec_str = "Attempt to execute logic in RPC mode"; - break; - case PKT_ERROR -2: - ec_str = "Failed to interpret transaction"; - break; - case PKT_ERROR -3: - ec_str = "Sender is frozen for the property"; - break; - case PKT_ERROR -22: - ec_str = "Transaction type or version not permitted"; - break; - case PKT_ERROR -51: - ec_str = "Sender is not authorized"; - break; - case PKT_ERROR -54: - ec_str = "Activation failed"; - break; - - case PKT_ERROR -100: - ec_str = "Transaction is not a supported type"; - break; - case PKT_ERROR -500: - ec_str = "Transaction version is not supported"; - break; - case PKT_ERROR -999: - ec_str = "Failed to determine subaction"; - break; - - case PKT_ERROR_SEND -22: - ec_str = "Transaction type or version not permitted"; - break; - case PKT_ERROR_SEND -23: - ec_str = "Value out of range or zero"; - break; - case PKT_ERROR_SEND -24: - ec_str = "Property does not exist"; - break; - case PKT_ERROR_SEND -25: - ec_str = "Sender has insufficient balance"; - break; - - case PKT_ERROR_STO -22: - ec_str = "Transaction type or version not permitted"; - break; - case PKT_ERROR_STO -23: - ec_str = "Value out of range or zero"; - break; - case PKT_ERROR_STO -24: - ec_str = "Property does not exist"; - break; - case PKT_ERROR_STO -25: - ec_str = "Sender has insufficient balance"; - break; - case PKT_ERROR_STO -26: - ec_str = "No other owners of the property"; - break; - case PKT_ERROR_STO -27: - ec_str = "Sender has insufficient balance to pay for fee"; - break; - case PKT_ERROR_STO -28: - ec_str = "Sender has insufficient balance to pay for amount + fee"; - break; - - case PKT_ERROR_SEND_ALL -22: - ec_str = "Transaction type or version not permitted"; - break; - case PKT_ERROR_SEND_ALL -54: - ec_str = "Sender has no tokens to send"; - break; - case PKT_ERROR_SEND_ALL -55: - ec_str = "Sender has no tokens to send"; - break; - - case PKT_ERROR_TRADEOFFER -22: - ec_str = "Transaction type or version not permitted"; - break; - case PKT_ERROR_TRADEOFFER -23: - ec_str = "Value out of range or zero"; - break; - case PKT_ERROR_TRADEOFFER -47: - ec_str = "Property for sale must be ELYSIUM or TELYSIUM"; - break; - case PKT_ERROR_TRADEOFFER -49: - ec_str = "Sender has no active sell offer for the property"; - break; - case PKT_ERROR_TRADEOFFER -48: - ec_str = "Sender already has an active sell offer for the property"; - break; - - case DEX_ERROR_SELLOFFER -101: - ec_str = "Value out of range or zero"; - break; - case DEX_ERROR_SELLOFFER -10: - ec_str = "Sender already has an active sell offer for the property"; - break; - case DEX_ERROR_SELLOFFER -25: - ec_str = "Sender has insufficient balance"; - break; - case DEX_ERROR_SELLOFFER -11: - ec_str = "Sender has no active sell offer for the property"; - break; - case DEX_ERROR_SELLOFFER -12: - ec_str = "Sender has no active sell offer for the property"; - break; - - case DEX_ERROR_ACCEPT -15: - ec_str = "No matching sell offer for accept order found"; - break; - case DEX_ERROR_ACCEPT -20: - ec_str = "Cannot locate accept to destroy"; - break; - case DEX_ERROR_ACCEPT -22: - ec_str = "Transaction type or version not permitted"; - break; - case DEX_ERROR_ACCEPT -23: - ec_str = "Value out of range or zero"; - break; - case DEX_ERROR_ACCEPT -205: - ec_str = "An accept from the sender to the recipient already exists"; - break; - case DEX_ERROR_ACCEPT -105: - ec_str = "Transaction fee too small"; - break; - - case PKT_ERROR_METADEX -21: - ec_str = "Ecosystem is invalid"; - break; - case PKT_ERROR_METADEX -22: - ec_str = "Transaction type or version not permitted"; - break; - case PKT_ERROR_METADEX -25: - ec_str = "Sender has insufficient balance"; - break; - case PKT_ERROR_METADEX -29: - ec_str = "Property for sale and desired property are not be equal"; - break; - case PKT_ERROR_METADEX -30: - ec_str = "Property for sale and desired property are not in the same ecosystem"; - break; - case PKT_ERROR_METADEX -31: - ec_str = "Property for sale does not exist"; - break; - case PKT_ERROR_METADEX -32: - ec_str = "Property desired does not exist"; - break; - case PKT_ERROR_METADEX -33: - ec_str = "Amount for sale out of range or zero"; - break; - case PKT_ERROR_METADEX -34: - ec_str = "Amount desired out of range or zero"; - break; - case PKT_ERROR_METADEX -35: - ec_str = "One side of the trade must be OMNI or TOMNI"; - break; - - case METADEX_ERROR -1: - ec_str = "Unknown MetaDEx (Add) error"; - break; - case METADEX_ERROR -20: - ec_str = "Unknown MetaDEx (Cancel Price) error"; - break; - case METADEX_ERROR -30: - ec_str = "Unknown MetaDEx (Cancel Pair) error"; - break; - case METADEX_ERROR -40: - ec_str = "Unknown MetaDEx (Cancel Everything) error"; - break; - case METADEX_ERROR -66: - ec_str = "Trade has a unit price of zero"; - break; - case METADEX_ERROR -70: - ec_str = "Trade already exists"; - break; - - case PKT_ERROR_SP -20: - ec_str = "Block is not in the active chain"; - break; - case PKT_ERROR_SP -21: - ec_str = "Ecosystem is invalid"; - break; - case PKT_ERROR_SP -22: - ec_str = "Transaction type or version not permitted"; - break; - case PKT_ERROR_SP -23: - ec_str = "Value out of range or zero"; - break; - case PKT_ERROR_SP -24: - ec_str = "Desired property does not exist"; - break; - case PKT_ERROR_SP -36: - ec_str = "Invalid property type"; - break; - case PKT_ERROR_SP -37: - ec_str = "Property name is empty"; - break; - case PKT_ERROR_SP -38: - ec_str = "Deadline is in the past"; - break; - case PKT_ERROR_SP -39: - ec_str = "Sender has an active crowdsale"; - break; - case PKT_ERROR_SP -40: - ec_str = "Sender has no active crowdsale"; - break; - case PKT_ERROR_SP -41: - ec_str = "Property identifier mismatch"; - break; - case PKT_ERROR_SP -42: - ec_str = "Property is not managed"; - break; - case PKT_ERROR_SP -43: - ec_str = "Sender is not the issuer of the property"; - break; - case PKT_ERROR_SP -44: - ec_str = "Attempt to grant more than the maximum number of tokens"; - break; - case PKT_ERROR_SP -50: - ec_str = "Tokens to issue and desired property are not in the same ecosystem"; - break; - - case PKT_ERROR_TOKENS -22: - ec_str = "Transaction type or version not permitted"; - break; - case PKT_ERROR_TOKENS -23: - ec_str = "Value out of range or zero"; - break; - case PKT_ERROR_TOKENS -24: - ec_str = "Property does not exist"; - break; - case PKT_ERROR_TOKENS -25: - ec_str = "Sender has insufficient balance"; - break; - case PKT_ERROR_TOKENS -39: - ec_str = "Sender has an active crowdsale"; - break; - case PKT_ERROR_TOKENS -43: - ec_str = "Sender is not the issuer of the property"; - break; - case PKT_ERROR_TOKENS -45: - ec_str = "Receiver is empty"; - break; - case PKT_ERROR_TOKENS -46: - ec_str = "Receiver has an active crowdsale"; - break; - case PKT_ERROR_TOKENS -47: - ec_str = "Freezing is not enabled for the property"; - break; - case PKT_ERROR_TOKENS -48: - ec_str = "Address is not frozen"; - break; - case PKT_ERROR_TOKENS -49: - ec_str = "Freezing is already enabled for the property"; - break; - case PKT_ERROR_TOKENS -50: - ec_str = "Address is already frozen"; - break; - - default: - ec_str = "Unknown error"; - } - - return ec_str; -} - - -#endif // ELYSIUM_ERRORS_H diff --git a/src/elysium/fees.cpp b/src/elysium/fees.cpp deleted file mode 100644 index d645e46bf6..0000000000 --- a/src/elysium/fees.cpp +++ /dev/null @@ -1,489 +0,0 @@ -/** - * @file fees.cpp - * - * This file contains code for handling Elysium fees. - */ - -#include "elysium/fees.h" - -#include "elysium/elysium.h" -#include "elysium/log.h" -#include "elysium/rules.h" -#include "elysium/sp.h" -#include "elysium/sto.h" - -#include "leveldb/db.h" - -#include "validation.h" - -#include -#include - -#include -#include - -using namespace elysium; - -std::map distributionThresholds; - -// Returns the distribution threshold for a property -int64_t CElysiumFeeCache::GetDistributionThreshold(const uint32_t &propertyId) -{ - return distributionThresholds[propertyId]; -} - -// Sets the distribution thresholds to total tokens for a property / ELYSIUM_FEE_THRESHOLD -void CElysiumFeeCache::UpdateDistributionThresholds(uint32_t propertyId) -{ - int64_t distributionThreshold = getTotalTokens(propertyId) / ELYSIUM_FEE_THRESHOLD; - if (distributionThreshold <= 0) { - // protect against zero valued thresholds for low token count properties - distributionThreshold = 1; - } - distributionThresholds[propertyId] = distributionThreshold; -} - -// Gets the current amount of the fee cache for a property -int64_t CElysiumFeeCache::GetCachedAmount(const uint32_t &propertyId) -{ - assert(pdb); - // Get the fee history, set is sorted by block so last entry is most recent - std::set sCacheHistoryItems = GetCacheHistory(propertyId); - if (!sCacheHistoryItems.empty()) { - std::set::iterator endIt = sCacheHistoryItems.end(); - --endIt; - feeCacheItem mostRecentItem = *endIt; - return mostRecentItem.second; - } else { - return 0; // property has never generated a fee - } -} - -// Zeros a property in the fee cache -void CElysiumFeeCache::ClearCache(const uint32_t &propertyId, int block) -{ - if (elysium_debug_fees) PrintToLog("ClearCache starting (block %d, property ID %d)...\n", block, propertyId); - const std::string key = strprintf("%010d", propertyId); - std::set sCacheHistoryItems = GetCacheHistory(propertyId); - if (elysium_debug_fees) PrintToLog(" Iterating cache history (%d items)...\n",sCacheHistoryItems.size()); - std::string newValue; - if (!sCacheHistoryItems.empty()) { - for (std::set::iterator it = sCacheHistoryItems.begin(); it != sCacheHistoryItems.end(); it++) { - feeCacheItem tempItem = *it; - if (tempItem.first == block) continue; - if (!newValue.empty()) newValue += ","; - newValue += strprintf("%d:%d", tempItem.first, tempItem.second); - if (elysium_debug_fees) PrintToLog(" Readding entry: block %d amount %d\n", tempItem.first, tempItem.second); - } - if (!newValue.empty()) newValue += ","; - } - if (elysium_debug_fees) PrintToLog(" Adding zero valued entry: block %d\n", block); - newValue += strprintf("%d:%d", block, 0); - leveldb::Status status = pdb->Put(writeoptions, key, newValue); - assert(status.ok()); - ++nWritten; - - PruneCache(propertyId, block); - - if (elysium_debug_fees) PrintToLog("Cleared cache for property %d block %d [%s]\n", propertyId, block, status.ToString()); -} - -// Adds a fee to the cache (eg on a completed trade) -void CElysiumFeeCache::AddFee(const uint32_t &propertyId, int block, const int64_t &amount) -{ - if (elysium_debug_fees) PrintToLog("Starting AddFee for prop %d (block %d amount %d)...\n", propertyId, block, amount); - - // Get current cached fee - int64_t currentCachedAmount = GetCachedAmount(propertyId); - if (elysium_debug_fees) PrintToLog(" Current cached amount %d\n", currentCachedAmount); - - // Add new fee and rewrite record - if ((currentCachedAmount > 0) && (amount > std::numeric_limits::max() - currentCachedAmount)) { - // overflow - there is no way the fee cache should exceed the maximum possible number of tokens, not safe to continue - const std::string& msg = strprintf("Shutting down due to fee cache overflow (block %d property %d current %d amount %d)\n", block, propertyId, currentCachedAmount, amount); - PrintToLog(msg); - if (!GetBoolArg("-overrideforcedshutdown", false)) { - boost::filesystem::path persistPath = GetDataDir() / "MP_persist"; - if (boost::filesystem::exists(persistPath)) boost::filesystem::remove_all(persistPath); // prevent the node being restarted without a reparse after forced shutdown - AbortNode(msg, msg); - } - } - int64_t newCachedAmount = currentCachedAmount + amount; - - if (elysium_debug_fees) PrintToLog(" New cached amount %d\n", newCachedAmount); - const std::string key = strprintf("%010d", propertyId); - std::set sCacheHistoryItems = GetCacheHistory(propertyId); - if (elysium_debug_fees) PrintToLog(" Iterating cache history (%d items)...\n",sCacheHistoryItems.size()); - std::string newValue; - if (!sCacheHistoryItems.empty()) { - for (std::set::iterator it = sCacheHistoryItems.begin(); it != sCacheHistoryItems.end(); it++) { - feeCacheItem tempItem = *it; - if (tempItem.first == block) continue; // this is an older entry for the same block, discard it - if (!newValue.empty()) newValue += ","; - newValue += strprintf("%d:%d", tempItem.first, tempItem.second); - if (elysium_debug_fees) PrintToLog(" Readding entry: block %d amount %d\n", tempItem.first, tempItem.second); - } - if (!newValue.empty()) newValue += ","; - } - if (elysium_debug_fees) PrintToLog(" Adding requested entry: block %d new amount %d\n", block, newCachedAmount); - newValue += strprintf("%d:%d", block, newCachedAmount); - leveldb::Status status = pdb->Put(writeoptions, key, newValue); - assert(status.ok()); - ++nWritten; - if (elysium_debug_fees) PrintToLog("AddFee completed for property %d (new=%s [%s])\n", propertyId, newValue, status.ToString()); - - // Call for pruning (we only prune when we update a record) - PruneCache(propertyId, block); - - // Call for cache evaluation (we only need to do this each time a fee cache is increased) - EvalCache(propertyId, block); - - return; -} - -// Rolls back the cache to an earlier state (eg in event of a reorg) - block is *inclusive* (ie entries=block will get deleted) -void CElysiumFeeCache::RollBackCache(int block) -{ - assert(pdb); - for (uint8_t ecosystem = 1; ecosystem <= 2; ecosystem++) { - uint32_t startPropertyId = (ecosystem == 1) ? 1 : TEST_ECO_PROPERTY_1; - for (uint32_t propertyId = startPropertyId; propertyId < elysium::_my_sps->peekNextSPID(ecosystem); propertyId++) { - const std::string key = strprintf("%010d", propertyId); - std::set sCacheHistoryItems = GetCacheHistory(propertyId); - if (!sCacheHistoryItems.empty()) { - std::set::iterator mostRecentIt = sCacheHistoryItems.end(); - std::string newValue; - --mostRecentIt; - feeCacheItem mostRecentItem = *mostRecentIt; - if (mostRecentItem.first < block) continue; // all entries are unaffected by this rollback, nothing to do - for (std::set::iterator it = sCacheHistoryItems.begin(); it != sCacheHistoryItems.end(); it++) { - feeCacheItem tempItem = *it; - if (tempItem.first >= block) continue; // discard this entry - if (!newValue.empty()) newValue += ","; - newValue += strprintf("%d:%d", tempItem.first, tempItem.second); - } - leveldb::Status status = pdb->Put(writeoptions, key, newValue); - assert(status.ok()); - PrintToLog("Rolling back fee cache for property %d, new=%s [%s])\n", propertyId, newValue, status.ToString()); - } - } - } -} - -// Evaluates fee caches for the property against threshold and executes distribution if threshold met -void CElysiumFeeCache::EvalCache(const uint32_t &propertyId, int block) -{ - if (GetCachedAmount(propertyId) >= distributionThresholds[propertyId]) { - DistributeCache(propertyId, block); - } -} - -// Performs distribution of fees -void CElysiumFeeCache::DistributeCache(const uint32_t &propertyId, int block) -{ - LOCK(cs_main); - - int64_t cachedAmount = GetCachedAmount(propertyId); - - if (cachedAmount == 0) { - PrintToLog("Aborting fee distribution for property %d, the fee cache is empty!\n", propertyId); - } - - OwnerAddrType receiversSet; - if (isTestEcosystemProperty(propertyId)) { - receiversSet = STO_GetReceivers("FEEDISTRIBUTION", ELYSIUM_PROPERTY_TELYSIUM, cachedAmount); - } else { - receiversSet = STO_GetReceivers("FEEDISTRIBUTION", ELYSIUM_PROPERTY_ELYSIUM, cachedAmount); - } - - uint64_t numberOfReceivers = receiversSet.size(); // there will always be addresses holding ELYSIUM, so no need to check size>0 - PrintToLog("Starting fee distribution for property %d to %d recipients...\n", propertyId, numberOfReceivers); - - int64_t sent_so_far = 0; - std::set historyItems; - for (OwnerAddrType::reverse_iterator it = receiversSet.rbegin(); it != receiversSet.rend(); ++it) { - const std::string& address = it->second; - int64_t will_really_receive = it->first; - sent_so_far += will_really_receive; - if (elysium_debug_fees) PrintToLog(" %s receives %d (running total %d of %d)\n", address, will_really_receive, sent_so_far, cachedAmount); - assert(update_tally_map(address, propertyId, will_really_receive, BALANCE)); - feeHistoryItem recipient(address, will_really_receive); - historyItems.insert(recipient); - } - - PrintToLog("Fee distribution completed, distributed %d out of %d\n", sent_so_far, cachedAmount); - - // store the fee distribution - p_feehistory->RecordFeeDistribution(propertyId, block, sent_so_far, historyItems); - - // final check to ensure the entire fee cache was distributed, then empty the cache - assert(sent_so_far == cachedAmount); - ClearCache(propertyId, block); -} - -// Prunes entries over MAX_STATE_HISTORY blocks old from the entry for a property -void CElysiumFeeCache::PruneCache(const uint32_t &propertyId, int block) -{ - if (elysium_debug_fees) PrintToLog("Starting PruneCache for prop %d block %d...\n", propertyId, block); - assert(pdb); - - int pruneBlock = block - MAX_STATE_HISTORY; - if (elysium_debug_fees) PrintToLog("Removing entries prior to block %d...\n", pruneBlock); - const std::string key = strprintf("%010d", propertyId); - std::set sCacheHistoryItems = GetCacheHistory(propertyId); - if (elysium_debug_fees) PrintToLog(" Iterating cache history (%d items)...\n",sCacheHistoryItems.size()); - if (!sCacheHistoryItems.empty()) { - std::set::iterator startIt = sCacheHistoryItems.begin(); - feeCacheItem firstItem = *startIt; - if (firstItem.first >= pruneBlock) { - if (elysium_debug_fees) PrintToLog("Endingg PruneCache - no matured entries found.\n"); - return; // all entries are above supplied block value, nothing to do - } - std::string newValue; - for (std::set::iterator it = sCacheHistoryItems.begin(); it != sCacheHistoryItems.end(); it++) { - feeCacheItem tempItem = *it; - if (tempItem.first < pruneBlock) { - if (elysium_debug_fees) { - PrintToLog(" Skipping matured entry: block %d amount %d\n", tempItem.first, tempItem.second); - continue; // discard this entry - } - } - if (!newValue.empty()) newValue += ","; - newValue += strprintf("%d:%d", tempItem.first, tempItem.second); - if (elysium_debug_fees) PrintToLog(" Readding immature entry: block %d amount %d\n", tempItem.first, tempItem.second); - } - // make sure the pruned cache isn't completely empty, if it is, prune down to just the most recent entry - if (newValue.empty()) { - std::set::iterator mostRecentIt = sCacheHistoryItems.end(); - --mostRecentIt; - feeCacheItem mostRecentItem = *mostRecentIt; - newValue = strprintf("%d:%d", mostRecentItem.first, mostRecentItem.second); - if (elysium_debug_fees) PrintToLog(" All entries matured and pruned - readding most recent entry: block %d amount %d\n", mostRecentItem.first, mostRecentItem.second); - } - leveldb::Status status = pdb->Put(writeoptions, key, newValue); - assert(status.ok()); - if (elysium_debug_fees) PrintToLog("PruneCache completed for property %d (new=%s [%s])\n", propertyId, newValue, status.ToString()); - } else { - return; // nothing to do - } -} - -// Show Fee Cache DB statistics -void CElysiumFeeCache::printStats() -{ - PrintToLog("CElysiumFeeCache stats: nWritten= %d , nRead= %d\n", nWritten, nRead); -} - -// Show Fee Cache DB records -void CElysiumFeeCache::printAll() -{ - int count = 0; - leveldb::Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) { - ++count; - PrintToLog("entry #%8d= %s:%s\n", count, it->key().ToString(), it->value().ToString()); - } - delete it; -} - -// Return a set containing fee cache history items -std::set CElysiumFeeCache::GetCacheHistory(const uint32_t &propertyId) -{ - assert(pdb); - - const std::string key = strprintf("%010d", propertyId); - - std::set sCacheHistoryItems; - std::string strValue; - leveldb::Status status = pdb->Get(readoptions, key, &strValue); - if (status.IsNotFound()) { - return sCacheHistoryItems; // no cache, return empty set - } - assert(status.ok()); - std::vector vCacheHistoryItems; - boost::split(vCacheHistoryItems, strValue, boost::is_any_of(","), boost::token_compress_on); - for (std::vector::iterator it = vCacheHistoryItems.begin(); it != vCacheHistoryItems.end(); ++it) { - std::vector vCacheHistoryItem; - boost::split(vCacheHistoryItem, *it, boost::is_any_of(":"), boost::token_compress_on); - if (2 != vCacheHistoryItem.size()) { - PrintToLog("ERROR: vCacheHistoryItem has unexpected number of elements: %d (raw %s)!\n", vCacheHistoryItem.size(), *it); - printAll(); - continue; - } - int64_t cacheItemBlock = boost::lexical_cast(vCacheHistoryItem[0]); - int64_t cacheItemAmount = boost::lexical_cast(vCacheHistoryItem[1]); - sCacheHistoryItems.insert(std::make_pair(cacheItemBlock, cacheItemAmount)); - } - - return sCacheHistoryItems; -} - -// Show Fee History DB statistics -void CElysiumFeeHistory::printStats() -{ - PrintToLog("CElysiumFeeHistory stats: nWritten= %d , nRead= %d\n", nWritten, nRead); -} - -// Show Fee History DB records -void CElysiumFeeHistory::printAll() -{ - int count = 0; - leveldb::Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) { - ++count; - PrintToLog("entry #%8d= %s-%s\n", count, it->key().ToString(), it->value().ToString()); - PrintToLog("entry #%8d= %s-%s\n", count, it->key().ToString(), it->value().ToString()); - } - delete it; -} - -// Count Fee History DB records -int CElysiumFeeHistory::CountRecords() -{ - // No faster way to count than to iterate - "There is no way to implement Count more efficiently inside leveldb than outside." - int count = 0; - leveldb::Iterator* it = NewIterator(); - for(it->SeekToFirst(); it->Valid(); it->Next()) { - ++count; - } - delete it; - return count; -} - -// Roll back history in event of reorg, block is inclusive -void CElysiumFeeHistory::RollBackHistory(int block) -{ - assert(pdb); - - std::set sDistributions; - leveldb::Iterator* it = NewIterator(); - for (it->SeekToFirst(); it->Valid(); it->Next()) { - std::string strValue = it->value().ToString(); - std::string strKey = it->key().ToString(); - std::vector vFeeHistoryDetail; - boost::split(vFeeHistoryDetail, strValue, boost::is_any_of(":"), boost::token_compress_on); - if (4 != vFeeHistoryDetail.size()) { - PrintToLog("ERROR: vFeeHistoryDetail has unexpected number of elements: %d !\n", vFeeHistoryDetail.size()); - continue; // bad data - } - int feeBlock = boost::lexical_cast(vFeeHistoryDetail[0]); - if (feeBlock >= block) { - PrintToLog("%s() deleting from fee history DB: %s %s\n", __FUNCTION__, strKey, strValue); - pdb->Delete(writeoptions, strKey); - } - } - delete it; -} - -// Retrieve fee distributions for a property -std::set CElysiumFeeHistory::GetDistributionsForProperty(const uint32_t &propertyId) -{ - assert(pdb); - - std::set sDistributions; - leveldb::Iterator* it = NewIterator(); - for (it->SeekToFirst(); it->Valid(); it->Next()) { - std::string strValue = it->value().ToString(); - std::vector vFeeHistoryDetail; - boost::split(vFeeHistoryDetail, strValue, boost::is_any_of(":"), boost::token_compress_on); - if (4 != vFeeHistoryDetail.size()) { - PrintToLog("ERROR: vFeeHistoryDetail has unexpected number of elements: %d !\n", vFeeHistoryDetail.size()); - printAll(); - continue; // bad data - } - uint32_t prop = boost::lexical_cast(vFeeHistoryDetail[1]); - if (prop == propertyId) { - std::string key = it->key().ToString(); - int id = boost::lexical_cast(key); - sDistributions.insert(id); - } - } - delete it; - return sDistributions; -} - -// Populate data about a fee distribution -bool CElysiumFeeHistory::GetDistributionData(int id, uint32_t *propertyId, int *block, int64_t *total) -{ - assert(pdb); - - const std::string key = strprintf("%d", id); - std::string strValue; - leveldb::Status status = pdb->Get(readoptions, key, &strValue); - if (status.IsNotFound()) { - return false; // fee distribution not found - } - assert(status.ok()); - std::vector vFeeHistoryDetail; - boost::split(vFeeHistoryDetail, strValue, boost::is_any_of(":"), boost::token_compress_on); - if (4 != vFeeHistoryDetail.size()) { - PrintToLog("ERROR: vFeeHistoryDetail has unexpected number of elements: %d !\n", vFeeHistoryDetail.size()); - printAll(); - return false; // bad data - } - *block = boost::lexical_cast(vFeeHistoryDetail[0]); - *propertyId = boost::lexical_cast(vFeeHistoryDetail[1]); - *total = boost::lexical_cast(vFeeHistoryDetail[2]); - return true; -} - -// Retrieve the recipients for a fee distribution -std::set CElysiumFeeHistory::GetFeeDistribution(int id) -{ - assert(pdb); - - const std::string key = strprintf("%d", id); - std::set sFeeHistoryItems; - std::string strValue; - leveldb::Status status = pdb->Get(readoptions, key, &strValue); - if (status.IsNotFound()) { - return sFeeHistoryItems; // fee distribution not found, return empty set - } - assert(status.ok()); - std::vector vFeeHistoryDetail; - boost::split(vFeeHistoryDetail, strValue, boost::is_any_of(":"), boost::token_compress_on); - if (4 != vFeeHistoryDetail.size()) { - PrintToLog("ERROR: vFeeHistoryDetail has unexpected number of elements: %d !\n", vFeeHistoryDetail.size()); - printAll(); - return sFeeHistoryItems; // bad data, return empty set - } - std::vector vFeeHistoryItems; - boost::split(vFeeHistoryItems, vFeeHistoryDetail[3], boost::is_any_of(","), boost::token_compress_on); - for (std::vector::iterator it = vFeeHistoryItems.begin(); it != vFeeHistoryItems.end(); ++it) { - std::vector vFeeHistoryItem; - boost::split(vFeeHistoryItem, *it, boost::is_any_of("="), boost::token_compress_on); - if (2 != vFeeHistoryItem.size()) { - PrintToLog("ERROR: vFeeHistoryItem has unexpected number of elements: %d (raw %s)!\n", vFeeHistoryItem.size(), *it); - printAll(); - continue; - } - int64_t feeHistoryItemAmount = boost::lexical_cast(vFeeHistoryItem[1]); - sFeeHistoryItems.insert(std::make_pair(vFeeHistoryItem[0], feeHistoryItemAmount)); - } - - return sFeeHistoryItems; -} - -// Record a fee distribution -void CElysiumFeeHistory::RecordFeeDistribution(const uint32_t &propertyId, int block, int64_t total, std::set feeRecipients) -{ - assert(pdb); - - int count = CountRecords() + 1; - std::string key = strprintf("%d", count); - std::string feeRecipientsStr; - - if (!feeRecipients.empty()) { - for (std::set::iterator it = feeRecipients.begin(); it != feeRecipients.end(); it++) { - feeHistoryItem tempRecipient = *it; - feeRecipientsStr += strprintf("%s=%d,", tempRecipient.first, tempRecipient.second); - } - if (feeRecipientsStr.size() > 0) { - feeRecipientsStr.resize(feeRecipientsStr.size() - 1); - } - } - - std::string value = strprintf("%d:%d:%d:%s", block, propertyId, total, feeRecipientsStr); - leveldb::Status status = pdb->Put(writeoptions, key, value); - if (elysium_debug_fees) PrintToLog("Added fee distribution to feeCacheHistory - key=%s value=%s [%s]\n", key, value, status.ToString()); -} diff --git a/src/elysium/fees.h b/src/elysium/fees.h deleted file mode 100644 index ef83e8240b..0000000000 --- a/src/elysium/fees.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef ELYSIUM_FEES_H -#define ELYSIUM_FEES_H - -#include "leveldb/db.h" - -#include "elysium/log.h" -#include "elysium/persistence.h" - -#include -#include -#include - -typedef std::pair feeCacheItem; -typedef std::pair feeHistoryItem; - -/** LevelDB based storage for the MetaDEx fee cache - */ -class CElysiumFeeCache : public CDBBase -{ -public: - CElysiumFeeCache(const boost::filesystem::path& path, bool fWipe) - { - leveldb::Status status = Open(path, fWipe); - PrintToLog("Loading fee cache database: %s\n", status.ToString()); - } - - virtual ~CElysiumFeeCache() - { - if (elysium_debug_fees) PrintToLog("CElysiumFeeCache closed\n"); - } - - // Show Fee Cache DB statistics - void printStats(); - // Show Fee Cache DB records - void printAll(); - - // Sets the distribution thresholds to total tokens for a property / ELYSIUM_FEE_THRESHOLD - void UpdateDistributionThresholds(uint32_t propertyId); - // Returns the distribution threshold for a property - int64_t GetDistributionThreshold(const uint32_t &propertyId); - // Return a set containing fee cache history items - std::set GetCacheHistory(const uint32_t &propertyId); - // Gets the current amount of the fee cache for a property - int64_t GetCachedAmount(const uint32_t &propertyId); - // Prunes entries over 50 blocks old from the entry for a property - void PruneCache(const uint32_t &propertyId, int block); - // Rolls back the cache to an earlier state (eg in event of a reorg) - block is *inclusive* (ie entries=block will get deleted) - void RollBackCache(int block); - // Zeros a property in the fee cache - void ClearCache(const uint32_t &propertyId, int block); - // Adds a fee to the cache (eg on a completed trade) - void AddFee(const uint32_t &propertyId, int block, const int64_t &amount); - // Evaluates fee caches for all properties against threshold and executes distribution if threshold met - void EvalCache(const uint32_t &propertyId, int block); - // Performs distribution of fees - void DistributeCache(const uint32_t &propertyId, int block); -}; - -/** LevelDB based storage for the MetaDEx fee distributions - */ -class CElysiumFeeHistory : public CDBBase -{ -public: - CElysiumFeeHistory(const boost::filesystem::path& path, bool fWipe) - { - leveldb::Status status = Open(path, fWipe); - PrintToLog("Loading fee history database: %s\n", status.ToString()); - } - - virtual ~CElysiumFeeHistory() - { - if (elysium_debug_fees) PrintToLog("CElysiumFeeHistory closed\n"); - } - - // Show Fee History DB statistics - void printStats(); - // Show Fee History DB records - void printAll(); - - // Roll back history in event of reorg - void RollBackHistory(int block); - // Count Fee History DB records - int CountRecords(); - // Record a fee distribution - void RecordFeeDistribution(const uint32_t &propertyId, int block, int64_t total, std::set feeRecipients); - // Retrieve the recipients for a fee distribution - std::set GetFeeDistribution(int id); - // Retrieve fee distributions for a property - std::set GetDistributionsForProperty(const uint32_t &propertyId); - // Populate data about a fee distribution - bool GetDistributionData(int id, uint32_t *propertyId, int *block, int64_t *total); - // Retrieve fee distribution receipts for an address -}; - -namespace elysium -{ - extern CElysiumFeeCache *p_feecache; - extern CElysiumFeeHistory *p_feehistory; -} - -#endif // ELYSIUM_FEES_H diff --git a/src/elysium/fetchwallettx.cpp b/src/elysium/fetchwallettx.cpp deleted file mode 100644 index 61a59d586d..0000000000 --- a/src/elysium/fetchwallettx.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/** - * @file fetchwallettx.cpp - * - * The fetch functions provide a sorted list of transaction hashes ordered by block, - * position in block and position in wallet including STO receipts. - */ - -#include "elysium/fetchwallettx.h" - -#include "elysium/log.h" -#include "elysium/elysium.h" -#include "elysium/pending.h" -#include "elysium/utilsbitcoin.h" - -#include "init.h" -#include "validation.h" -#include "sync.h" -#include "tinyformat.h" -#include "txdb.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace elysium -{ -/** - * Gets the byte offset of a transaction from the transaction index. - */ -unsigned int GetTransactionByteOffset(const uint256& txid) -{ - LOCK(cs_main); - - CDiskTxPos position; - if (pblocktree->ReadTxIndex(txid, position)) { - return position.nTxOffset; - } - - return 0; -} - -/** - * Returns an ordered list of Elysium transactions including STO receipts that are relevant to the wallet. - * - * Ignores order in the wallet (which can be skewed by watch addresses) and utilizes block height and position within block. - */ -std::map FetchWalletElysiumTransactions(unsigned int count, int startBlock, int endBlock) -{ - std::map mapResponse; -#ifdef ENABLE_WALLET - if (pwalletMain == NULL) { - return mapResponse; - } - std::set seenHashes; - std::list acentries; - CWallet::TxItems txOrdered; - { - LOCK(pwalletMain->cs_wallet); - txOrdered = pwalletMain->wtxOrdered; - } - // Iterate backwards through wallet transactions until we have count items to return: - for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { - const CWalletTx* pwtx = it->second.first; - if (pwtx == NULL) continue; - const uint256& txHash = pwtx->GetHash(); - { - LOCK(cs_main); - if (!p_txlistdb->exists(txHash)) continue; - } - const uint256& blockHash = pwtx->hashBlock; - if (blockHash.IsNull() || (NULL == GetBlockIndex(blockHash))) continue; - const CBlockIndex* pBlockIndex = GetBlockIndex(blockHash); - if (NULL == pBlockIndex) continue; - int blockHeight = pBlockIndex->nHeight; - if (blockHeight < startBlock || blockHeight > endBlock) continue; - int blockPosition = GetTransactionByteOffset(txHash); - std::string sortKey = strprintf("%06d%010d", blockHeight, blockPosition); - mapResponse.insert(std::make_pair(sortKey, txHash)); - seenHashes.insert(txHash); - if (mapResponse.size() >= count) break; - } - - // Insert STO receipts - receiving an STO has no inbound transaction to the wallet, so we will insert these manually into the response - std::string mySTOReceipts; - { - LOCK(cs_main); - mySTOReceipts = s_stolistdb->getMySTOReceipts(""); - } - std::vector vecReceipts; - if (!mySTOReceipts.empty()) { - boost::split(vecReceipts, mySTOReceipts, boost::is_any_of(","), boost::token_compress_on); - } - for (size_t i = 0; i < vecReceipts.size(); i++) { - std::vector svstr; - boost::split(svstr, vecReceipts[i], boost::is_any_of(":"), boost::token_compress_on); - if (svstr.size() != 4) { - PrintToLog("STODB Error - number of tokens is not as expected (%s)\n", vecReceipts[i]); - continue; - } - int blockHeight = atoi(svstr[1]); - if (blockHeight < startBlock || blockHeight > endBlock) continue; - uint256 txHash = uint256S(svstr[0]); - if (seenHashes.find(txHash) != seenHashes.end()) continue; // an STO may already be in the wallet if we sent it - int blockPosition = GetTransactionByteOffset(txHash); - std::string sortKey = strprintf("%06d%010d", blockHeight, blockPosition); - mapResponse.insert(std::make_pair(sortKey, txHash)); - } - - // Insert pending transactions (sets block as 999999 and position as wallet position) - LOCK(cs_main); - - for (PendingMap::const_iterator it = my_pending.begin(); it != my_pending.end(); ++it) { - const uint256& txHash = it->first; - int blockHeight = 999999; - if (blockHeight < startBlock || blockHeight > endBlock) continue; - int blockPosition = 0; - { - LOCK(pwalletMain->cs_wallet); - std::map::const_iterator walletIt = pwalletMain->mapWallet.find(txHash); - if (walletIt != pwalletMain->mapWallet.end()) { - const CWalletTx& wtx = walletIt->second; - blockPosition = wtx.nOrderPos; - } - } - std::string sortKey = strprintf("%06d%010d", blockHeight, blockPosition); - mapResponse.insert(std::make_pair(sortKey, txHash)); - } -#endif - return mapResponse; -} - - -} // namespace elysium diff --git a/src/elysium/fetchwallettx.h b/src/elysium/fetchwallettx.h deleted file mode 100644 index f41d55c842..0000000000 --- a/src/elysium/fetchwallettx.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ELYSIUM_FETCHWALLETTX_H -#define ELYSIUM_FETCHWALLETTX_H - -class uint256; - -#include -#include - -namespace elysium -{ -/** Gets the byte offset of a transaction from the transaction index. */ -unsigned int GetTransactionByteOffset(const uint256& txid); - -/** Returns an ordered list of Elysium transactions that are relevant to the wallet. */ -std::map FetchWalletElysiumTransactions(unsigned int count, int startBlock = 0, int endBlock = 999999); -} - -#endif // ELYSIUM_FETCHWALLETTX_H diff --git a/src/elysium/log.cpp b/src/elysium/log.cpp deleted file mode 100644 index 8460af2cc1..0000000000 --- a/src/elysium/log.cpp +++ /dev/null @@ -1,339 +0,0 @@ -#include "elysium/log.h" - -#include "chainparamsbase.h" -#include "util.h" -#include "utiltime.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -// Default log files -const std::string LOG_FILENAME = "exodus.log"; - -// Options -static const long LOG_BUFFERSIZE = 8000000; // 8 MB -static const long LOG_SHRINKSIZE = 50000000; // 50 MB - -// Debug flags -bool elysium_debug_parser_data = 0; -bool elysium_debug_parser_readonly = 0; -//! Print information to potential DEx payments and outputs -bool elysium_debug_parser_dex = 1; -bool elysium_debug_parser = 0; -bool elysium_debug_verbose = 0; -bool elysium_debug_verbose2 = 0; -bool elysium_debug_verbose3 = 0; -bool elysium_debug_vin = 0; -bool elysium_debug_script = 0; -bool elysium_debug_dex = 1; -bool elysium_debug_send = 1; -bool elysium_debug_tokens = 0; -//! Print information about payloads with non-sequential sequence number -bool elysium_debug_spec = 0; -bool elysium_debug_ely = 0; -bool elysium_debug_tally = 1; -bool elysium_debug_sp = 1; -bool elysium_debug_sto = 1; -bool elysium_debug_txdb = 0; -bool elysium_debug_tradedb = 1; -bool elysium_debug_persistence = 0; -bool elysium_debug_ui = 0; -bool elysium_debug_pending = 1; -bool elysium_debug_metadex1 = 0; -bool elysium_debug_metadex2 = 0; -//! Print orderbook before and after each trade -bool elysium_debug_metadex3 = 0; -//! Print transaction fields, when interpreting packets -bool elysium_debug_packets = 1; -//! Print transaction fields, when interpreting packets (in RPC mode) -bool elysium_debug_packets_readonly = 0; -bool elysium_debug_walletcache = 0; -//! Print each line added to consensus hash -bool elysium_debug_consensus_hash = 0; -//! Print consensus hashes for each block when parsing -bool elysium_debug_consensus_hash_every_block = 0; -//! Print extra info on alert processing -bool elysium_debug_alerts = 1; -//! Print consensus hashes for each transaction when parsing -bool elysium_debug_consensus_hash_every_transaction = 0; -//! Debug fees -bool elysium_debug_fees = 1; - -/** - * LogPrintf() has been broken a couple of times now - * by well-meaning people adding mutexes in the most straightforward way. - * It breaks because it may be called by global destructors during shutdown. - * Since the order of destruction of static/global objects is undefined, - * defining a mutex as a global object doesn't work (the mutex gets - * destroyed, and then some later destructor calls OutputDebugStringF, - * maybe indirectly, and you get a core dump at shutdown trying to lock - * the mutex). - */ -static boost::once_flag debugLogInitFlag = BOOST_ONCE_INIT; -/** - * We use boost::call_once() to make sure these are initialized - * in a thread-safe manner the first time called: - */ -static FILE* fileout = NULL; -static boost::mutex* mutexDebugLog = NULL; -/** Flag to indicate, whether the Elysium log file should be reopened. */ -extern std::atomic fReopenElysiumLog; - -/** - * @return The current timestamp in the format: 2009-01-03 18:15:05 - */ -static std::string GetTimestamp() -{ - return DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()); -} - -/** - * Prints to the standard output, usually the console. - * - * The configuration option "-logtimestamps" can be used to indicate, whether - * the message should be prepended with a timestamp. - * - * @param str[in] The message to print - * @return The total number of characters written - */ -static int ConsolePrint(const std::string& str) -{ - int ret = 0; // Number of characters written - static bool fStartedNewLine = true; - - if (fLogTimestamps && fStartedNewLine) { - ret = fprintf(stdout, "%s %s", GetTimestamp().c_str(), str.c_str()); - } else { - ret = fwrite(str.data(), 1, str.size(), stdout); - } - if (!str.empty() && str[str.size()-1] == '\n') { - fStartedNewLine = true; - } else { - fStartedNewLine = false; - } - fflush(stdout); - - return ret; -} - -/** - * Returns path for debug log file. - * - * The log file can be specified via startup option "--elysiumlogfile=/path/to/exodus.log", - * and if none is provided, then the client's datadir is used as default location. - */ -static boost::filesystem::path GetLogPath() -{ - boost::filesystem::path pathLogFile; - std::string strLogPath = GetArg("-elysiumlogfile", ""); - - if (!strLogPath.empty()) { - pathLogFile = boost::filesystem::path(strLogPath); - TryCreateDirectory(pathLogFile.parent_path()); - } else { - pathLogFile = GetDataDir() / LOG_FILENAME; - } - - return pathLogFile; -} - -/** - * Opens debug log file. - */ -static void DebugLogInit() -{ - assert(fileout == NULL); - assert(mutexDebugLog == NULL); - - boost::filesystem::path pathDebug = GetLogPath(); - fileout = fopen(pathDebug.string().c_str(), "a"); - - if (fileout) { - setbuf(fileout, NULL); // Unbuffered - } else { - ConsolePrint(tfm::format("Failed to open debug log file: %s\n", pathDebug.string())); - } - - mutexDebugLog = new boost::mutex(); -} - -/** - * Prints to log file. - * - * The configuration options "-logtimestamps" can be used to indicate, whether - * the message to log should be prepended with a timestamp. - * - * If "-printtoconsole" is enabled, then the message is written to the standard - * output, usually the console, instead of a log file. - * - * @param str[in] The message to log - * @return The total number of characters written - */ -int LogFilePrint(const std::string& str) -{ - int ret = 0; // Number of characters written - if (fPrintToConsole) { - // Print to console - ret = ConsolePrint(str); - } - else if (fPrintToDebugLog && AreBaseParamsConfigured()) { - static bool fStartedNewLine = true; - boost::call_once(&DebugLogInit, debugLogInitFlag); - - if (fileout == NULL) { - return ret; - } - boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); - - // Reopen the log file, if requested - if (fReopenElysiumLog) { - fReopenElysiumLog = false; - boost::filesystem::path pathDebug = GetLogPath(); - if (freopen(pathDebug.string().c_str(), "a", fileout) != NULL) { - setbuf(fileout, NULL); // Unbuffered - } - } - - // Printing log timestamps can be useful for profiling - if (fLogTimestamps && fStartedNewLine) { - ret += fprintf(fileout, "%s ", GetTimestamp().c_str()); - } - if (!str.empty() && str[str.size()-1] == '\n') { - fStartedNewLine = true; - } else { - fStartedNewLine = false; - } - ret += fwrite(str.data(), 1, str.size(), fileout); - } - - return ret; -} - -/** - * Determine whether to override compiled debug levels via enumerating startup option --elysiumdebug. - * - * Example usage (granular categories) : --elysiumdebug=parser --elysiumdebug=metadex1 --elysiumdebug=ui - * Example usage (enable all categories) : --elysiumdebug=all - * Example usage (disable all debugging) : --elysiumdebug=none - * Example usage (disable all except XYZ) : --elysiumdebug=none --omnidebug=parser --elysiumdebug=sto - */ -void InitDebugLogLevels() -{ - if (!IsArgSet("-elysiumdebug")) { - return; - } - - const std::vector& debugLevels = mapMultiArgs.at("-elysiumdebug"); - - for (std::vector::const_iterator it = debugLevels.begin(); it != debugLevels.end(); ++it) { - if (*it == "parser_data") elysium_debug_parser_data = true; - if (*it == "parser_readonly") elysium_debug_parser_readonly = true; - if (*it == "parser_dex") elysium_debug_parser_dex = true; - if (*it == "parser") elysium_debug_parser = true; - if (*it == "verbose") elysium_debug_verbose = true; - if (*it == "verbose2") elysium_debug_verbose2 = true; - if (*it == "verbose3") elysium_debug_verbose3 = true; - if (*it == "vin") elysium_debug_vin = true; - if (*it == "script") elysium_debug_script = true; - if (*it == "dex") elysium_debug_dex = true; - if (*it == "send") elysium_debug_send = true; - if (*it == "tokens") elysium_debug_tokens = true; - if (*it == "spec") elysium_debug_spec = true; - if (*it == "ely") elysium_debug_ely = true; - if (*it == "tally") elysium_debug_tally = true; - if (*it == "sp") elysium_debug_sp = true; - if (*it == "sto") elysium_debug_sto = true; - if (*it == "txdb") elysium_debug_txdb = true; - if (*it == "tradedb") elysium_debug_tradedb = true; - if (*it == "persistence") elysium_debug_persistence = true; - if (*it == "ui") elysium_debug_ui = true; - if (*it == "pending") elysium_debug_pending = true; - if (*it == "metadex1") elysium_debug_metadex1 = true; - if (*it == "metadex2") elysium_debug_metadex2 = true; - if (*it == "metadex3") elysium_debug_metadex3 = true; - if (*it == "packets") elysium_debug_packets = true; - if (*it == "packets_readonly") elysium_debug_packets_readonly = true; - if (*it == "walletcache") elysium_debug_walletcache = true; - if (*it == "consensus_hash") elysium_debug_consensus_hash = true; - if (*it == "consensus_hash_every_block") elysium_debug_consensus_hash_every_block = true; - if (*it == "alerts") elysium_debug_alerts = true; - if (*it == "consensus_hash_every_transaction") elysium_debug_consensus_hash_every_transaction = true; - if (*it == "fees") elysium_debug_fees = true; - if (*it == "none" || *it == "all") { - bool allDebugState = false; - if (*it == "all") allDebugState = true; - elysium_debug_parser_data = allDebugState; - elysium_debug_parser_readonly = allDebugState; - elysium_debug_parser_dex = allDebugState; - elysium_debug_parser = allDebugState; - elysium_debug_verbose = allDebugState; - elysium_debug_verbose2 = allDebugState; - elysium_debug_verbose3 = allDebugState; - elysium_debug_vin = allDebugState; - elysium_debug_script = allDebugState; - elysium_debug_dex = allDebugState; - elysium_debug_send = allDebugState; - elysium_debug_tokens = allDebugState; - elysium_debug_spec = allDebugState; - elysium_debug_ely = allDebugState; - elysium_debug_tally = allDebugState; - elysium_debug_sp = allDebugState; - elysium_debug_sto = allDebugState; - elysium_debug_txdb = allDebugState; - elysium_debug_tradedb = allDebugState; - elysium_debug_persistence = allDebugState; - elysium_debug_ui = allDebugState; - elysium_debug_pending = allDebugState; - elysium_debug_metadex1 = allDebugState; - elysium_debug_metadex2 = allDebugState; - elysium_debug_metadex3 = allDebugState; - elysium_debug_packets = allDebugState; - elysium_debug_packets_readonly = allDebugState; - elysium_debug_walletcache = allDebugState; - elysium_debug_consensus_hash = allDebugState; - elysium_debug_consensus_hash_every_block = allDebugState; - elysium_debug_alerts = allDebugState; - elysium_debug_consensus_hash_every_transaction = allDebugState; - elysium_debug_fees = allDebugState; - } - } -} - -/** - * Scrolls debug log, if it's getting too big. - */ -void ShrinkDebugLog() -{ - boost::filesystem::path pathLog = GetLogPath(); - FILE* file = fopen(pathLog.string().c_str(), "r"); - - if (file && boost::filesystem::file_size(pathLog) > LOG_SHRINKSIZE) { - // Restart the file with some of the end - char* pch = new char[LOG_BUFFERSIZE]; - if (NULL != pch) { - fseek(file, -LOG_BUFFERSIZE, SEEK_END); - int nBytes = fread(pch, 1, LOG_BUFFERSIZE, file); - fclose(file); - file = NULL; - - file = fopen(pathLog.string().c_str(), "w"); - if (file) { - fwrite(pch, 1, nBytes, file); - fclose(file); - file = NULL; - } - delete[] pch; - } - } else if (NULL != file) { - fclose(file); - file = NULL; - } -} diff --git a/src/elysium/log.h b/src/elysium/log.h deleted file mode 100644 index 5706c64a9b..0000000000 --- a/src/elysium/log.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef ELYSIUM_LOG_H -#define ELYSIUM_LOG_H - -#include "util.h" -#include "tinyformat.h" - -#include - -/** Prints to the log file. */ -int LogFilePrint(const std::string& str); - -/** Determine whether to override compiled debug levels. */ -void InitDebugLogLevels(); - -/** Scrolls log file, if it's getting too big. */ -void ShrinkDebugLog(); - -// Debug flags -extern bool elysium_debug_parser_data; -extern bool elysium_debug_parser_readonly; -extern bool elysium_debug_parser_dex; -extern bool elysium_debug_parser; -extern bool elysium_debug_verbose; -extern bool elysium_debug_verbose2; -extern bool elysium_debug_verbose3; -extern bool elysium_debug_vin; -extern bool elysium_debug_script; -extern bool elysium_debug_dex; -extern bool elysium_debug_send; -extern bool elysium_debug_tokens; -extern bool elysium_debug_spec; -extern bool elysium_debug_ely; -extern bool elysium_debug_tally; -extern bool elysium_debug_sp; -extern bool elysium_debug_sto; -extern bool elysium_debug_txdb; -extern bool elysium_debug_tradedb; -extern bool elysium_debug_persistence; -extern bool elysium_debug_ui; -extern bool elysium_debug_pending; -extern bool elysium_debug_metadex1; -extern bool elysium_debug_metadex2; -extern bool elysium_debug_metadex3; -extern bool elysium_debug_packets; -extern bool elysium_debug_packets_readonly; -extern bool elysium_debug_walletcache; -extern bool elysium_debug_consensus_hash; -extern bool elysium_debug_consensus_hash_every_block; -extern bool elysium_debug_alerts; -extern bool elysium_debug_consensus_hash_every_transaction; -extern bool elysium_debug_fees; - -/* When we switch to C++11, this can be switched to variadic templates instead - * of this macro-based construction (see tinyformat.h). - */ -#define MAKE_ELYSIUM_ERROR_AND_LOG_FUNC(n) \ - template \ - static inline int PrintToLog(const char* format, TINYFORMAT_VARARGS(n)) \ - { \ - return LogFilePrint(tfm::format(format, TINYFORMAT_PASSARGS(n))); \ - } \ - template \ - static inline int PrintToLog(TINYFORMAT_VARARGS(n)) \ - { \ - return LogFilePrint(tfm::format("%s", TINYFORMAT_PASSARGS(n))); \ - } - -TINYFORMAT_FOREACH_ARGNUM(MAKE_ELYSIUM_ERROR_AND_LOG_FUNC) - -#undef MAKE_ELYSIUM_ERROR_AND_LOG_FUNC - - -#endif // ELYSIUM_LOG_H diff --git a/src/elysium/mdex.cpp b/src/elysium/mdex.cpp deleted file mode 100644 index 7e1426990c..0000000000 --- a/src/elysium/mdex.cpp +++ /dev/null @@ -1,850 +0,0 @@ -#include "elysium/mdex.h" - -#include "elysium/errors.h" -#include "elysium/fees.h" -#include "elysium/log.h" -#include "elysium/elysium.h" -#include "elysium/rules.h" -#include "elysium/sp.h" -#include "elysium/tx.h" -#include "elysium/uint256_extensions.h" - -#include "arith_uint256.h" -#include "chain.h" -#include "validation.h" -#include "tinyformat.h" -#include "uint256.h" - -#include - -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include - -typedef boost::multiprecision::cpp_dec_float_100 dec_float; -typedef boost::multiprecision::checked_int128_t int128_t; - -using namespace elysium; - -//! Number of digits of unit price -#define DISPLAY_PRECISION_LEN 50 - -//! Global map for price and order data -md_PropertiesMap elysium::metadex; - -md_PricesMap* elysium::get_Prices(uint32_t prop) -{ - md_PropertiesMap::iterator it = metadex.find(prop); - - if (it != metadex.end()) return &(it->second); - - return (md_PricesMap*) NULL; -} - -md_Set* elysium::get_Indexes(md_PricesMap* p, rational_t price) -{ - md_PricesMap::iterator it = p->find(price); - - if (it != p->end()) return &(it->second); - - return (md_Set*) NULL; -} - -enum MatchReturnType -{ - NOTHING = 0, - TRADED = 1, - TRADED_MOREINSELLER, - TRADED_MOREINBUYER, - ADDED, - CANCELLED, -}; - -static const std::string getTradeReturnType(MatchReturnType ret) -{ - switch (ret) { - case NOTHING: return "NOTHING"; - case TRADED: return "TRADED"; - case TRADED_MOREINSELLER: return "TRADED_MOREINSELLER"; - case TRADED_MOREINBUYER: return "TRADED_MOREINBUYER"; - case ADDED: return "ADDED"; - case CANCELLED: return "CANCELLED"; - default: return "* unknown *"; - } -} - -// Used by rangeInt64, xToInt64 -static bool rangeInt64(const int128_t& value) -{ - return (std::numeric_limits::min() <= value && value <= std::numeric_limits::max()); -} - -// Used by xToString -static bool rangeInt64(const rational_t& value) -{ - return (rangeInt64(value.numerator()) && rangeInt64(value.denominator())); -} - -// Used by CMPMetaDEx::displayUnitPrice -static int64_t xToRoundUpInt64(const rational_t& value) -{ - // for integer rounding up: ceil(num / denom) => 1 + (num - 1) / denom - int128_t result = int128_t(1) + (value.numerator() - int128_t(1)) / value.denominator(); - - assert(rangeInt64(result)); - - return result.convert_to(); -} - -std::string xToString(const dec_float& value) -{ - return value.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed); -} - -std::string xToString(const int128_t& value) -{ - return strprintf("%s", boost::lexical_cast(value)); -} - -std::string xToString(const rational_t& value) -{ - if (rangeInt64(value)) { - int64_t num = value.numerator().convert_to(); - int64_t denom = value.denominator().convert_to(); - dec_float x = dec_float(num) / dec_float(denom); - return xToString(x); - } else { - return strprintf("%s / %s", xToString(value.numerator()), xToString(value.denominator())); - } -} - -// find the best match on the market -// NOTE: sometimes I refer to the older order as seller & the newer order as buyer, in this trade -// INPUT: property, desprop, desprice = of the new order being inserted; the new object being processed -// RETURN: -static MatchReturnType x_Trade(CMPMetaDEx* const pnew) -{ - const uint32_t propertyForSale = pnew->getProperty(); - const uint32_t propertyDesired = pnew->getDesProperty(); - MatchReturnType NewReturn = NOTHING; - bool bBuyerSatisfied = false; - - if (elysium_debug_metadex1) PrintToLog("%s(%s: prop=%d, desprop=%d, desprice= %s);newo: %s\n", - __FUNCTION__, pnew->getAddr(), propertyForSale, propertyDesired, xToString(pnew->inversePrice()), pnew->ToString()); - - md_PricesMap* const ppriceMap = get_Prices(propertyDesired); - - // nothing for the desired property exists in the market, sorry! - if (!ppriceMap) { - PrintToLog("%s()=%d:%s NOT FOUND ON THE MARKET\n", __FUNCTION__, NewReturn, getTradeReturnType(NewReturn)); - return NewReturn; - } - - // within the desired property map (given one property) iterate over the items looking at prices - for (md_PricesMap::iterator priceIt = ppriceMap->begin(); priceIt != ppriceMap->end(); ++priceIt) { // check all prices - const rational_t sellersPrice = priceIt->first; - - if (elysium_debug_metadex2) PrintToLog("comparing prices: desprice %s needs to be GREATER THAN OR EQUAL TO %s\n", - xToString(pnew->inversePrice()), xToString(sellersPrice)); - - // Is the desired price check satisfied? The buyer's inverse price must be larger than that of the seller. - if (pnew->inversePrice() < sellersPrice) { - continue; - } - - md_Set* const pofferSet = &(priceIt->second); - - // at good (single) price level and property iterate over offers looking at all parameters to find the match - md_Set::iterator offerIt = pofferSet->begin(); - while (offerIt != pofferSet->end()) { // specific price, check all properties - const CMPMetaDEx* const pold = &(*offerIt); - assert(pold->unitPrice() == sellersPrice); - - if (elysium_debug_metadex1) PrintToLog("Looking at existing: %s (its prop= %d, its des prop= %d) = %s\n", - xToString(sellersPrice), pold->getProperty(), pold->getDesProperty(), pold->ToString()); - - // does the desired property match? - if (pold->getDesProperty() != propertyForSale) { - ++offerIt; - continue; - } - - if (elysium_debug_metadex1) PrintToLog("MATCH FOUND, Trade: %s = %s\n", xToString(sellersPrice), pold->ToString()); - - // match found, execute trade now! - const int64_t seller_amountForSale = pold->getAmountRemaining(); - const int64_t buyer_amountOffered = pnew->getAmountRemaining(); - - if (elysium_debug_metadex1) PrintToLog("$$ trading using price: %s; seller: forsale=%d, desired=%d, remaining=%d, buyer amount offered=%d\n", - xToString(sellersPrice), pold->getAmountForSale(), pold->getAmountDesired(), pold->getAmountRemaining(), pnew->getAmountRemaining()); - if (elysium_debug_metadex1) PrintToLog("$$ old: %s\n", pold->ToString()); - if (elysium_debug_metadex1) PrintToLog("$$ new: %s\n", pnew->ToString()); - - /////////////////////////// - - // preconditions - assert(0 < pold->getAmountRemaining()); - assert(0 < pnew->getAmountRemaining()); - assert(pnew->getProperty() != pnew->getDesProperty()); - assert(pnew->getProperty() == pold->getDesProperty()); - assert(pold->getProperty() == pnew->getDesProperty()); - assert(pold->unitPrice() <= pnew->inversePrice()); - assert(pnew->unitPrice() <= pold->inversePrice()); - - /////////////////////////// - - // First determine how many representable (indivisible) tokens Alice can - // purchase from Bob, using Bob's unit price - // This implies rounding down, since rounding up is impossible, and would - // require more tokens than Alice has - arith_uint256 iCouldBuy = (ConvertTo256(pnew->getAmountRemaining()) * ConvertTo256(pold->getAmountForSale())) / ConvertTo256(pold->getAmountDesired()); - - int64_t nCouldBuy = 0; - if (iCouldBuy < ConvertTo256(pold->getAmountRemaining())) { - nCouldBuy = ConvertTo64(iCouldBuy); - } else { - nCouldBuy = pold->getAmountRemaining(); - } - - if (nCouldBuy == 0) { - if (elysium_debug_metadex1) PrintToLog( - "-- buyer has not enough tokens for sale to purchase one unit!\n"); - ++offerIt; - continue; - } - - // If the amount Alice would have to pay to buy Bob's tokens at his price - // is fractional, always round UP the amount Alice has to pay - // This will always be better for Bob. Rounding in the other direction - // will always be impossible, because ot would violate Bob's accepted price - arith_uint256 iWouldPay = DivideAndRoundUp((ConvertTo256(nCouldBuy) * ConvertTo256(pold->getAmountDesired())), ConvertTo256(pold->getAmountForSale())); - int64_t nWouldPay = ConvertTo64(iWouldPay); - - // If the resulting adjusted unit price is higher than Alice' price, the - // orders shall not execute, and no representable fill is made - const rational_t xEffectivePrice(nWouldPay, nCouldBuy); - - if (xEffectivePrice > pnew->inversePrice()) { - if (elysium_debug_metadex1) PrintToLog( - "-- effective price is too expensive: %s\n", xToString(xEffectivePrice)); - ++offerIt; - continue; - } - - const int64_t buyer_amountGot = nCouldBuy; - const int64_t seller_amountGot = nWouldPay; - const int64_t buyer_amountLeft = pnew->getAmountRemaining() - seller_amountGot; - const int64_t seller_amountLeft = pold->getAmountRemaining() - buyer_amountGot; - - if (elysium_debug_metadex1) PrintToLog("$$ buyer_got= %d, seller_got= %d, seller_left_for_sale= %d, buyer_still_for_sale= %d\n", - buyer_amountGot, seller_amountGot, seller_amountLeft, buyer_amountLeft); - - /////////////////////////// - - // postconditions - assert(xEffectivePrice >= pold->unitPrice()); - assert(xEffectivePrice <= pnew->inversePrice()); - assert(0 <= seller_amountLeft); - assert(0 <= buyer_amountLeft); - assert(seller_amountForSale == seller_amountLeft + buyer_amountGot); - assert(buyer_amountOffered == buyer_amountLeft + seller_amountGot); - - /////////////////////////// - - int64_t buyer_amountGotAfterFee = buyer_amountGot; - int64_t tradingFee = 0; - - // strip a 0.05% fee from non-ELYSIUM pairs if fees are activated - if (IsFeatureActivated(FEATURE_FEES, pnew->getBlock())) { - if (pold->getProperty() > ELYSIUM_PROPERTY_TELYSIUM && pold->getDesProperty() > ELYSIUM_PROPERTY_TELYSIUM) { - int64_t feeDivider = 2000; // 0.05% - tradingFee = buyer_amountGot / feeDivider; - - // subtract the fee from the amount the seller will receive - buyer_amountGotAfterFee = buyer_amountGot - tradingFee; - - // add the fee to the fee cache - p_feecache->AddFee(pnew->getDesProperty(), pnew->getBlock(), tradingFee); - } else { - if (elysium_debug_fees) PrintToLog("Skipping fee reduction for trade match %s:%s as one of the properties is Omni\n", pold->getHash().GetHex(), pnew->getHash().GetHex()); - } - } - - // transfer the payment property from buyer to seller - assert(update_tally_map(pnew->getAddr(), pnew->getProperty(), -seller_amountGot, BALANCE)); - assert(update_tally_map(pold->getAddr(), pold->getDesProperty(), seller_amountGot, BALANCE)); - - // transfer the market (the one being sold) property from seller to buyer - assert(update_tally_map(pold->getAddr(), pold->getProperty(), -buyer_amountGot, METADEX_RESERVE)); - assert(update_tally_map(pnew->getAddr(), pnew->getDesProperty(), buyer_amountGotAfterFee, BALANCE)); - - NewReturn = TRADED; - - CMPMetaDEx seller_replacement = *pold; // < can be moved into last if block - seller_replacement.setAmountRemaining(seller_amountLeft, "seller_replacement"); - - pnew->setAmountRemaining(buyer_amountLeft, "buyer"); - - if (0 < buyer_amountLeft) { - NewReturn = TRADED_MOREINBUYER; - } - - if (0 == buyer_amountLeft) { - bBuyerSatisfied = true; - } - - if (0 < seller_amountLeft) { - NewReturn = TRADED_MOREINSELLER; - } - - if (elysium_debug_metadex1) PrintToLog("==== TRADED !!! %u=%s\n", NewReturn, getTradeReturnType(NewReturn)); - - // record the trade in MPTradeList - t_tradelistdb->recordMatchedTrade(pold->getHash(), pnew->getHash(), // < might just pass pold, pnew - pold->getAddr(), pnew->getAddr(), pold->getDesProperty(), pnew->getDesProperty(), seller_amountGot, buyer_amountGotAfterFee, pnew->getBlock(), tradingFee); - - if (elysium_debug_metadex1) PrintToLog("++ erased old: %s\n", offerIt->ToString()); - // erase the old seller element - pofferSet->erase(offerIt++); - - // insert the updated one in place of the old - if (0 < seller_replacement.getAmountRemaining()) { - PrintToLog("++ inserting seller_replacement: %s\n", seller_replacement.ToString()); - pofferSet->insert(seller_replacement); - } - - if (bBuyerSatisfied) { - assert(buyer_amountLeft == 0); - break; - } - } // specific price, check all properties - - if (bBuyerSatisfied) break; - } // check all prices - - PrintToLog("%s()=%d:%s\n", __FUNCTION__, NewReturn, getTradeReturnType(NewReturn)); - - return NewReturn; -} - -/** - * Used for display of unit prices to 8 decimal places at UI layer. - * - * Automatically returns unit or inverse price as needed. - */ -std::string CMPMetaDEx::displayUnitPrice() const -{ - rational_t tmpDisplayPrice; - if (getDesProperty() == ELYSIUM_PROPERTY_ELYSIUM || getDesProperty() == ELYSIUM_PROPERTY_TELYSIUM) { - tmpDisplayPrice = unitPrice(); - if (isPropertyDivisible(getProperty())) tmpDisplayPrice = tmpDisplayPrice * COIN; - } else { - tmpDisplayPrice = inversePrice(); - if (isPropertyDivisible(getDesProperty())) tmpDisplayPrice = tmpDisplayPrice * COIN; - } - - // offers with unit prices under 0.00000001 will be excluded from UI layer - TODO: find a better way to identify sub 0.00000001 prices - std::string tmpDisplayPriceStr = xToString(tmpDisplayPrice); - if (!tmpDisplayPriceStr.empty()) { if (tmpDisplayPriceStr.substr(0,1) == "0") return "0.00000000"; } - - // we must always round up here - for example if the actual price required is 0.3333333344444 - // round: 0.33333333 - price is insufficient and thus won't result in a trade - // round: 0.33333334 - price will be sufficient to result in a trade - std::string displayValue = FormatDivisibleMP(xToRoundUpInt64(tmpDisplayPrice)); - return displayValue; -} - -/** - * Used for display of unit prices with 50 decimal places at RPC layer. - * - * Note: unit price is no longer always shown in ELYSIUM and/or inverted - */ -std::string CMPMetaDEx::displayFullUnitPrice() const -{ - rational_t tempUnitPrice = unitPrice(); - - /* Matching types require no action (divisible/divisible or indivisible/indivisible) - Non-matching types require adjustment for display purposes - divisible/indivisible : *COIN - indivisible/divisible : /COIN - */ - if ( isPropertyDivisible(getProperty()) && !isPropertyDivisible(getDesProperty()) ) tempUnitPrice = tempUnitPrice*COIN; - if ( !isPropertyDivisible(getProperty()) && isPropertyDivisible(getDesProperty()) ) tempUnitPrice = tempUnitPrice/COIN; - - std::string unitPriceStr = xToString(tempUnitPrice); - return unitPriceStr; -} - -rational_t CMPMetaDEx::unitPrice() const -{ - rational_t effectivePrice; - if (amount_forsale) effectivePrice = rational_t(amount_desired, amount_forsale); - return effectivePrice; -} - -rational_t CMPMetaDEx::inversePrice() const -{ - rational_t inversePrice; - if (amount_desired) inversePrice = rational_t(amount_forsale, amount_desired); - return inversePrice; -} - -int64_t CMPMetaDEx::getAmountToFill() const -{ - // round up to ensure that the amount we present will actually result in buying all available tokens - arith_uint256 iAmountNeededToFill = DivideAndRoundUp((ConvertTo256(amount_remaining) * ConvertTo256(amount_desired)), ConvertTo256(amount_forsale)); - int64_t nAmountNeededToFill = ConvertTo64(iAmountNeededToFill); - return nAmountNeededToFill; -} - -int64_t CMPMetaDEx::getBlockTime() const -{ - CBlockIndex* pblockindex = chainActive[block]; - return pblockindex->GetBlockTime(); -} - -void CMPMetaDEx::setAmountRemaining(int64_t amount, const std::string& label) -{ - amount_remaining = amount; - PrintToLog("update remaining amount still up for sale (%ld %s):%s\n", amount, label, ToString()); -} - -std::string CMPMetaDEx::ToString() const -{ - return strprintf("%s:%34s in %d/%03u, txid: %s , trade #%u %s for #%u %s", - xToString(unitPrice()), addr, block, idx, txid.ToString().substr(0, 10), - property, FormatMP(property, amount_forsale), desired_property, FormatMP(desired_property, amount_desired)); -} - -void CMPMetaDEx::saveOffer(std::ofstream& file, SHA256_CTX* shaCtx) const -{ - std::string lineOut = strprintf("%s,%d,%d,%d,%d,%d,%d,%d,%s,%d", - addr, - block, - amount_forsale, - property, - amount_desired, - desired_property, - subaction, - idx, - txid.ToString(), - amount_remaining - ); - - // add the line to the hash - SHA256_Update(shaCtx, lineOut.c_str(), lineOut.length()); - - // write the line - file << lineOut << std::endl; -} - -bool MetaDEx_compare::operator()(const CMPMetaDEx &lhs, const CMPMetaDEx &rhs) const -{ - if (lhs.getBlock() == rhs.getBlock()) return lhs.getIdx() < rhs.getIdx(); - else return lhs.getBlock() < rhs.getBlock(); -} - -bool elysium::MetaDEx_INSERT(const CMPMetaDEx& objMetaDEx) -{ - // Create an empty price map (to use in case price map for this property does not already exist) - md_PricesMap temp_prices; - // Attempt to obtain the price map for the property - md_PricesMap *p_prices = get_Prices(objMetaDEx.getProperty()); - - // Create an empty set of metadex objects (to use in case no set currently exists at this price) - md_Set temp_indexes; - md_Set *p_indexes = NULL; - - // Prepare for return code - std::pair ret; - - // Attempt to obtain a set of metadex objects for this price from the price map - if (p_prices) p_indexes = get_Indexes(p_prices, objMetaDEx.unitPrice()); - // See if the set was populated, if not no set exists at this price level, use the empty set that we created earlier - if (!p_indexes) p_indexes = &temp_indexes; - - // Attempt to insert the metadex object into the set - ret = p_indexes->insert(objMetaDEx); - if (false == ret.second) return false; - - // If a prices map did not exist for this property, set p_prices to the temp empty price map - if (!p_prices) p_prices = &temp_prices; - - // Update the prices map with the new set at this price - (*p_prices)[objMetaDEx.unitPrice()] = *p_indexes; - - // Set the metadex map for the property to the updated (or new if it didn't exist) price map - metadex[objMetaDEx.getProperty()] = *p_prices; - - return true; -} - -// pretty much directly linked to the ADD TX21 command off the wire -int elysium::MetaDEx_ADD(const std::string& sender_addr, uint32_t prop, int64_t amount, int block, uint32_t property_desired, int64_t amount_desired, const uint256& txid, unsigned int idx) -{ - int rc = METADEX_ERROR -1; - - // Create a MetaDEx object from paremeters - CMPMetaDEx new_mdex(sender_addr, block, prop, amount, property_desired, amount_desired, txid, idx, CMPTransaction::ADD); - if (elysium_debug_metadex1) PrintToLog("%s(); buyer obj: %s\n", __FUNCTION__, new_mdex.ToString()); - - // Ensure this is not a badly priced trade (for example due to zero amounts) - if (0 >= new_mdex.unitPrice()) return METADEX_ERROR -66; - - // Match against existing trades, remainder of the order will be put into the order book - if (elysium_debug_metadex3) MetaDEx_debug_print(); - x_Trade(&new_mdex); - if (elysium_debug_metadex3) MetaDEx_debug_print(); - - // Insert the remaining order into the MetaDEx maps - if (0 < new_mdex.getAmountRemaining()) { //switch to getAmountRemaining() when ready - if (!MetaDEx_INSERT(new_mdex)) { - PrintToLog("%s() ERROR: ALREADY EXISTS, line %d, file: %s\n", __FUNCTION__, __LINE__, __FILE__); - return METADEX_ERROR -70; - } else { - // move tokens into reserve - assert(update_tally_map(sender_addr, prop, -new_mdex.getAmountRemaining(), BALANCE)); - assert(update_tally_map(sender_addr, prop, new_mdex.getAmountRemaining(), METADEX_RESERVE)); - - if (elysium_debug_metadex1) PrintToLog("==== INSERTED: %s= %s\n", xToString(new_mdex.unitPrice()), new_mdex.ToString()); - if (elysium_debug_metadex3) MetaDEx_debug_print(); - } - } - - rc = 0; - return rc; -} - -int elysium::MetaDEx_CANCEL_AT_PRICE(const uint256& txid, unsigned int block, const std::string& sender_addr, uint32_t prop, int64_t amount, uint32_t property_desired, int64_t amount_desired) -{ - int rc = METADEX_ERROR -20; - CMPMetaDEx mdex(sender_addr, 0, prop, amount, property_desired, amount_desired, uint256(), 0, CMPTransaction::CANCEL_AT_PRICE); - md_PricesMap* prices = get_Prices(prop); - const CMPMetaDEx* p_mdex = NULL; - - if (elysium_debug_metadex1) PrintToLog("%s():%s\n", __FUNCTION__, mdex.ToString()); - - if (elysium_debug_metadex2) MetaDEx_debug_print(); - - if (!prices) { - PrintToLog("%s() NOTHING FOUND for %s\n", __FUNCTION__, mdex.ToString()); - return rc -1; - } - - // within the desired property map (given one property) iterate over the items - for (md_PricesMap::iterator my_it = prices->begin(); my_it != prices->end(); ++my_it) { - rational_t sellers_price = my_it->first; - - if (mdex.unitPrice() != sellers_price) continue; - - md_Set* indexes = &(my_it->second); - - for (md_Set::iterator iitt = indexes->begin(); iitt != indexes->end();) { - p_mdex = &(*iitt); - - if (elysium_debug_metadex3) PrintToLog("%s(): %s\n", __FUNCTION__, p_mdex->ToString()); - - if ((p_mdex->getDesProperty() != property_desired) || (p_mdex->getAddr() != sender_addr)) { - ++iitt; - continue; - } - - rc = 0; - PrintToLog("%s(): REMOVING %s\n", __FUNCTION__, p_mdex->ToString()); - - // move from reserve to main - assert(update_tally_map(p_mdex->getAddr(), p_mdex->getProperty(), -p_mdex->getAmountRemaining(), METADEX_RESERVE)); - assert(update_tally_map(p_mdex->getAddr(), p_mdex->getProperty(), p_mdex->getAmountRemaining(), BALANCE)); - - // record the cancellation - bool bValid = true; - p_txlistdb->recordMetaDExCancelTX(txid, p_mdex->getHash(), bValid, block, p_mdex->getProperty(), p_mdex->getAmountRemaining()); - - indexes->erase(iitt++); - } - } - - if (elysium_debug_metadex2) MetaDEx_debug_print(); - - return rc; -} - -int elysium::MetaDEx_CANCEL_ALL_FOR_PAIR(const uint256& txid, unsigned int block, const std::string& sender_addr, uint32_t prop, uint32_t property_desired) -{ - int rc = METADEX_ERROR -30; - md_PricesMap* prices = get_Prices(prop); - const CMPMetaDEx* p_mdex = NULL; - - PrintToLog("%s(%d,%d)\n", __FUNCTION__, prop, property_desired); - - if (elysium_debug_metadex3) MetaDEx_debug_print(); - - if (!prices) { - PrintToLog("%s() NOTHING FOUND\n", __FUNCTION__); - return rc -1; - } - - // within the desired property map (given one property) iterate over the items - for (md_PricesMap::iterator my_it = prices->begin(); my_it != prices->end(); ++my_it) { - md_Set* indexes = &(my_it->second); - - for (md_Set::iterator iitt = indexes->begin(); iitt != indexes->end();) { - p_mdex = &(*iitt); - - if (elysium_debug_metadex3) PrintToLog("%s(): %s\n", __FUNCTION__, p_mdex->ToString()); - - if ((p_mdex->getDesProperty() != property_desired) || (p_mdex->getAddr() != sender_addr)) { - ++iitt; - continue; - } - - rc = 0; - PrintToLog("%s(): REMOVING %s\n", __FUNCTION__, p_mdex->ToString()); - - // move from reserve to main - assert(update_tally_map(p_mdex->getAddr(), p_mdex->getProperty(), -p_mdex->getAmountRemaining(), METADEX_RESERVE)); - assert(update_tally_map(p_mdex->getAddr(), p_mdex->getProperty(), p_mdex->getAmountRemaining(), BALANCE)); - - // record the cancellation - bool bValid = true; - p_txlistdb->recordMetaDExCancelTX(txid, p_mdex->getHash(), bValid, block, p_mdex->getProperty(), p_mdex->getAmountRemaining()); - - indexes->erase(iitt++); - } - } - - if (elysium_debug_metadex3) MetaDEx_debug_print(); - - return rc; -} - -/** - * Scans the orderbook and remove everything for an address. - */ -int elysium::MetaDEx_CANCEL_EVERYTHING(const uint256& txid, unsigned int block, const std::string& sender_addr, unsigned char ecosystem) -{ - int rc = METADEX_ERROR -40; - - PrintToLog("%s()\n", __FUNCTION__); - - if (elysium_debug_metadex2) MetaDEx_debug_print(); - - PrintToLog("<<<<<<\n"); - - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - unsigned int prop = my_it->first; - - // skip property, if it is not in the expected ecosystem - if (isMainEcosystemProperty(ecosystem) && !isMainEcosystemProperty(prop)) continue; - if (isTestEcosystemProperty(ecosystem) && !isTestEcosystemProperty(prop)) continue; - - PrintToLog(" ## property: %u\n", prop); - md_PricesMap& prices = my_it->second; - - for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it) { - rational_t price = it->first; - md_Set& indexes = it->second; - - PrintToLog(" # Price Level: %s\n", xToString(price)); - - for (md_Set::iterator it = indexes.begin(); it != indexes.end();) { - PrintToLog("%s= %s\n", xToString(price), it->ToString()); - - if (it->getAddr() != sender_addr) { - ++it; - continue; - } - - rc = 0; - PrintToLog("%s(): REMOVING %s\n", __FUNCTION__, it->ToString()); - - // move from reserve to balance - assert(update_tally_map(it->getAddr(), it->getProperty(), -it->getAmountRemaining(), METADEX_RESERVE)); - assert(update_tally_map(it->getAddr(), it->getProperty(), it->getAmountRemaining(), BALANCE)); - - // record the cancellation - bool bValid = true; - p_txlistdb->recordMetaDExCancelTX(txid, it->getHash(), bValid, block, it->getProperty(), it->getAmountRemaining()); - - indexes.erase(it++); - } - } - } - PrintToLog(">>>>>>\n"); - - if (elysium_debug_metadex2) MetaDEx_debug_print(); - - return rc; -} - -/** - * Scans the orderbook and removes every all-pair order - */ -int elysium::MetaDEx_SHUTDOWN_ALLPAIR() -{ - int rc = 0; - PrintToLog("%s()\n", __FUNCTION__); - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - md_PricesMap& prices = my_it->second; - for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it) { - md_Set& indexes = it->second; - for (md_Set::iterator it = indexes.begin(); it != indexes.end();) { - if (it->getDesProperty() > ELYSIUM_PROPERTY_TELYSIUM && it->getProperty() > ELYSIUM_PROPERTY_TELYSIUM) { // no ELYSIUM/TELYSIUM side to the trade - PrintToLog("%s(): REMOVING %s\n", __FUNCTION__, it->ToString()); - // move from reserve to balance - assert(update_tally_map(it->getAddr(), it->getProperty(), -it->getAmountRemaining(), METADEX_RESERVE)); - assert(update_tally_map(it->getAddr(), it->getProperty(), it->getAmountRemaining(), BALANCE)); - indexes.erase(it++); - } - } - } - } - return rc; -} - -/** - * Scans the orderbook and removes every order - */ -int elysium::MetaDEx_SHUTDOWN() -{ - int rc = 0; - PrintToLog("%s()\n", __FUNCTION__); - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - md_PricesMap& prices = my_it->second; - for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it) { - md_Set& indexes = it->second; - for (md_Set::iterator it = indexes.begin(); it != indexes.end();) { - PrintToLog("%s(): REMOVING %s\n", __FUNCTION__, it->ToString()); - // move from reserve to balance - assert(update_tally_map(it->getAddr(), it->getProperty(), -it->getAmountRemaining(), METADEX_RESERVE)); - assert(update_tally_map(it->getAddr(), it->getProperty(), it->getAmountRemaining(), BALANCE)); - indexes.erase(it++); - } - } - } - return rc; -} - -// searches the metadex maps to see if a trade is still open -// allows search to be optimized if propertyIdForSale is specified -bool elysium::MetaDEx_isOpen(const uint256& txid, uint32_t propertyIdForSale) -{ - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - if (propertyIdForSale != 0 && propertyIdForSale != my_it->first) continue; - md_PricesMap & prices = my_it->second; - for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it) { - md_Set & indexes = (it->second); - for (md_Set::iterator it = indexes.begin(); it != indexes.end(); ++it) { - CMPMetaDEx obj = *it; - if( obj.getHash().GetHex() == txid.GetHex() ) return true; - } - } - } - return false; -} - -/** - * Returns a string describing the status of a trade - * - */ -std::string elysium::MetaDEx_getStatusText(int tradeStatus) -{ - switch (tradeStatus) { - case TRADE_OPEN: return "open"; - case TRADE_OPEN_PART_FILLED: return "open part filled"; - case TRADE_FILLED: return "filled"; - case TRADE_CANCELLED: return "cancelled"; - case TRADE_CANCELLED_PART_FILLED: return "cancelled part filled"; - case TRADE_INVALID: return "trade invalid"; - default: return "unknown"; - } -} - -/** - * Returns the status of a MetaDEx trade - * - */ -int elysium::MetaDEx_getStatus(const uint256& txid, uint32_t propertyIdForSale, int64_t amountForSale, int64_t totalSold) -{ - // NOTE: If the calling code is already aware of the total amount sold, pass the value in to this function to avoid duplication of - // work. If the calling code doesn't know the amount, leave default (-1) and we will calculate it from levelDB lookups. - if (totalSold == -1) { - UniValue tradeArray(UniValue::VARR); - int64_t totalReceived; - t_tradelistdb->getMatchingTrades(txid, propertyIdForSale, tradeArray, totalSold, totalReceived); - } - - // Return a "trade invalid" status if the trade was invalidated at parsing/interpretation (eg insufficient funds) - if (!getValidMPTX(txid)) return TRADE_INVALID; - - // Calculate and return the status of the trade via the amount sold and open/closed attributes. - if (MetaDEx_isOpen(txid, propertyIdForSale)) { - if (totalSold == 0) { - return TRADE_OPEN; - } else { - return TRADE_OPEN_PART_FILLED; - } - } else { - if (totalSold == 0) { - return TRADE_CANCELLED; - } else if (totalSold < amountForSale) { - return TRADE_CANCELLED_PART_FILLED; - } else { - return TRADE_FILLED; - } - } -} - -void elysium::MetaDEx_debug_print(bool bShowPriceLevel, bool bDisplay) -{ - PrintToLog("<<<\n"); - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - uint32_t prop = my_it->first; - - PrintToLog(" ## property: %u\n", prop); - md_PricesMap& prices = my_it->second; - - for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it) { - rational_t price = it->first; - md_Set& indexes = it->second; - - if (bShowPriceLevel) PrintToLog(" # Price Level: %s\n", xToString(price)); - - for (md_Set::iterator it = indexes.begin(); it != indexes.end(); ++it) { - const CMPMetaDEx& obj = *it; - - if (bDisplay) PrintToLog("%s= %s\n", xToString(price), obj.ToString()); - else PrintToLog("%s= %s\n", xToString(price), obj.ToString()); - } - } - } - PrintToLog(">>>\n"); -} - -/** - * Locates a trade in the MetaDEx maps via txid and returns the trade object - * - */ -const CMPMetaDEx* elysium::MetaDEx_RetrieveTrade(const uint256& txid) -{ - for (md_PropertiesMap::iterator propIter = metadex.begin(); propIter != metadex.end(); ++propIter) { - md_PricesMap & prices = propIter->second; - for (md_PricesMap::iterator pricesIter = prices.begin(); pricesIter != prices.end(); ++pricesIter) { - md_Set & indexes = pricesIter->second; - for (md_Set::iterator tradesIter = indexes.begin(); tradesIter != indexes.end(); ++tradesIter) { - if (txid == (*tradesIter).getHash()) return &(*tradesIter); - } - } - } - return (CMPMetaDEx*) NULL; -} diff --git a/src/elysium/mdex.h b/src/elysium/mdex.h deleted file mode 100644 index 637c60516d..0000000000 --- a/src/elysium/mdex.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef ELYSIUM_MDEX_H -#define ELYSIUM_MDEX_H - -#include "elysium/tx.h" - -#include "uint256.h" - -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -typedef boost::rational rational_t; - -// MetaDEx trade statuses -#define TRADE_INVALID -1 -#define TRADE_OPEN 1 -#define TRADE_OPEN_PART_FILLED 2 -#define TRADE_FILLED 3 -#define TRADE_CANCELLED 4 -#define TRADE_CANCELLED_PART_FILLED 5 - -/** Converts price to string. */ -std::string xToString(const rational_t& value); - -/** A trade on the distributed exchange. - */ -class CMPMetaDEx -{ -private: - int block; - uint256 txid; - unsigned int idx; // index within block - uint32_t property; - int64_t amount_forsale; - uint32_t desired_property; - int64_t amount_desired; - int64_t amount_remaining; - uint8_t subaction; - std::string addr; - -public: - uint256 getHash() const { return txid; } - - uint32_t getProperty() const { return property; } - uint32_t getDesProperty() const { return desired_property; } - - int64_t getAmountForSale() const { return amount_forsale; } - int64_t getAmountDesired() const { return amount_desired; } - int64_t getAmountRemaining() const { return amount_remaining; } - int64_t getAmountToFill() const; - - void setAmountRemaining(int64_t ar, const std::string& label = ""); - - uint8_t getAction() const { return subaction; } - - const std::string& getAddr() const { return addr; } - - int getBlock() const { return block; } - unsigned int getIdx() const { return idx; } - - int64_t getBlockTime() const; - - CMPMetaDEx() - : block(0), idx(0), property(0), amount_forsale(0), desired_property(0), amount_desired(0), - amount_remaining(0), subaction(0) {} - - CMPMetaDEx(const std::string& addr, int b, uint32_t c, int64_t nValue, uint32_t cd, int64_t ad, - const uint256& tx, uint32_t i, uint8_t suba) - : block(b), txid(tx), idx(i), property(c), amount_forsale(nValue), desired_property(cd), amount_desired(ad), - amount_remaining(nValue), subaction(suba), addr(addr) {} - - CMPMetaDEx(const std::string& addr, int b, uint32_t c, int64_t nValue, uint32_t cd, int64_t ad, - const uint256& tx, uint32_t i, uint8_t suba, int64_t ar) - : block(b), txid(tx), idx(i), property(c), amount_forsale(nValue), desired_property(cd), amount_desired(ad), - amount_remaining(ar), subaction(suba), addr(addr) {} - - CMPMetaDEx(const CMPTransaction& tx) - : block(tx.block), txid(tx.txid), idx(tx.tx_idx), property(tx.property), amount_forsale(tx.nValue), - desired_property(tx.desired_property), amount_desired(tx.desired_value), amount_remaining(tx.nValue), - subaction(tx.subaction), addr(tx.sender) {} - - std::string ToString() const; - - rational_t unitPrice() const; - rational_t inversePrice() const; - - /** Used for display of unit prices to 8 decimal places at UI layer. */ - std::string displayUnitPrice() const; - /** Used for display of unit prices with 50 decimal places at RPC layer. */ - std::string displayFullUnitPrice() const; - - void saveOffer(std::ofstream& file, SHA256_CTX* shaCtx) const; -}; - -namespace elysium -{ -struct MetaDEx_compare -{ - bool operator()(const CMPMetaDEx& lhs, const CMPMetaDEx& rhs) const; -}; - -// --------------- -//! Set of objects sorted by block+idx -typedef std::set md_Set; -//! Map of prices; there is a set of sorted objects for each price -typedef std::map md_PricesMap; -//! Map of properties; there is a map of prices for each property -typedef std::map md_PropertiesMap; - -//! Global map for price and order data -extern md_PropertiesMap metadex; - -// TODO: explore a property-pair, instead of a single property as map's key........ -md_PricesMap* get_Prices(uint32_t prop); -md_Set* get_Indexes(md_PricesMap* p, rational_t price); -// --------------- - -int MetaDEx_ADD(const std::string& sender_addr, uint32_t, int64_t, int block, uint32_t property_desired, int64_t amount_desired, const uint256& txid, unsigned int idx); -int MetaDEx_CANCEL_AT_PRICE(const uint256&, uint32_t, const std::string&, uint32_t, int64_t, uint32_t, int64_t); -int MetaDEx_CANCEL_ALL_FOR_PAIR(const uint256&, uint32_t, const std::string&, uint32_t, uint32_t); -int MetaDEx_CANCEL_EVERYTHING(const uint256& txid, uint32_t block, const std::string& sender_addr, unsigned char ecosystem); -int MetaDEx_SHUTDOWN(); -int MetaDEx_SHUTDOWN_ALLPAIR(); -bool MetaDEx_INSERT(const CMPMetaDEx& objMetaDEx); -void MetaDEx_debug_print(bool bShowPriceLevel = false, bool bDisplay = false); -bool MetaDEx_isOpen(const uint256& txid, uint32_t propertyIdForSale = 0); -int MetaDEx_getStatus(const uint256& txid, uint32_t propertyIdForSale, int64_t amountForSale, int64_t totalSold = -1); -std::string MetaDEx_getStatusText(int tradeStatus); - -// Locates a trade in the MetaDEx maps via txid and returns the trade object -const CMPMetaDEx* MetaDEx_RetrieveTrade(const uint256& txid); - -} - - -#endif // ELYSIUM_MDEX_H diff --git a/src/elysium/notifications.cpp b/src/elysium/notifications.cpp deleted file mode 100644 index 248ff30f15..0000000000 --- a/src/elysium/notifications.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "elysium/notifications.h" - -#include "elysium/log.h" -#include "elysium/elysium.h" -#include "elysium/rules.h" -#include "elysium/utilsbitcoin.h" -#include "elysium/version.h" - -#include "validation.h" -#include "util.h" -#include "ui_interface.h" - -#include -#include - -#include -#include -#include - -namespace elysium -{ - -//! Vector of currently active Elysium alerts -std::vector currentElysiumAlerts; - -/** - * Deletes previously broadcast alerts from sender from the alerts vector - * - * Note cannot be used to delete alerts from other addresses, nor to delete system generated feature alerts - */ -void DeleteAlerts(const std::string& sender) -{ - for (std::vector::iterator it = currentElysiumAlerts.begin(); it != currentElysiumAlerts.end(); ) { - AlertData alert = *it; - if (sender == alert.alert_sender) { - PrintToLog("Removing deleted alert (from:%s type:%d expiry:%d message:%s)\n", alert.alert_sender, - alert.alert_type, alert.alert_expiry, alert.alert_message); - it = currentElysiumAlerts.erase(it); - uiInterface.ElysiumStateChanged(); - } else { - it++; - } - } -} - -/** - * Removes all active alerts. - * - * A signal is fired to notify the UI about the status update. - */ -void ClearAlerts() -{ - currentElysiumAlerts.clear(); - uiInterface.ElysiumStateChanged(); -} - -/** - * Adds a new alert to the alerts vector - * - */ -void AddAlert(const std::string& sender, uint16_t alertType, uint32_t alertExpiry, const std::string& alertMessage) -{ - AlertData newAlert; - newAlert.alert_sender = sender; - newAlert.alert_type = alertType; - newAlert.alert_expiry = alertExpiry; - newAlert.alert_message = alertMessage; - - // very basic sanity checks for broadcast alerts to catch malformed packets - if (sender != "elysium" && (alertType < ALERT_BLOCK_EXPIRY || alertType > ALERT_CLIENT_VERSION_EXPIRY)) { - PrintToLog("New alert REJECTED (alert type not recognized): %s, %d, %d, %s\n", sender, alertType, alertExpiry, alertMessage); - return; - } - - currentElysiumAlerts.push_back(newAlert); - PrintToLog("New alert added: %s, %d, %d, %s\n", sender, alertType, alertExpiry, alertMessage); -} - -/** - * Determines whether the sender is an authorized source for Elysium Core alerts. - * - * The option "-elysiumalertallowsender=source" can be used to whitelist additional sources, - * and the option "-elysiumalertignoresender=source" can be used to ignore a source. - * - * To consider any alert as authorized, "-elysiumalertallowsender=any" can be used. This - * should only be done for testing purposes! - */ -bool CheckAlertAuthorization(const std::string& sender) -{ - std::set whitelisted; - - // Mainnet - whitelisted.insert("48UM25xTXCxPRwnv36YjjJNaAK4whKR8Rd"); // Poramin Insom - - // Testnet / Regtest - // use -elysiumalertallowsender for testing - - // Add manually whitelisted sources - if (mapMultiArgs.count("-elysiumalertallowsender")) { - const std::vector& sources = mapMultiArgs.at("-elysiumalertallowsender"); - - for (std::vector::const_iterator it = sources.begin(); it != sources.end(); ++it) { - whitelisted.insert(*it); - } - } - - // Remove manually ignored sources - if (mapMultiArgs.count("-elysiumalertignoresender")) { - const std::vector& sources = mapMultiArgs.at("-elysiumalertignoresender"); - - for (std::vector::const_iterator it = sources.begin(); it != sources.end(); ++it) { - whitelisted.erase(*it); - } - } - - bool fAuthorized = (whitelisted.count(sender) || - whitelisted.count("any")); - - return fAuthorized; -} - -/** - * Alerts including meta data. - */ -std::vector GetElysiumAlerts() -{ - return currentElysiumAlerts; -} - -/** - * Human readable alert messages. - */ -std::vector GetElysiumAlertMessages() -{ - std::vector vstr; - for (std::vector::iterator it = currentElysiumAlerts.begin(); it != currentElysiumAlerts.end(); it++) { - vstr.push_back((*it).alert_message); - } - return vstr; -} - -/** - * Expires any alerts that need expiring. - */ -bool CheckExpiredAlerts(unsigned int curBlock, uint64_t curTime) -{ - for (std::vector::iterator it = currentElysiumAlerts.begin(); it != currentElysiumAlerts.end(); ) { - AlertData alert = *it; - switch (alert.alert_type) { - case ALERT_BLOCK_EXPIRY: - if (curBlock >= alert.alert_expiry) { - PrintToLog("Expiring alert (from %s: type:%d expiry:%d message:%s)\n", alert.alert_sender, - alert.alert_type, alert.alert_expiry, alert.alert_message); - it = currentElysiumAlerts.erase(it); - uiInterface.ElysiumStateChanged(); - } else { - it++; - } - break; - case ALERT_BLOCKTIME_EXPIRY: - if (curTime > alert.alert_expiry) { - PrintToLog("Expiring alert (from %s: type:%d expiry:%d message:%s)\n", alert.alert_sender, - alert.alert_type, alert.alert_expiry, alert.alert_message); - it = currentElysiumAlerts.erase(it); - uiInterface.ElysiumStateChanged(); - } else { - it++; - } - break; - case ALERT_CLIENT_VERSION_EXPIRY: - if (ELYSIUM_VERSION > alert.alert_expiry) { - PrintToLog("Expiring alert (form: %s type:%d expiry:%d message:%s)\n", alert.alert_sender, - alert.alert_type, alert.alert_expiry, alert.alert_message); - it = currentElysiumAlerts.erase(it); - uiInterface.ElysiumStateChanged(); - } else { - it++; - } - break; - default: // unrecognized alert type - PrintToLog("Removing invalid alert (from:%s type:%d expiry:%d message:%s)\n", alert.alert_sender, - alert.alert_type, alert.alert_expiry, alert.alert_message); - it = currentElysiumAlerts.erase(it); - uiInterface.ElysiumStateChanged(); - break; - } - } - return true; -} - -} // namespace elysium diff --git a/src/elysium/notifications.h b/src/elysium/notifications.h deleted file mode 100644 index 2e6cf26a2d..0000000000 --- a/src/elysium/notifications.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef ELYSIUM_NOTIFICATIONS_H -#define ELYSIUM_NOTIFICATIONS_H - -#include -#include -#include - -//! Alert types -#define ALERT_FEATURE_UNSUPPORTED 0 // not allowed via alert broadcast -#define ALERT_BLOCK_EXPIRY 1 -#define ALERT_BLOCKTIME_EXPIRY 2 -#define ALERT_CLIENT_VERSION_EXPIRY 3 - -namespace elysium -{ -/** A structure for alert messages. - */ -struct AlertData -{ - //! Alert sender - std::string alert_sender; - //! Alert type - uint16_t alert_type; - //! Alert expiry - uint32_t alert_expiry; - //! Alert message - std::string alert_message; -}; - -/** Determines whether the sender is an authorized source for Elysium alerts. */ -bool CheckAlertAuthorization(const std::string& sender); - -/** Deletes previously broadcast alerts from the sender. */ -void DeleteAlerts(const std::string& sender); -/** Removes all active alerts. */ -void ClearAlerts(); - -/** Adds a new alert to the alerts vector. */ -void AddAlert(const std::string& sender, uint16_t alertType, uint32_t alertExpiry, const std::string& alertMessage); - -/** Alert string including meta data. */ -std::vector GetElysiumAlerts(); -/** Human readable alert messages. */ -std::vector GetElysiumAlertMessages(); - -/** Expires any alerts that need expiring. */ -bool CheckExpiredAlerts(unsigned int curBlock, uint64_t curTime); -} - -#endif // ELYSIUM_NOTIFICATIONS_H diff --git a/src/elysium/packetencoder.cpp b/src/elysium/packetencoder.cpp deleted file mode 100644 index a9a3d3af36..0000000000 --- a/src/elysium/packetencoder.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "packetencoder.h" - -#include "rules.h" -#include "script.h" -#include "utilsbitcoin.h" - -#include "../base58.h" -#include "../utilstrencodings.h" - -#include "../crypto/sha256.h" - -#include "../script/standard.h" - -#include -#include -#include -#include -#include -#include - -#include - -namespace elysium { - -// could not change to "elysium" because of previous exodus transactions -const std::array magic = { 0x65, 0x78, 0x6f, 0x64, 0x75, 0x73 }; // "exodus" - -// PacketKeyGenerator Implementation. - -PacketKeyGenerator::PacketKeyGenerator(const std::string& seed) : seed(seed) -{ -} - -std::array PacketKeyGenerator::Next() -{ - CSHA256 hasher; - std::array hash; - - hasher.Write(reinterpret_cast(seed.data()), seed.size()); - hasher.Finalize(hash.data()); - - seed = HexStr(hash.begin(), hash.end()); - std::transform(seed.begin(), seed.end(), seed.begin(), ::toupper); - - return hash; -} - -// Functions. - -const CBitcoinAddress& GetSystemAddress() -{ - static const CBitcoinAddress mainAddress("ZzzcQkPmXomcTcSVGsDHsGBCvxg67joaj5"); - static const CBitcoinAddress testAddress("TTFL4sPFHP22Dzqbw9mPQJEjdG7Wf1ajjZ"); - - return isNonMainNet() ? testAddress : mainAddress; -} - -boost::optional DeterminePacketClass(const CTransaction& tx, int height) -{ - // Inspect all outputs. - auto& sysAddr = GetSystemAddress(); - bool hasSysAddr = false; - bool hasMultisig = false; - bool hasOpReturn = false; - - for (auto& output : tx.vout) { - txnouttype type; - - if (!GetOutputType(output.scriptPubKey, type)) { - continue; - } - - if (!IsAllowedOutputType(type, height)) { - continue; - } - - if (type == TX_PUBKEYHASH) { - CTxDestination dest; - - if (ExtractDestination(output.scriptPubKey, dest) && CBitcoinAddress(dest) == sysAddr) { - hasSysAddr = true; - } - } else if (type == TX_MULTISIG) { - hasMultisig = true; - } else if (type == TX_NULL_DATA) { - // Check if the first push is prefixed with magic bytes. - std::vector> pushes; - - GetPushedValues(output.scriptPubKey, std::back_inserter(pushes)); - - if (!pushes.empty() && pushes[0].size() >= magic.size() && std::equal(magic.begin(), magic.end(), pushes[0].begin())) { - hasOpReturn = true; - } - } - } - - // Determine packet class based on inspection result. - if (hasOpReturn) { - return PacketClass::C; - } - - if (hasSysAddr && hasMultisig) { - return PacketClass::B; - } - - return boost::none; -} - -} // namespace elysium - -namespace std { - -using namespace elysium; - -string to_string(PacketClass c) -{ - switch (c) { - case PacketClass::B: - return "B"; - case PacketClass::C: - return "C"; - default: - throw invalid_argument("Packet class is not valid"); - } -} - -} // namespace std diff --git a/src/elysium/packetencoder.h b/src/elysium/packetencoder.h deleted file mode 100644 index 99b3c4c38c..0000000000 --- a/src/elysium/packetencoder.h +++ /dev/null @@ -1,231 +0,0 @@ -#ifndef FIRO_ELYSIUM_PACKETENCODER_H -#define FIRO_ELYSIUM_PACKETENCODER_H - -#include "script.h" - -#include "../base58.h" -#include "../pubkey.h" -#include "../random.h" - -#include "../primitives/transaction.h" - -#include "../script/script.h" -#include "../script/standard.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace elysium { - -static_assert(CPubKey::COMPRESSED_PUBLIC_KEY_SIZE >= 4, "Size of compressed public key must be at least 4 bytes"); - -constexpr unsigned CLASS_B_MAX_CHUNKS = 255; -constexpr unsigned CLASS_B_CHUNK_SIZE = CPubKey::COMPRESSED_PUBLIC_KEY_SIZE - 2; // One byte require for key type, another for ECDSA coordinate fix. -constexpr unsigned CLASS_B_CHUNK_PAYLOAD_SIZE = CLASS_B_CHUNK_SIZE - 1; // One byte for chunk number. - -/** - * Maximum size for packet payload for all classes. - **/ -constexpr unsigned MAX_PACKET_PAYLOAD = CLASS_B_CHUNK_PAYLOAD_SIZE * CLASS_B_MAX_CHUNKS; - -enum class PacketClass -{ - B, - C -}; - -class PacketKeyGenerator -{ -public: - PacketKeyGenerator(const std::string& seed); - -public: - std::array Next(); - -protected: - std::string seed; -}; - -class KeyEncoder -{ -public: - template - KeyEncoder(PacketKey first, PacketKey last) - { - SetPacketKey(first, last); - } - -public: - template - void SetPacketKey(PacketKey first, PacketKey last) - { - auto size = std::distance(first, last); - - if (size < 0 || static_cast(size) != encKey.size()) { - throw std::invalid_argument("Invalid key size"); - } - - std::copy(first, last, encKey.begin()); - } - -public: - template - CPubKey Encode(uint8_t chunk, Payload first, Payload last) - { - auto size = std::distance(first, last); - - if (size < 0 || static_cast(size) > CLASS_B_CHUNK_PAYLOAD_SIZE) { - throw std::invalid_argument("Invalid payload"); - } - - std::array data; - data.fill(0); - - // Write chunk number and payload. - static_assert(CLASS_B_CHUNK_SIZE + 2 == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE, "Chunk size is not in the expected size"); - static_assert(CLASS_B_CHUNK_PAYLOAD_SIZE + 1 == CLASS_B_CHUNK_SIZE, "Payload size is not in the expected size"); - - data[0] = 0x02; // Compressed public key indicator. - data[1] = chunk; - - std::copy(first, last, data.begin() + 2); - - // Obfuscation packet, which is chunk number and payload. - static_assert(std::tuple_size::value == CLASS_B_CHUNK_SIZE, "Size of encryption key must be the same as chunk size"); - - auto it = data.begin() + 1; - - for (unsigned i = 0; i < CLASS_B_CHUNK_SIZE; i++) { - *it++ ^= encKey[i]; - } - - // Fix ECDSA coodinate. - auto fix = static_cast(GetRand(256)); - - for (int i = 0; i < 256; i++, fix++) { - *it = fix; - - CPubKey key(data.begin(), data.end()); - if (key.IsFullyValid()) { - return key; - } - } - - throw std::runtime_error("Failed to generate a valid public key"); - } - -protected: - std::array encKey; -}; - -/** - * Prefix of class C packet. - **/ -extern const std::array magic; - -const CBitcoinAddress& GetSystemAddress(); -boost::optional DeterminePacketClass(const CTransaction& tx, int height); - -/** - * Embedds a payload in obfuscated multisig outputs, then adds P2PKH output to system address. - * - * @see The class B transaction encoding specification: https://github.com/mastercoin-MSC/spec#class-b-transactions-also-known-as-the-multisig-method - **/ -template -Output EncodeClassB(const std::string& sender, const CPubKey& redeemingKey, Payload first, Payload last, Output output) -{ - auto remaining = std::distance(first, last); - PacketKeyGenerator packetKeys(sender); - size_t processed = 0; - unsigned chunk = 1; - - while (remaining > 0) { - // Get number of keys required for payload. - // At most 3 keys per output is allowed. - int generatingKeys = (remaining > static_cast(CLASS_B_CHUNK_PAYLOAD_SIZE)) ? 2 : 1; - - // Put payload in the keys. - std::vector keys = { redeemingKey }; // Always include the redeeming pubkey - - for (int i = 0; i < generatingKeys; i++, chunk++) { - if (chunk > CLASS_B_MAX_CHUNKS) { - throw std::invalid_argument("Payload too large"); - } - - // Get key to encrypt packet. - auto packetKey = packetKeys.Next(); - - static_assert(std::tuple_size::value >= CLASS_B_CHUNK_SIZE, "Size of packet key is less than packet size"); - - // Encode payload. - KeyEncoder encoder(packetKey.begin(), packetKey.end() - (packetKey.size() - CLASS_B_CHUNK_SIZE)); - auto selected = std::min(remaining, static_cast(CLASS_B_CHUNK_PAYLOAD_SIZE)); - - auto encoded = encoder.Encode(static_cast(chunk), first + processed, first + processed + selected); - keys.push_back(std::move(encoded)); - - processed += selected; - remaining -= selected; - } - - // Create output. - auto script = GetScriptForMultisig(1, keys); - *output++ = CTxOut(GetDustThreshold(script), script); - } - - // Add P2PKH output to system address. - auto script = GetScriptForDestination(GetSystemAddress().Get()); - *output++ = CTxOut(GetDustThreshold(script), script); - - return output; -} - -/** - * Embedds a payload in an OP_RETURN output, prefixed with magic bytes. - **/ -template -CTxOut EncodeClassC(Payload first, Payload last) -{ - std::vector data; - CScript script; - - data.insert(data.end(), magic.begin(), magic.end()); - data.insert(data.end(), first, last); - - script << OP_RETURN << data; - - if (script.size() > nMaxDatacarrierBytes) { - throw std::invalid_argument("Payload is too large"); - } - - return CTxOut(0, script); -} - -} // namespace elysium - -namespace std { - -using namespace elysium; - -string to_string(PacketClass c); - -template -basic_ostream& operator<<(basic_ostream& os, PacketClass v) -{ - return os << to_string(v); -} - -} // namespace std - -#endif // FIRO_ELYSIUM_PACKETENCODER_H diff --git a/src/elysium/parse_string.cpp b/src/elysium/parse_string.cpp deleted file mode 100644 index 57eb2bfa6c..0000000000 --- a/src/elysium/parse_string.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "elysium/parse_string.h" - -#include - -#include - -#include -#include - -namespace elysium -{ -int64_t StrToInt64(const std::string& str, bool divisible) -{ - // copy original, so it remains unchanged - std::string strAmount (str); - int64_t nAmount = 0; - - // check for a negative (minus sign) and invalidate if present - size_t negSignPos = strAmount.find("-"); - if (negSignPos != std::string::npos) return 0; - - // convert the string into a usable int64 - if (divisible) { - // check for existance of decimal point - size_t pos = strAmount.find("."); - if (pos == std::string::npos) { - // no decimal point but divisible so pad 8 zeros on right - strAmount += "00000000"; - } else { - // check for existence of second decimal point, if so invalidate amount - size_t posSecond = strAmount.find(".", pos + 1); - if (posSecond != std::string::npos) return 0; - - if ((strAmount.size() - pos) < 9) { - // there are decimals either exact or not enough, pad as needed - std::string strRightOfDecimal = strAmount.substr(pos + 1); - unsigned int zerosToPad = 8 - strRightOfDecimal.size(); - - // do we need to pad? - if (zerosToPad > 0) - { - for (unsigned int it = 0; it != zerosToPad; it++) { - strAmount += "0"; - } - } - } else { - // there are too many decimals, truncate after 8 - strAmount = strAmount.substr(0, pos + 9); - } - } - strAmount.erase(std::remove(strAmount.begin(), strAmount.end(), '.'), strAmount.end()); - try { - nAmount = boost::lexical_cast(strAmount); - } catch (const boost::bad_lexical_cast &e) {} - } else { - size_t pos = strAmount.find("."); - std::string newStrAmount = strAmount.substr(0, pos); - try { - nAmount = boost::lexical_cast(newStrAmount); - } catch (const boost::bad_lexical_cast &e) {} - } - - return nAmount; -} - -} // namespace elysium diff --git a/src/elysium/parse_string.h b/src/elysium/parse_string.h deleted file mode 100644 index a4463f6bd5..0000000000 --- a/src/elysium/parse_string.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ELYSIUM_PARSE_STRING_H -#define ELYSIUM_PARSE_STRING_H - -#include -#include - -namespace elysium -{ -// Converts strings to 64 bit wide interger. -// Divisible and indivisible amounts are accepted. -// 1 indivisible unit equals 0.00000001 divisible units. -// If input string is not a accepted number, 0 is returned. -// Divisible amounts are truncated after 8 decimal places. -// Characters after decimal mark are ignored for indivisible -// amounts. -// Any minus sign invalidates. -int64_t StrToInt64(const std::string& str, bool divisible); -} - - -#endif // ELYSIUM_PARSE_STRING_H diff --git a/src/elysium/pending.cpp b/src/elysium/pending.cpp deleted file mode 100644 index 326de04b25..0000000000 --- a/src/elysium/pending.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "elysium/pending.h" - -#include "elysium/log.h" -#include "elysium/elysium.h" -#include "elysium/sp.h" -#include "elysium/walletcache.h" -#include "elysium/mdex.h" - -#include "amount.h" -#include "validation.h" -#include "sync.h" -#include "txmempool.h" -#include "uint256.h" -#include "ui_interface.h" - -#include - -namespace elysium { - -//! Global map of pending transaction objects -PendingMap my_pending; - -/** - * Adds a transaction to the pending map using supplied parameters. - */ -void PendingAdd(const uint256& txid, const std::string& sendingAddress, uint16_t type, uint32_t propertyId, - int64_t amount, bool fSubtract, const boost::optional &receivingAddress) -{ - if (elysium_debug_pending) PrintToLog("%s(%s,%s,%d,%d,%d,%s)\n", __func__, txid.GetHex(), sendingAddress, type, propertyId, amount, fSubtract); - - // bypass tally update for pending transactions, if there the amount should not be subtracted from the balance (e.g. for cancels) - if (fSubtract) { - if (!update_tally_map(sendingAddress, propertyId, -amount, PENDING)) { - PrintToLog("ERROR - Update tally for pending failed! %s(%s,%s,%d,%d,%d,%s)\n", __func__, txid.GetHex(), sendingAddress, type, propertyId, amount, fSubtract); - return; - } - } - - // add pending object - CMPPending pending; - pending.src = sendingAddress; - pending.amount = amount; - pending.prop = propertyId; - pending.type = type; - pending.dest = receivingAddress; - { - LOCK(cs_main); - my_pending.insert(std::make_pair(txid, pending)); - } - // after adding a transaction to pending the available balance may now be reduced, refresh wallet totals - CheckWalletUpdate(true); // force an update since some outbound pending (eg MetaDEx cancel) may not change balances - uiInterface.ElysiumPendingChanged(true); -} - -/** - * Deletes a transaction from the pending map and credits the amount back to the pending tally for the address. - * - * NOTE: this is currently called for every Firo transaction prior to running through the parser. - */ -void PendingDelete(const uint256& txid) -{ - LOCK(cs_main); - - PendingMap::iterator it = my_pending.find(txid); - if (it != my_pending.end()) { - const CMPPending& pending = it->second; - int64_t src_amount = getMPbalance(pending.src, pending.prop, PENDING); - if (elysium_debug_pending) PrintToLog("%s(%s): amount=%d\n", __FUNCTION__, txid.GetHex(), src_amount); - if (src_amount) update_tally_map(pending.src, pending.prop, pending.amount, PENDING); - my_pending.erase(it); - - // if pending map is now empty following deletion, trigger a status change - if (my_pending.empty()) uiInterface.ElysiumPendingChanged(false); - } -} - -/** - * Performs a check to ensure all pending transactions are still in the mempool. - * - * NOTE: Transactions no longer in the mempool (eg orphaned) are deleted from - * the pending map and credited back to the pending tally. - */ -void PendingCheck() -{ - LOCK(cs_main); - - std::vector vecMemPoolTxids; - mempool.queryHashes(vecMemPoolTxids); - - for (PendingMap::iterator it = my_pending.begin(); it != my_pending.end(); ++it) { - const uint256& txid = it->first; - if (std::find(vecMemPoolTxids.begin(), vecMemPoolTxids.end(), txid) == vecMemPoolTxids.end()) { - PrintToLog("WARNING: Pending transaction %s is no longer in this nodes mempool and will be discarded\n", txid.GetHex()); - PendingDelete(txid); - } - } -} - -} // namespace elysium - -/** - * Prints information about a pending transaction object. - */ -void CMPPending::print(const uint256& txid) const -{ - PrintToLog("%s : %s %d %d %d %s\n", txid.GetHex(), src, prop, amount, type); -} diff --git a/src/elysium/pending.h b/src/elysium/pending.h deleted file mode 100644 index f230ec27cd..0000000000 --- a/src/elysium/pending.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef ELYSIUM_PENDING_H -#define ELYSIUM_PENDING_H - -class uint256; -struct CMPPending; - -#include "sync.h" - -#include - -#include -#include -#include - -namespace elysium -{ -//! Map of pending transaction objects -typedef std::map PendingMap; - -//! Global map of pending transaction objects -extern PendingMap my_pending; - -/** Adds a transaction to the pending map using supplied parameters. */ -void PendingAdd(const uint256& txid, const std::string& sendingAddress, uint16_t type, uint32_t propertyId, - int64_t amount, bool fSubtract = true, const boost::optional &receivingAddress = boost::none); - -/** Deletes a transaction from the pending map and credits the amount back to the pending tally for the address. */ -void PendingDelete(const uint256& txid); - -/** Performs a check to ensure all pending transactions are still in the mempool. */ -void PendingCheck(); - -} - -/** Structure to hold information about pending transactions. - */ -struct CMPPending -{ - std::string src; // the source address - uint32_t prop; - int64_t amount; - uint32_t type; - boost::optional dest; - - /** Default constructor. */ - CMPPending() : prop(0), amount(0), type(0) {}; - - /** Prints information about a pending transaction object. */ - void print(const uint256& txid) const; -}; - - -#endif // ELYSIUM_PENDING_H diff --git a/src/elysium/persistence.cpp b/src/elysium/persistence.cpp deleted file mode 100644 index 8b3f91c292..0000000000 --- a/src/elysium/persistence.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "elysium/persistence.h" - -#include "elysium/log.h" - -#include "util.h" - -#include "leveldb/db.h" -#include "leveldb/write_batch.h" - -#include - -#include - -/** - * Opens or creates a LevelDB based database. - */ -leveldb::Status CDBBase::Open(const boost::filesystem::path& path, bool fWipe) -{ - if (fWipe) { - if (elysium_debug_persistence) PrintToLog("Wiping LevelDB in %s\n", path.string()); - leveldb::DestroyDB(path.string(), options); - } - TryCreateDirectory(path); - if (elysium_debug_persistence) PrintToLog("Opening LevelDB in %s\n", path.string()); - - return leveldb::DB::Open(options, path.string(), &pdb); -} - -/** - * Deletes all entries of the database, and resets the counters. - */ -void CDBBase::Clear() -{ - int64_t nTimeStart = GetTimeMicros(); - unsigned int n = 0; - leveldb::WriteBatch batch; - leveldb::Iterator* it = NewIterator(); - - for (it->SeekToFirst(); it->Valid(); it->Next()) { - batch.Delete(it->key()); - ++n; - } - - delete it; - - leveldb::Status status = pdb->Write(writeoptions, &batch); - nRead = 0; - nWritten = 0; - - int64_t nTime = GetTimeMicros() - nTimeStart; - if (elysium_debug_persistence) - PrintToLog("Removed %d entries: %s [%.3f ms/entry, %.3f ms total]\n", - n, status.ToString(), (n > 0 ? (0.001 * nTime / n) : 0), 0.001 * nTime); -} - -/** - * Deinitializes and closes the database. - */ -void CDBBase::Close() -{ - if (pdb) { - delete pdb; - pdb = NULL; - } -} - - -/** -@todo Move initialization and deinitialization of databases into this file (?) -@todo Move file based storage into this file -@todo Replace file based storage with LevelDB based storage -@todo Wrap global state objects and prevent direct access: - -static CMPTradeList* ptradedb = new CMPTradeList(); - -CMPTradeList& TradeDB() { - assert(ptradedb); - return *ptradedb; -} - -// before: -t_tradelistdb->recordTrade(); - -// after: -TradeDB().recordTrade(); - -*/ diff --git a/src/elysium/persistence.h b/src/elysium/persistence.h deleted file mode 100644 index 9edc8f271b..0000000000 --- a/src/elysium/persistence.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef ELYSIUM_PERSISTENCE_H -#define ELYSIUM_PERSISTENCE_H - -#include "leveldb/db.h" - -#include - -#include -#include - -/** Base class for LevelDB based storage. - */ -class CDBBase -{ -private: - //! Options used when iterating over values of the database - leveldb::ReadOptions iteroptions; - -protected: - //! Database options used - leveldb::Options options; - - //! Options used when reading from the database - leveldb::ReadOptions readoptions; - - //! Options used when writing to the database - leveldb::WriteOptions writeoptions; - - //! Options used when sync writing to the database - leveldb::WriteOptions syncoptions; - - //! The database itself - leveldb::DB* pdb; - - //! Number of entries read - unsigned int nRead; - - //! Number of entries written - unsigned int nWritten; - - CDBBase() : pdb(NULL), nRead(0), nWritten(0) - { - options.paranoid_checks = true; - options.create_if_missing = true; - options.compression = leveldb::kNoCompression; - options.max_open_files = 64; - readoptions.verify_checksums = true; - iteroptions.verify_checksums = true; - iteroptions.fill_cache = false; - syncoptions.sync = true; - } - - virtual ~CDBBase() - { - Close(); - } - - /** - * Creates and returns a new LevelDB iterator. - * - * It is expected that the database is not closed. The iterator is owned by the - * caller, and the object has to be deleted explicitly. - * - * @return A new LevelDB iterator - */ - leveldb::Iterator* NewIterator() const - { - assert(pdb != NULL); - return pdb->NewIterator(iteroptions); - } - - /** - * Opens or creates a LevelDB based database. - * - * If the database is wiped before opening, it's content is destroyed, including - * all log files and meta data. - * - * @param path The path of the database to open - * @param fWipe Whether to wipe the database before opening - * @return A Status object, indicating success or failure - */ - leveldb::Status Open(const boost::filesystem::path& path, bool fWipe = false); - - /** - * Deinitializes and closes the database. - */ - void Close(); - -public: - /** - * Deletes all entries of the database, and resets the counters. - */ - void Clear(); -}; - - -#endif // ELYSIUM_PERSISTENCE_H diff --git a/src/elysium/property.cpp b/src/elysium/property.cpp deleted file mode 100644 index 972d243ffd..0000000000 --- a/src/elysium/property.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "property.h" - -#include "elysium.h" -#include "rules.h" -#include "utilsbitcoin.h" - -#include "../chainparams.h" - -namespace elysium { - -bool IsEnabledFlag(SigmaStatus status) -{ - return status == SigmaStatus::SoftEnabled || status == SigmaStatus::HardEnabled; -} - -bool IsRequireCreationFee(EcosystemId ecosystem) -{ - return IsRequireCreationFee(ecosystem, GetHeight()); -} - -bool IsRequireCreationFee(EcosystemId ecosystem, int block) -{ - return IsRequireCreationFee(ecosystem, block, Params().NetworkIDString()); -} - -bool IsRequireCreationFee(EcosystemId ecosystem, int block, const std::string& network) -{ - if (ecosystem != ELYSIUM_PROPERTY_ELYSIUM) { - return false; - } - - return block >= ConsensusParams(network).PROPERTY_CREATION_FEE_BLOCK; -} - -} // namespace elysium diff --git a/src/elysium/property.h b/src/elysium/property.h deleted file mode 100644 index c30a0e17e8..0000000000 --- a/src/elysium/property.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef FIRO_ELYSIUM_PROPERTY_H -#define FIRO_ELYSIUM_PROPERTY_H - -#include - -#include - -namespace elysium { - -#define TEST_ECO_PROPERTY_1 (0x80000003UL) - -// could probably also use: int64_t maxInt64 = std::numeric_limits::max(); -// maximum numeric values from the spec: -#define MAX_INT_8_BYTES (9223372036854775807UL) - -typedef uint8_t EcosystemId; -typedef uint32_t PropertyId; - -enum class SigmaStatus : uint8_t { - SoftDisabled = 0, - SoftEnabled = 1, - HardDisabled = 2, - HardEnabled = 3 -}; - -bool IsEnabledFlag(SigmaStatus status); -bool IsRequireCreationFee(EcosystemId ecosystem); -bool IsRequireCreationFee(EcosystemId ecosystem, int block); -bool IsRequireCreationFee(EcosystemId ecosystem, int block, const std::string& network); - -} // namespace elysium - -#endif // FIRO_ELYSIUM_PROPERTY_H diff --git a/src/elysium/rpc.cpp b/src/elysium/rpc.cpp deleted file mode 100644 index 9c1db6687d..0000000000 --- a/src/elysium/rpc.cpp +++ /dev/null @@ -1,2464 +0,0 @@ -/** - * @file rpc.cpp - * - * This file contains RPC calls for data retrieval. - */ - -#include "rpc.h" - -#include "activation.h" -#include "consensushash.h" -#include "convert.h" -#include "dex.h" -#include "errors.h" -#include "fees.h" -#include "fetchwallettx.h" -#include "log.h" -#include "mdex.h" -#include "notifications.h" -#include "elysium.h" -#include "rpcrequirements.h" -#include "rpctx.h" -#include "rpctxobject.h" -#include "rpcvalues.h" -#include "rules.h" -#include "sp.h" -#include "sto.h" -#include "tally.h" -#include "tx.h" -#include "utilsbitcoin.h" -#include "version.h" -#include "wallettxs.h" - -#ifdef ENABLE_WALLET -#include "wallet.h" -#include "walletmodels.h" -#endif - -#include "../amount.h" -#include "../chainparams.h" -#include "../init.h" -#include "../validation.h" -#include "../primitives/block.h" -#include "../primitives/transaction.h" -#include "../rpc/server.h" -#include "../tinyformat.h" -#include "../txmempool.h" -#include "../uint256.h" -#include "../utilstrencodings.h" -#ifdef ENABLE_WALLET -#include "../wallet/wallet.h" -#endif - -#include - -#include -#include -#include -#include - -#include - -using std::runtime_error; -using namespace elysium; - -namespace { - -#ifdef ENABLE_WALLET -UniValue SigmaMintToJson(const SigmaMint& mint, bool verbose) -{ - // Load property info. - CMPSPInfo::Entry info; - - { - LOCK(cs_main); - - if (!_my_sps->getSP(mint.property, info)) { - throw std::invalid_argument("property " + std::to_string(mint.property) + " is not valid"); - } - } - - if (mint.denomination >= info.denominations.size()) { - throw std::invalid_argument("denomination " + std::to_string(mint.denomination) + " is not valid"); - } - - auto value = info.denominations[mint.denomination]; - - // Construct JSON. - UniValue json(UniValue::VOBJ); - - json.push_back(Pair("propertyid", static_cast(mint.property))); - json.push_back(Pair("denomination", mint.denomination)); - - if (info.isDivisible()) { - json.push_back(Pair("value", FormatDivisibleMP(value))); - } else { - json.push_back(Pair("value", FormatIndivisibleMP(value))); - } - - if (verbose && mint.chainState.block >= 0) { - json.push_back(Pair("block", mint.chainState.block)); - json.push_back(Pair("group", static_cast(mint.chainState.group))); - json.push_back(Pair("index", mint.chainState.index)); - } - - return json; -} - -template -UniValue SigmaMintsToJson(It begin, It end, bool verbose = false) -{ - UniValue json(UniValue::VARR); - - for (auto it = begin; it != end; it++) { - json.push_back(SigmaMintToJson(*it, verbose)); - } - - return json; -} -#endif - -} - -/** - * Throws a JSONRPCError, depending on error code. - */ -void PopulateFailure(int error) -{ - switch (error) { - case MP_TX_NOT_FOUND: - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); - case MP_TX_UNCONFIRMED: - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unconfirmed transactions are not supported"); - case MP_BLOCK_NOT_IN_CHAIN: - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not part of the active chain"); - case MP_CROWDSALE_WITHOUT_PROPERTY: - throw JSONRPCError(RPC_INTERNAL_ERROR, "Potential database corruption: \ - \"Crowdsale Purchase\" without valid property identifier"); - case MP_INVALID_TX_IN_DB_FOUND: - throw JSONRPCError(RPC_INTERNAL_ERROR, "Potential database corruption: Invalid transaction found"); - case MP_TX_IS_NOT_ELYSIUM_PROTOCOL: - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not a Elysium Protocol transaction"); - } - throw JSONRPCError(RPC_INTERNAL_ERROR, "Generic transaction population failure"); -} - -void PropertyToJSON(const CMPSPInfo::Entry& sProperty, UniValue& property_obj) -{ - property_obj.push_back(Pair("name", sProperty.name)); - property_obj.push_back(Pair("category", sProperty.category)); - property_obj.push_back(Pair("subcategory", sProperty.subcategory)); - property_obj.push_back(Pair("data", sProperty.data)); - property_obj.push_back(Pair("url", sProperty.url)); - property_obj.push_back(Pair("divisible", sProperty.isDivisible())); -} - -void MetaDexObjectToJSON(const CMPMetaDEx& obj, UniValue& metadex_obj) -{ - bool propertyIdForSaleIsDivisible = isPropertyDivisible(obj.getProperty()); - bool propertyIdDesiredIsDivisible = isPropertyDivisible(obj.getDesProperty()); - // add data to JSON object - metadex_obj.push_back(Pair("address", obj.getAddr())); - metadex_obj.push_back(Pair("txid", obj.getHash().GetHex())); - if (obj.getAction() == 4) metadex_obj.push_back(Pair("ecosystem", isTestEcosystemProperty(obj.getProperty()) ? "test" : "main")); - metadex_obj.push_back(Pair("propertyidforsale", (uint64_t) obj.getProperty())); - metadex_obj.push_back(Pair("propertyidforsaleisdivisible", propertyIdForSaleIsDivisible)); - metadex_obj.push_back(Pair("amountforsale", FormatMP(obj.getProperty(), obj.getAmountForSale()))); - metadex_obj.push_back(Pair("amountremaining", FormatMP(obj.getProperty(), obj.getAmountRemaining()))); - metadex_obj.push_back(Pair("propertyiddesired", (uint64_t) obj.getDesProperty())); - metadex_obj.push_back(Pair("propertyiddesiredisdivisible", propertyIdDesiredIsDivisible)); - metadex_obj.push_back(Pair("amountdesired", FormatMP(obj.getDesProperty(), obj.getAmountDesired()))); - metadex_obj.push_back(Pair("amounttofill", FormatMP(obj.getDesProperty(), obj.getAmountToFill()))); - metadex_obj.push_back(Pair("action", (int) obj.getAction())); - metadex_obj.push_back(Pair("block", obj.getBlock())); - metadex_obj.push_back(Pair("blocktime", obj.getBlockTime())); -} - -void MetaDexObjectsToJSON(std::vector& vMetaDexObjs, UniValue& response) -{ - MetaDEx_compare compareByHeight; - - // sorts metadex objects based on block height and position in block - std::sort (vMetaDexObjs.begin(), vMetaDexObjs.end(), compareByHeight); - - for (std::vector::const_iterator it = vMetaDexObjs.begin(); it != vMetaDexObjs.end(); ++it) { - UniValue metadex_obj(UniValue::VOBJ); - MetaDexObjectToJSON(*it, metadex_obj); - - response.push_back(metadex_obj); - } -} - -bool BalanceToJSON(const std::string& address, uint32_t property, UniValue& balance_obj, bool divisible) -{ - // confirmed balance minus unconfirmed, spent amounts - int64_t nAvailable = getUserAvailableMPbalance(address, property); - - int64_t nReserved = 0; - nReserved += getMPbalance(address, property, ACCEPT_RESERVE); - nReserved += getMPbalance(address, property, METADEX_RESERVE); - nReserved += getMPbalance(address, property, SELLOFFER_RESERVE); - - int64_t nFrozen = getUserFrozenMPbalance(address, property); - - if (divisible) { - balance_obj.push_back(Pair("balance", FormatDivisibleMP(nAvailable))); - balance_obj.push_back(Pair("reserved", FormatDivisibleMP(nReserved))); - if (nFrozen != 0) balance_obj.push_back(Pair("frozen", FormatDivisibleMP(nFrozen))); - } else { - balance_obj.push_back(Pair("balance", FormatIndivisibleMP(nAvailable))); - balance_obj.push_back(Pair("reserved", FormatIndivisibleMP(nReserved))); - if (nFrozen != 0) balance_obj.push_back(Pair("frozen", FormatIndivisibleMP(nFrozen))); - } - - if (nAvailable == 0 && nReserved == 0) { - return false; - } else { - return true; - } -} - -// Obtains details of a fee distribution -UniValue elysium_getfeedistribution(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_getfeedistribution distributionid\n" - "\nGet the details for a fee distribution.\n" - "\nArguments:\n" - "1. distributionid (number, required) the distribution to obtain details for\n" - "\nResult:\n" - "{\n" - " \"distributionid\" : n, (number) the distribution id\n" - " \"propertyid\" : n, (number) the property id of the distributed tokens\n" - " \"block\" : n, (number) the block the distribution occurred\n" - " \"amount\" : \"n.nnnnnnnn\", (string) the amount that was distributed\n" - " \"recipients\": [ (array of JSON objects) a list of recipients\n" - " {\n" - " \"address\" : \"address\", (string) the address of the recipient\n" - " \"amount\" : \"n.nnnnnnnn\" (string) the amount of fees received by the recipient\n" - " },\n" - " ...\n" - " ]\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getfeedistribution", "1") - + HelpExampleRpc("elysium_getfeedistribution", "1") - ); - - int id = request.params[0].get_int(); - - int block = 0; - uint32_t propertyId = 0; - int64_t total = 0; - - UniValue response(UniValue::VOBJ); - - bool found = p_feehistory->GetDistributionData(id, &propertyId, &block, &total); - if (!found) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee distribution ID does not exist"); - } - response.push_back(Pair("distributionid", id)); - response.push_back(Pair("propertyid", (uint64_t)propertyId)); - response.push_back(Pair("block", block)); - response.push_back(Pair("amount", FormatMP(propertyId, total))); - UniValue recipients(UniValue::VARR); - std::set > sRecipients = p_feehistory->GetFeeDistribution(id); - bool divisible = isPropertyDivisible(propertyId); - if (!sRecipients.empty()) { - for (std::set >::iterator it = sRecipients.begin(); it != sRecipients.end(); it++) { - std::string address = (*it).first; - int64_t amount = (*it).second; - UniValue recipient(UniValue::VOBJ); - recipient.push_back(Pair("address", address)); - if (divisible) { - recipient.push_back(Pair("amount", FormatDivisibleMP(amount))); - } else { - recipient.push_back(Pair("amount", FormatIndivisibleMP(amount))); - } - recipients.push_back(recipient); - } - } - response.push_back(Pair("recipients", recipients)); - return response; -} - -// Obtains all fee distributions for a property -// TODO : Split off code to populate a fee distribution object into a seperate function -UniValue elysium_getfeedistributions(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_getfeedistributions propertyid\n" - "\nGet the details of all fee distributions for a property.\n" - "\nArguments:\n" - "1. propertyid (number, required) the property id to retrieve distributions for\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"distributionid\" : n, (number) the distribution id\n" - " \"propertyid\" : n, (number) the property id of the distributed tokens\n" - " \"block\" : n, (number) the block the distribution occurred\n" - " \"amount\" : \"n.nnnnnnnn\", (string) the amount that was distributed\n" - " \"recipients\": [ (array of JSON objects) a list of recipients\n" - " {\n" - " \"address\" : \"address\", (string) the address of the recipient\n" - " \"amount\" : \"n.nnnnnnnn\" (string) the amount of fees received by the recipient\n" - " },\n" - " ...\n" - " }\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getfeedistributions", "1") - + HelpExampleRpc("elysium_getfeedistributions", "1") - ); - - uint32_t prop = ParsePropertyId(request.params[0]); - RequireExistingProperty(prop); - - UniValue response(UniValue::VARR); - - std::set sDistributions = p_feehistory->GetDistributionsForProperty(prop); - if (!sDistributions.empty()) { - for (std::set::iterator it = sDistributions.begin(); it != sDistributions.end(); it++) { - int id = *it; - int block = 0; - uint32_t propertyId = 0; - int64_t total = 0; - UniValue responseObj(UniValue::VOBJ); - bool found = p_feehistory->GetDistributionData(id, &propertyId, &block, &total); - if (!found) { - PrintToLog("Fee History Error - Distribution data not found for distribution ID %d but it was included in GetDistributionsForProperty(prop %d)\n", id, prop); - continue; - } - responseObj.push_back(Pair("distributionid", id)); - responseObj.push_back(Pair("propertyid", (uint64_t)propertyId)); - responseObj.push_back(Pair("block", block)); - responseObj.push_back(Pair("amount", FormatMP(propertyId, total))); - UniValue recipients(UniValue::VARR); - std::set > sRecipients = p_feehistory->GetFeeDistribution(id); - bool divisible = isPropertyDivisible(propertyId); - if (!sRecipients.empty()) { - for (std::set >::iterator it = sRecipients.begin(); it != sRecipients.end(); it++) { - std::string address = (*it).first; - int64_t amount = (*it).second; - UniValue recipient(UniValue::VOBJ); - recipient.push_back(Pair("address", address)); - if (divisible) { - recipient.push_back(Pair("amount", FormatDivisibleMP(amount))); - } else { - recipient.push_back(Pair("amount", FormatIndivisibleMP(amount))); - } - recipients.push_back(recipient); - } - } - responseObj.push_back(Pair("recipients", recipients)); - response.push_back(responseObj); - } - } - return response; -} - -// Obtains the trigger value for fee distribution for a/all properties -UniValue elysium_getfeetrigger(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() > 1) - throw runtime_error( - "elysium_getfeetrigger ( propertyid )\n" - "\nReturns the amount of fees required in the cache to trigger distribution.\n" - "\nArguments:\n" - "1. propertyid (number, optional) filter the results on this property id\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"propertyid\" : nnnnnnn, (number) the property id\n" - " \"feetrigger\" : \"n.nnnnnnnn\", (string) the amount of fees required to trigger distribution\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getfeetrigger", "3") - + HelpExampleRpc("elysium_getfeetrigger", "3") - ); - - uint32_t propertyId = 0; - if (0 < request.params.size()) { - propertyId = ParsePropertyId(request.params[0]); - } - - if (propertyId > 0) { - RequireExistingProperty(propertyId); - } - - UniValue response(UniValue::VARR); - - for (uint8_t ecosystem = 1; ecosystem <= 2; ecosystem++) { - uint32_t startPropertyId = (ecosystem == 1) ? 1 : TEST_ECO_PROPERTY_1; - for (uint32_t itPropertyId = startPropertyId; itPropertyId < _my_sps->peekNextSPID(ecosystem); itPropertyId++) { - if (propertyId == 0 || propertyId == itPropertyId) { - int64_t feeTrigger = p_feecache->GetDistributionThreshold(itPropertyId); - std::string strFeeTrigger = FormatMP(itPropertyId, feeTrigger); - UniValue cacheObj(UniValue::VOBJ); - cacheObj.push_back(Pair("propertyid", (uint64_t)itPropertyId)); - cacheObj.push_back(Pair("feetrigger", strFeeTrigger)); - response.push_back(cacheObj); - } - } - } - - return response; -} - -// Provides the fee share the wallet (or specific address) will receive from fee distributions -UniValue elysium_getfeeshare(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() > 2) - throw runtime_error( - "elysium_getfeeshare ( address ecosystem )\n" - "\nReturns the percentage share of fees distribution applied to the wallet (default) or address (if supplied).\n" - "\nArguments:\n" - "1. address (string, optional) retrieve the fee share for the supplied address\n" - "2. ecosystem (number, optional) the ecosystem to check the fee share (1 for main ecosystem, 2 for test ecosystem)\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"address\" : nnnnnnn, (number) the property id\n" - " \"feeshare\" : \"n.nnnnnnnn\", (string) the percentage of fees this address will receive based on current state\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getfeeshare", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\" 1") - + HelpExampleRpc("elysium_getfeeshare", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\", 1") - ); - - std::string address; - uint8_t ecosystem = 1; - if (0 < request.params.size()) { - if ("*" != request.params[0].get_str()) { //ParseAddressOrEmpty doesn't take wildcards - address = ParseAddressOrEmpty(request.params[0]); - } else { - address = "*"; - } - } - if (1 < request.params.size()) { - ecosystem = ParseEcosystem(request.params[1]); - } - - UniValue response(UniValue::VARR); - bool addObj = false; - - OwnerAddrType receiversSet; - if (ecosystem == 1) { - receiversSet = STO_GetReceivers("FEEDISTRIBUTION", ELYSIUM_PROPERTY_ELYSIUM, COIN); - } else { - receiversSet = STO_GetReceivers("FEEDISTRIBUTION", ELYSIUM_PROPERTY_TELYSIUM, COIN); - } - - for (OwnerAddrType::reverse_iterator it = receiversSet.rbegin(); it != receiversSet.rend(); ++it) { - addObj = false; - if (address.empty()) { - if (IsMyAddress(it->second)) { - addObj = true; - } - } else if (address == it->second || address == "*") { - addObj = true; - } - if (addObj) { - UniValue feeShareObj(UniValue::VOBJ); - // NOTE: using float here as this is a display value only which isn't an exact percentage and - // changes block to block (due to dev Elysium) so high precision not required(?) - double feeShare = (double(it->first) / double(COIN)) * (double)100; - std::string strFeeShare = strprintf("%.4f", feeShare); - strFeeShare += "%"; - feeShareObj.push_back(Pair("address", it->second)); - feeShareObj.push_back(Pair("feeshare", strFeeShare)); - response.push_back(feeShareObj); - } - } - - return response; -} - -// Provides the current values of the fee cache -UniValue elysium_getfeecache(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() > 1) - throw runtime_error( - "elysium_getfeecache ( propertyid )\n" - "\nReturns the amount of fees cached for distribution.\n" - "\nArguments:\n" - "1. propertyid (number, optional) filter the results on this property id\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"propertyid\" : nnnnnnn, (number) the property id\n" - " \"cachedfees\" : \"n.nnnnnnnn\", (string) the amount of fees cached for this property\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getfeecache", "31") - + HelpExampleRpc("elysium_getfeecache", "31") - ); - - uint32_t propertyId = 0; - if (0 < request.params.size()) { - propertyId = ParsePropertyId(request.params[0]); - } - - if (propertyId > 0) { - RequireExistingProperty(propertyId); - } - - UniValue response(UniValue::VARR); - - for (uint8_t ecosystem = 1; ecosystem <= 2; ecosystem++) { - uint32_t startPropertyId = (ecosystem == 1) ? 1 : TEST_ECO_PROPERTY_1; - for (uint32_t itPropertyId = startPropertyId; itPropertyId < _my_sps->peekNextSPID(ecosystem); itPropertyId++) { - if (propertyId == 0 || propertyId == itPropertyId) { - int64_t cachedFee = p_feecache->GetCachedAmount(itPropertyId); - if (cachedFee == 0) { - // filter empty results unless the call specifically requested this property - if (propertyId != itPropertyId) continue; - } - std::string strFee = FormatMP(itPropertyId, cachedFee); - UniValue cacheObj(UniValue::VOBJ); - cacheObj.push_back(Pair("propertyid", (uint64_t)itPropertyId)); - cacheObj.push_back(Pair("cachedfees", strFee)); - response.push_back(cacheObj); - } - } - } - - return response; -} - -// generate a list of seed blocks based on the data in LevelDB -UniValue elysium_getseedblocks(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_getseedblocks startblock endblock\n" - "\nReturns a list of blocks containing Elysium transactions for use in seed block filtering.\n" - "\nWARNING: The Elysium crowdsale is not stored in LevelDB, thus this is currently only safe to use to generate seed blocks after block 255365." - "\nArguments:\n" - "1. startblock (number, required) the first block to look for Elysium transactions (inclusive)\n" - "2. endblock (number, required) the last block to look for Elysium transactions (inclusive)\n" - "\nResult:\n" - "[ (array of numbers) a list of seed blocks\n" - " nnnnnn, (number) the block height of the seed block\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getseedblocks", "290000 300000") - + HelpExampleRpc("elysium_getseedblocks", "290000, 300000") - ); - - int startHeight = request.params[0].get_int(); - int endHeight = request.params[1].get_int(); - - RequireHeightInChain(startHeight); - RequireHeightInChain(endHeight); - - UniValue response(UniValue::VARR); - - { - LOCK(cs_main); - std::set setSeedBlocks = p_txlistdb->GetSeedBlocks(startHeight, endHeight); - for (std::set::const_iterator it = setSeedBlocks.begin(); it != setSeedBlocks.end(); ++it) { - response.push_back(*it); - } - } - - return response; -} - -// obtain the payload for a transaction -UniValue elysium_getpayload(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_getpayload \"txid\"\n" - "\nGet the payload for an Elysium transaction.\n" - "\nArguments:\n" - "1. txid (string, required) the hash of the transaction to retrieve payload\n" - "\nResult:\n" - "{\n" - " \"payload\" : \"payloadmessage\", (string) the decoded Elysium payload message\n" - " \"payloadsize\" : n (number) the size of the payload\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getpayload", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") - + HelpExampleRpc("elysium_getpayload", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") - ); - - uint256 txid = ParseHashV(request.params[0], "txid"); - - CTransactionRef tx; - uint256 blockHash; - if (!GetTransaction(txid, tx, Params().GetConsensus(), blockHash, true)) { - PopulateFailure(MP_TX_NOT_FOUND); - } - - int blockTime = 0; - int blockHeight = GetHeight(); - if (!blockHash.IsNull()) { - CBlockIndex* pBlockIndex = GetBlockIndex(blockHash); - if (NULL != pBlockIndex) { - blockTime = pBlockIndex->nTime; - blockHeight = pBlockIndex->nHeight; - } - } - - CMPTransaction mp_obj; - int parseRC = ParseTransaction(*tx, blockHeight, 0, mp_obj, blockTime); - if (parseRC < 0) PopulateFailure(MP_TX_IS_NOT_ELYSIUM_PROTOCOL); - - auto& payload = mp_obj.getRaw(); - UniValue payloadObj(UniValue::VOBJ); - payloadObj.push_back(Pair("payload", HexStr(payload))); - payloadObj.push_back(Pair("payloadsize", int64_t(payload.size()))); - return payloadObj; -} - -// determine whether to automatically commit transactions -UniValue elysium_setautocommit(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_setautocommit flag\n" - "\nSets the global flag that determines whether transactions are automatically committed and broadcast.\n" - "\nArguments:\n" - "1. flag (boolean, required) the flag\n" - "\nResult:\n" - "true|false (boolean) the updated flag status\n" - "\nExamples:\n" - + HelpExampleCli("elysium_setautocommit", "false") - + HelpExampleRpc("elysium_setautocommit", "false") - ); - - LOCK(cs_main); - - autoCommit = request.params[0].get_bool(); - return autoCommit; -} - -// display the tally map & the offer/accept list(s) -UniValue elysiumrpc(const JSONRPCRequest& request) -{ - int extra = 0; - int extra2 = 0, extra3 = 0; - - if (request.fHelp || request.params.size() > 3) - throw runtime_error( - "elysiumrpc\n" - "\nReturns the number of blocks in the longest block chain.\n" - "\nResult:\n" - "n (number) the current block count\n" - "\nExamples:\n" - + HelpExampleCli("elysiumrpc", "") - + HelpExampleRpc("elysiumrpc", "") - ); - - if (0 < request.params.size()) extra = atoi(request.params[0].get_str()); - if (1 < request.params.size()) extra2 = atoi(request.params[1].get_str()); - if (2 < request.params.size()) extra3 = atoi(request.params[2].get_str()); - - PrintToLog("%s(extra=%d,extra2=%d,extra3=%d)\n", __FUNCTION__, extra, extra2, extra3); - - bool bDivisible = isPropertyDivisible(extra2); - - // various extra tests - switch (extra) { - case 0: - { - LOCK(cs_main); - int64_t total = 0; - // display all balances - for (std::unordered_map::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) { - PrintToLog("%34s => ", my_it->first); - total += (my_it->second).print(extra2, bDivisible); - } - PrintToLog("total for property %d = %X is %s\n", extra2, extra2, FormatDivisibleMP(total)); - break; - } - case 1: - { - LOCK(cs_main); - // display the whole CMPTxList (leveldb) - p_txlistdb->printAll(); - p_txlistdb->printStats(); - break; - } - case 2: - { - LOCK(cs_main); - // display smart properties - _my_sps->printAll(); - break; - } - case 3: - { - LOCK(cs_main); - uint32_t id = 0; - // for each address display all currencies it holds - for (std::unordered_map::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) { - PrintToLog("%34s => ", my_it->first); - (my_it->second).print(extra2); - (my_it->second).init(); - while (0 != (id = (my_it->second).next())) { - PrintToLog("Id: %u=0x%X ", id, id); - } - PrintToLog("\n"); - } - break; - } - case 4: - { - LOCK(cs_main); - for (CrowdMap::const_iterator it = my_crowds.begin(); it != my_crowds.end(); ++it) { - (it->second).print(it->first); - } - break; - } - case 5: - { - LOCK(cs_main); - PrintToLog("isMPinBlockRange(%d,%d)=%s\n", extra2, extra3, isMPinBlockRange(extra2, extra3, false) ? "YES" : "NO"); - break; - } - case 6: - { - LOCK(cs_main); - MetaDEx_debug_print(true, true); - break; - } - case 7: - { - LOCK(cs_main); - // display the whole CMPTradeList (leveldb) - t_tradelistdb->printAll(); - t_tradelistdb->printStats(); - break; - } - case 8: - { - LOCK(cs_main); - // display the STO receive list - s_stolistdb->printAll(); - s_stolistdb->printStats(); - break; - } - case 10: - { - PrintToLog("Locking cs_main for %d milliseconds..\n", extra2); - LOCK(cs_main); - MilliSleep(extra2); - PrintToLog("Unlocking cs_main now\n"); - break; - } -#ifdef ENABLE_WALLET - case 11: - { - PrintToLog("Locking pwalletMain->cs_wallet for %d milliseconds..\n", extra2); - LOCK(pwalletMain->cs_wallet); - MilliSleep(extra2); - PrintToLog("Unlocking pwalletMain->cs_wallet now\n"); - break; - } -#endif - case 14: - { - LOCK(cs_main); - p_feecache->printAll(); - p_feecache->printStats(); - - int64_t a = 1000; - int64_t b = 1999; - int64_t c = 2001; - int64_t d = 20001; - int64_t e = 19999; - - int64_t z = 2000; - - int64_t aa = a/z; - int64_t bb = b/z; - int64_t cc = c/z; - int64_t dd = d/z; - int64_t ee = e/z; - - PrintToLog("%d / %d = %d\n",a,z,aa); - PrintToLog("%d / %d = %d\n",b,z,bb); - PrintToLog("%d / %d = %d\n",c,z,cc); - PrintToLog("%d / %d = %d\n",d,z,dd); - PrintToLog("%d / %d = %d\n",e,z,ee); - - break; - } - default: - break; - } - - return GetHeight(); -} - -// display an MP balance via RPC -UniValue elysium_getbalance(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_getbalance \"address\" propertyid\n" - "\nReturns the token balance for a given address and property.\n" - "\nArguments:\n" - "1. address (string, required) the address\n" - "2. propertyid (number, required) the property identifier\n" - "\nResult:\n" - "{\n" - " \"balance\" : \"n.nnnnnnnn\", (string) the available balance of the address\n" - " \"reserved\" : \"n.nnnnnnnn\" (string) the amount reserved by sell offers and accepts\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getbalance", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\" 1") - + HelpExampleRpc("elysium_getbalance", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\", 1") - ); - - std::string address = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - - RequireExistingProperty(propertyId); - - UniValue balanceObj(UniValue::VOBJ); - BalanceToJSON(address, propertyId, balanceObj, isPropertyDivisible(propertyId)); - - return balanceObj; -} - -UniValue elysium_getallbalancesforid(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_getallbalancesforid propertyid\n" - "\nReturns a list of token balances for a given currency or property identifier.\n" - "\nArguments:\n" - "1. propertyid (number, required) the property identifier\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"address\" : \"address\", (string) the address\n" - " \"balance\" : \"n.nnnnnnnn\", (string) the available balance of the address\n" - " \"reserved\" : \"n.nnnnnnnn\" (string) the amount reserved by sell offers and accepts\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getallbalancesforid", "1") - + HelpExampleRpc("elysium_getallbalancesforid", "1") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - - RequireExistingProperty(propertyId); - - UniValue response(UniValue::VARR); - bool isDivisible = isPropertyDivisible(propertyId); // we want to check this BEFORE the loop - - LOCK(cs_main); - - for (std::unordered_map::iterator it = mp_tally_map.begin(); it != mp_tally_map.end(); ++it) { - uint32_t id = 0; - bool includeAddress = false; - std::string address = it->first; - (it->second).init(); - while (0 != (id = (it->second).next())) { - if (id == propertyId) { - includeAddress = true; - break; - } - } - if (!includeAddress) { - continue; // ignore this address, has never transacted in this propertyId - } - UniValue balanceObj(UniValue::VOBJ); - balanceObj.push_back(Pair("address", address)); - bool nonEmptyBalance = BalanceToJSON(address, propertyId, balanceObj, isDivisible); - - if (nonEmptyBalance) { - response.push_back(balanceObj); - } - } - - return response; -} - -UniValue elysium_getallbalancesforaddress(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_getallbalancesforaddress \"address\"\n" - "\nReturns a list of all token balances for a given address.\n" - "\nArguments:\n" - "1. address (string, required) the address\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"propertyid\" : n, (number) the property identifier\n" - " \"balance\" : \"n.nnnnnnnn\", (string) the available balance of the address\n" - " \"reserved\" : \"n.nnnnnnnn\" (string) the amount reserved by sell offers and accepts\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getallbalancesforaddress", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\"") - + HelpExampleRpc("elysium_getallbalancesforaddress", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\"") - ); - - std::string address = ParseAddress(request.params[0]); - - UniValue response(UniValue::VARR); - - LOCK(cs_main); - - CMPTally* addressTally = getTally(address); - - if (NULL == addressTally) { // addressTally object does not exist - throw JSONRPCError(RPC_INVALID_PARAMETER, "Address not found"); - } - - addressTally->init(); - - uint32_t propertyId = 0; - while (0 != (propertyId = addressTally->next())) { - UniValue balanceObj(UniValue::VOBJ); - balanceObj.push_back(Pair("propertyid", (uint64_t) propertyId)); - bool nonEmptyBalance = BalanceToJSON(address, propertyId, balanceObj, isPropertyDivisible(propertyId)); - - if (nonEmptyBalance) { - response.push_back(balanceObj); - } - } - - return response; -} - -UniValue elysium_getproperty(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_getproperty propertyid\n" - "\nReturns details for about the tokens or smart property to lookup.\n" - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the tokens or property\n" - "\nResult:\n" - "{\n" - " \"propertyid\" : n, (number) the identifier\n" - " \"name\" : \"name\", (string) the name of the tokens\n" - " \"category\" : \"category\", (string) the category used for the tokens\n" - " \"subcategory\" : \"subcategory\", (string) the subcategory used for the tokens\n" - " \"data\" : \"information\", (string) additional information or a description\n" - " \"url\" : \"uri\", (string) an URI, for example pointing to a website\n" - " \"divisible\" : true|false, (boolean) whether the tokens are divisible\n" - " \"issuer\" : \"address\", (string) the Firo address of the issuer on record\n" - " \"creationtxid\" : \"hash\", (string) the hex-encoded creation transaction hash\n" - " \"fixedissuance\" : true|false, (boolean) whether the token supply is fixed\n" - " \"managedissuance\" : true|false, (boolean) whether the token supply is managed\n" - " \"totaltokens\" : \"n.nnnnnnnn\", (string) the total number of tokens in existence\n" - " \"sigmastatus\" : \"status\", (string) the sigma status of the tokens\n" - " \"denominations\": [ (array of JSON objects) a list of sigma denominations\n" - " {\n" - " \"id\" : n (number) the identifier of the denomination\n" - " \"value\" : \"n.nnnnnnnn\" (string) the value of the denomination\n" - " },\n" - " ...\n" - " ]\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getproperty", "3") - + HelpExampleRpc("elysium_getproperty", "3") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - - RequireExistingProperty(propertyId); - - CMPSPInfo::Entry sp; - { - LOCK(cs_main); - if (!_my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property identifier does not exist"); - } - } - int64_t nTotalTokens = getTotalTokens(propertyId); - std::string strCreationHash = sp.txid.GetHex(); - std::string strTotalTokens = FormatMP(propertyId, nTotalTokens); - - UniValue response(UniValue::VOBJ); - response.push_back(Pair("propertyid", (uint64_t) propertyId)); - PropertyToJSON(sp, response); // name, category, subcategory, data, url, divisible - response.push_back(Pair("issuer", sp.issuer)); - response.push_back(Pair("creationtxid", strCreationHash)); - response.push_back(Pair("fixedissuance", sp.fixed)); - response.push_back(Pair("managedissuance", sp.manual)); - if (sp.manual) { - int currentBlock = GetHeight(); - LOCK(cs_main); - response.push_back(Pair("freezingenabled", isFreezingEnabled(propertyId, currentBlock))); - } - response.push_back(Pair("totaltokens", strTotalTokens)); - - try { - response.push_back(Pair("sigmastatus", std::to_string(sp.sigmaStatus))); - } catch (const std::invalid_argument& e) { - // status is invalid - throw JSONRPCError(RPC_INTERNAL_ERROR, e.what()); - } - - UniValue denominations(UniValue::VARR); - for (size_t i = 0; i < sp.denominations.size(); i++) { - UniValue denomination(UniValue::VOBJ); - denomination.push_back(Pair("id", int64_t(i))); - denomination.push_back(Pair("value", FormatMP(propertyId, sp.denominations[i]))); - denominations.push_back(denomination); - } - - response.push_back(Pair("denominations", denominations)); - - return response; -} - -UniValue elysium_listproperties(const JSONRPCRequest& request) -{ - if (request.fHelp) - throw runtime_error( - "elysium_listproperties\n" - "\nLists all tokens or smart properties.\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"propertyid\" : n, (number) the identifier of the tokens\n" - " \"name\" : \"name\", (string) the name of the tokens\n" - " \"category\" : \"category\", (string) the category used for the tokens\n" - " \"subcategory\" : \"subcategory\", (string) the subcategory used for the tokens\n" - " \"data\" : \"information\", (string) additional information or a description\n" - " \"url\" : \"uri\", (string) an URI, for example pointing to a website\n" - " \"divisible\" : true|false (boolean) whether the tokens are divisible\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_listproperties", "") - + HelpExampleRpc("elysium_listproperties", "") - ); - - UniValue response(UniValue::VARR); - - LOCK(cs_main); - - uint32_t nextSPID = _my_sps->peekNextSPID(1); - for (uint32_t propertyId = 1; propertyId < nextSPID; propertyId++) { - CMPSPInfo::Entry sp; - if (_my_sps->getSP(propertyId, sp)) { - UniValue propertyObj(UniValue::VOBJ); - propertyObj.push_back(Pair("propertyid", (uint64_t) propertyId)); - PropertyToJSON(sp, propertyObj); // name, category, subcategory, data, url, divisible - - response.push_back(propertyObj); - } - } - - uint32_t nextTestSPID = _my_sps->peekNextSPID(2); - for (uint32_t propertyId = TEST_ECO_PROPERTY_1; propertyId < nextTestSPID; propertyId++) { - CMPSPInfo::Entry sp; - if (_my_sps->getSP(propertyId, sp)) { - UniValue propertyObj(UniValue::VOBJ); - propertyObj.push_back(Pair("propertyid", (uint64_t) propertyId)); - PropertyToJSON(sp, propertyObj); // name, category, subcategory, data, url, divisible - - response.push_back(propertyObj); - } - } - - return response; -} - -UniValue elysium_getcrowdsale(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( - "elysium_getcrowdsale propertyid ( verbose )\n" - "\nReturns information about a crowdsale.\n" - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the crowdsale\n" - "2. verbose (boolean, optional) list crowdsale participants (default: false)\n" - "\nResult:\n" - "{\n" - " \"propertyid\" : n, (number) the identifier of the crowdsale\n" - " \"name\" : \"name\", (string) the name of the tokens issued via the crowdsale\n" - " \"active\" : true|false, (boolean) whether the crowdsale is still active\n" - " \"issuer\" : \"address\", (string) the Firo address of the issuer on record\n" - " \"propertyiddesired\" : n, (number) the identifier of the tokens eligible to participate in the crowdsale\n" - " \"tokensperunit\" : \"n.nnnnnnnn\", (string) the amount of tokens granted per unit invested in the crowdsale\n" - " \"earlybonus\" : n, (number) an early bird bonus for participants in percent per week\n" - " \"percenttoissuer\" : n, (number) a percentage of tokens that will be granted to the issuer\n" - " \"starttime\" : nnnnnnnnnn, (number) the start time of the of the crowdsale as Unix timestamp\n" - " \"deadline\" : nnnnnnnnnn, (number) the deadline of the crowdsale as Unix timestamp\n" - " \"amountraised\" : \"n.nnnnnnnn\", (string) the amount of tokens invested by participants\n" - " \"tokensissued\" : \"n.nnnnnnnn\", (string) the total number of tokens issued via the crowdsale\n" - " \"addedissuertokens\" : \"n.nnnnnnnn\", (string) the amount of tokens granted to the issuer as bonus\n" - " \"closedearly\" : true|false, (boolean) whether the crowdsale ended early (if not active)\n" - " \"maxtokens\" : true|false, (boolean) whether the crowdsale ended early due to reaching the limit of max. issuable tokens (if not active)\n" - " \"endedtime\" : nnnnnnnnnn, (number) the time when the crowdsale ended (if closed early)\n" - " \"closetx\" : \"hash\", (string) the hex-encoded hash of the transaction that closed the crowdsale (if closed manually)\n" - " \"participanttransactions\": [ (array of JSON objects) a list of crowdsale participations (if verbose=true)\n" - " {\n" - " \"txid\" : \"hash\", (string) the hex-encoded hash of participation transaction\n" - " \"amountsent\" : \"n.nnnnnnnn\", (string) the amount of tokens invested by the participant\n" - " \"participanttokens\" : \"n.nnnnnnnn\", (string) the tokens granted to the participant\n" - " \"issuertokens\" : \"n.nnnnnnnn\" (string) the tokens granted to the issuer as bonus\n" - " },\n" - " ...\n" - " ]\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getcrowdsale", "3 true") - + HelpExampleRpc("elysium_getcrowdsale", "3, true") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - bool showVerbose = (request.params.size() > 1) ? request.params[1].get_bool() : false; - - RequireExistingProperty(propertyId); - RequireCrowdsale(propertyId); - - CMPSPInfo::Entry sp; - { - LOCK(cs_main); - if (!_my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property identifier does not exist"); - } - } - - const uint256& creationHash = sp.txid; - - CTransactionRef tx; - uint256 hashBlock; - if (!GetTransaction(creationHash, tx, Params().GetConsensus(), hashBlock, true)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); - } - - UniValue response(UniValue::VOBJ); - bool active = isCrowdsaleActive(propertyId); - std::map > database; - - if (active) { - bool crowdFound = false; - - LOCK(cs_main); - - for (CrowdMap::const_iterator it = my_crowds.begin(); it != my_crowds.end(); ++it) { - const CMPCrowd& crowd = it->second; - if (propertyId == crowd.getPropertyId()) { - crowdFound = true; - database = crowd.getDatabase(); - } - } - if (!crowdFound) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Crowdsale is flagged active but cannot be retrieved"); - } - } else { - database = sp.historicalData; - } - - int64_t tokensIssued = getTotalTokens(propertyId); - const std::string& txidClosed = sp.txid_close.GetHex(); - - int64_t startTime = -1; - if (!hashBlock.IsNull() && GetBlockIndex(hashBlock)) { - startTime = GetBlockIndex(hashBlock)->nTime; - } - - // note the database is already deserialized here and there is minimal performance penalty to iterate recipients to calculate amountRaised - int64_t amountRaised = 0; - uint16_t propertyIdType = isPropertyDivisible(propertyId) ? ELYSIUM_PROPERTY_TYPE_DIVISIBLE : ELYSIUM_PROPERTY_TYPE_INDIVISIBLE; - uint16_t desiredIdType = isPropertyDivisible(sp.property_desired) ? ELYSIUM_PROPERTY_TYPE_DIVISIBLE : ELYSIUM_PROPERTY_TYPE_INDIVISIBLE; - std::map sortMap; - for (std::map >::const_iterator it = database.begin(); it != database.end(); it++) { - UniValue participanttx(UniValue::VOBJ); - std::string txid = it->first.GetHex(); - amountRaised += it->second.at(0); - participanttx.push_back(Pair("txid", txid)); - participanttx.push_back(Pair("amountsent", FormatByType(it->second.at(0), desiredIdType))); - participanttx.push_back(Pair("participanttokens", FormatByType(it->second.at(2), propertyIdType))); - participanttx.push_back(Pair("issuertokens", FormatByType(it->second.at(3), propertyIdType))); - std::string sortKey = strprintf("%d-%s", it->second.at(1), txid); - sortMap.insert(std::make_pair(sortKey, participanttx)); - } - - response.push_back(Pair("propertyid", (uint64_t) propertyId)); - response.push_back(Pair("name", sp.name)); - response.push_back(Pair("active", active)); - response.push_back(Pair("issuer", sp.issuer)); - response.push_back(Pair("propertyiddesired", (uint64_t) sp.property_desired)); - response.push_back(Pair("tokensperunit", FormatMP(propertyId, sp.num_tokens))); - response.push_back(Pair("earlybonus", sp.early_bird)); - response.push_back(Pair("percenttoissuer", sp.percentage)); - response.push_back(Pair("starttime", startTime)); - response.push_back(Pair("deadline", sp.deadline)); - response.push_back(Pair("amountraised", FormatMP(sp.property_desired, amountRaised))); - response.push_back(Pair("tokensissued", FormatMP(propertyId, tokensIssued))); - response.push_back(Pair("addedissuertokens", FormatMP(propertyId, sp.missedTokens))); - - // TODO: return fields every time? - if (!active) response.push_back(Pair("closedearly", sp.close_early)); - if (!active) response.push_back(Pair("maxtokens", sp.max_tokens)); - if (sp.close_early) response.push_back(Pair("endedtime", sp.timeclosed)); - if (sp.close_early && !sp.max_tokens) response.push_back(Pair("closetx", txidClosed)); - - if (showVerbose) { - UniValue participanttxs(UniValue::VARR); - for (std::map::iterator it = sortMap.begin(); it != sortMap.end(); ++it) { - participanttxs.push_back(it->second); - } - response.push_back(Pair("participanttransactions", participanttxs)); - } - - return response; -} - -UniValue elysium_getactivecrowdsales(const JSONRPCRequest& request) -{ - if (request.fHelp) - throw runtime_error( - "elysium_getactivecrowdsales\n" - "\nLists currently active crowdsales.\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"propertyid\" : n, (number) the identifier of the crowdsale\n" - " \"name\" : \"name\", (string) the name of the tokens issued via the crowdsale\n" - " \"issuer\" : \"address\", (string) the Firo address of the issuer on record\n" - " \"propertyiddesired\" : n, (number) the identifier of the tokens eligible to participate in the crowdsale\n" - " \"tokensperunit\" : \"n.nnnnnnnn\", (string) the amount of tokens granted per unit invested in the crowdsale\n" - " \"earlybonus\" : n, (number) an early bird bonus for participants in percent per week\n" - " \"percenttoissuer\" : n, (number) a percentage of tokens that will be granted to the issuer\n" - " \"starttime\" : nnnnnnnnnn, (number) the start time of the of the crowdsale as Unix timestamp\n" - " \"deadline\" : nnnnnnnnnn (number) the deadline of the crowdsale as Unix timestamp\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getactivecrowdsales", "") - + HelpExampleRpc("elysium_getactivecrowdsales", "") - ); - - UniValue response(UniValue::VARR); - - LOCK(cs_main); - - for (CrowdMap::const_iterator it = my_crowds.begin(); it != my_crowds.end(); ++it) { - const CMPCrowd& crowd = it->second; - uint32_t propertyId = crowd.getPropertyId(); - - CMPSPInfo::Entry sp; - if (!_my_sps->getSP(propertyId, sp)) { - continue; - } - - const uint256& creationHash = sp.txid; - - CTransactionRef tx; - uint256 hashBlock; - if (!GetTransaction(creationHash, tx, Params().GetConsensus(), hashBlock, true)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); - } - - int64_t startTime = -1; - if (!hashBlock.IsNull() && GetBlockIndex(hashBlock)) { - startTime = GetBlockIndex(hashBlock)->nTime; - } - - UniValue responseObj(UniValue::VOBJ); - responseObj.push_back(Pair("propertyid", (uint64_t) propertyId)); - responseObj.push_back(Pair("name", sp.name)); - responseObj.push_back(Pair("issuer", sp.issuer)); - responseObj.push_back(Pair("propertyiddesired", (uint64_t) sp.property_desired)); - responseObj.push_back(Pair("tokensperunit", FormatMP(propertyId, sp.num_tokens))); - responseObj.push_back(Pair("earlybonus", sp.early_bird)); - responseObj.push_back(Pair("percenttoissuer", sp.percentage)); - responseObj.push_back(Pair("starttime", startTime)); - responseObj.push_back(Pair("deadline", sp.deadline)); - response.push_back(responseObj); - } - - return response; -} - -UniValue elysium_getgrants(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_getgrants propertyid\n" - "\nReturns information about granted and revoked units of managed tokens.\n" - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the managed tokens to lookup\n" - "\nResult:\n" - "{\n" - " \"propertyid\" : n, (number) the identifier of the managed tokens\n" - " \"name\" : \"name\", (string) the name of the tokens\n" - " \"issuer\" : \"address\", (string) the Firo address of the issuer on record\n" - " \"creationtxid\" : \"hash\", (string) the hex-encoded creation transaction hash\n" - " \"totaltokens\" : \"n.nnnnnnnn\", (string) the total number of tokens in existence\n" - " \"issuances\": [ (array of JSON objects) a list of the granted and revoked tokens\n" - " {\n" - " \"txid\" : \"hash\", (string) the hash of the transaction that granted tokens\n" - " \"grant\" : \"n.nnnnnnnn\" (string) the number of tokens granted by this transaction\n" - " },\n" - " {\n" - " \"txid\" : \"hash\", (string) the hash of the transaction that revoked tokens\n" - " \"grant\" : \"n.nnnnnnnn\" (string) the number of tokens revoked by this transaction\n" - " },\n" - " ...\n" - " ]\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getgrants", "31") - + HelpExampleRpc("elysium_getgrants", "31") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - - CMPSPInfo::Entry sp; - { - LOCK(cs_main); - if (false == _my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property identifier does not exist"); - } - } - UniValue response(UniValue::VOBJ); - const uint256& creationHash = sp.txid; - int64_t totalTokens = getTotalTokens(propertyId); - - // TODO: sort by height? - - UniValue issuancetxs(UniValue::VARR); - std::map >::const_iterator it; - for (it = sp.historicalData.begin(); it != sp.historicalData.end(); it++) { - const std::string& txid = it->first.GetHex(); - int64_t grantedTokens = it->second.at(0); - int64_t revokedTokens = it->second.at(1); - - if (grantedTokens > 0) { - UniValue granttx(UniValue::VOBJ); - granttx.push_back(Pair("txid", txid)); - granttx.push_back(Pair("grant", FormatMP(propertyId, grantedTokens))); - issuancetxs.push_back(granttx); - } - - if (revokedTokens > 0) { - UniValue revoketx(UniValue::VOBJ); - revoketx.push_back(Pair("txid", txid)); - revoketx.push_back(Pair("revoke", FormatMP(propertyId, revokedTokens))); - issuancetxs.push_back(revoketx); - } - } - - response.push_back(Pair("propertyid", (uint64_t) propertyId)); - response.push_back(Pair("name", sp.name)); - response.push_back(Pair("issuer", sp.issuer)); - response.push_back(Pair("creationtxid", creationHash.GetHex())); - response.push_back(Pair("totaltokens", FormatMP(propertyId, totalTokens))); - response.push_back(Pair("issuances", issuancetxs)); - - return response; -} - -UniValue elysium_getorderbook(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( - "elysium_getorderbook propertyid ( propertyid )\n" - "\nList active offers on the distributed token exchange.\n" - "\nArguments:\n" - "1. propertyid (number, required) filter orders by property identifier for sale\n" - "2. propertyid (number, optional) filter orders by property identifier desired\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"address\" : \"address\", (string) the Firo address of the trader\n" - " \"txid\" : \"hash\", (string) the hex-encoded hash of the transaction of the order\n" - " \"ecosystem\" : \"main\"|\"test\", (string) the ecosytem in which the order was made (if \"cancel-ecosystem\")\n" - " \"propertyidforsale\" : n, (number) the identifier of the tokens put up for sale\n" - " \"propertyidforsaleisdivisible\" : true|false, (boolean) whether the tokens for sale are divisible\n" - " \"amountforsale\" : \"n.nnnnnnnn\", (string) the amount of tokens initially offered\n" - " \"amountremaining\" : \"n.nnnnnnnn\", (string) the amount of tokens still up for sale\n" - " \"propertyiddesired\" : n, (number) the identifier of the tokens desired in exchange\n" - " \"propertyiddesiredisdivisible\" : true|false, (boolean) whether the desired tokens are divisible\n" - " \"amountdesired\" : \"n.nnnnnnnn\", (string) the amount of tokens initially desired\n" - " \"amounttofill\" : \"n.nnnnnnnn\", (string) the amount of tokens still needed to fill the offer completely\n" - " \"action\" : n, (number) the action of the transaction: (1) \"trade\", (2) \"cancel-price\", (3) \"cancel-pair\", (4) \"cancel-ecosystem\"\n" - " \"block\" : nnnnnn, (number) the index of the block that contains the transaction\n" - " \"blocktime\" : nnnnnnnnnn (number) the timestamp of the block that contains the transaction\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getorderbook", "2") - + HelpExampleRpc("elysium_getorderbook", "2") - ); - - bool filterDesired = (request.params.size() > 1); - uint32_t propertyIdForSale = ParsePropertyId(request.params[0]); - uint32_t propertyIdDesired = 0; - - RequireExistingProperty(propertyIdForSale); - - if (filterDesired) { - propertyIdDesired = ParsePropertyId(request.params[1]); - - RequireExistingProperty(propertyIdDesired); - RequireSameEcosystem(propertyIdForSale, propertyIdDesired); - RequireDifferentIds(propertyIdForSale, propertyIdDesired); - } - - std::vector vecMetaDexObjects; - { - LOCK(cs_main); - for (md_PropertiesMap::const_iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - const md_PricesMap& prices = my_it->second; - for (md_PricesMap::const_iterator it = prices.begin(); it != prices.end(); ++it) { - const md_Set& indexes = it->second; - for (md_Set::const_iterator it = indexes.begin(); it != indexes.end(); ++it) { - const CMPMetaDEx& obj = *it; - if (obj.getProperty() != propertyIdForSale) continue; - if (!filterDesired || obj.getDesProperty() == propertyIdDesired) vecMetaDexObjects.push_back(obj); - } - } - } - } - - UniValue response(UniValue::VARR); - MetaDexObjectsToJSON(vecMetaDexObjects, response); - return response; -} - -UniValue elysium_gettradehistoryforaddress(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) - throw runtime_error( - "elysium_gettradehistoryforaddress \"address\" ( count propertyid )\n" - "\nRetrieves the history of orders on the distributed exchange for the supplied address.\n" - "\nArguments:\n" - "1. address (string, required) address to retrieve history for\n" - "2. count (number, optional) number of orders to retrieve (default: 10)\n" - "3. propertyid (number, optional) filter by property identifier transacted (default: no filter)\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"txid\" : \"hash\", (string) the hex-encoded hash of the transaction of the order\n" - " \"sendingaddress\" : \"address\", (string) the Firo address of the trader\n" - " \"ismine\" : true|false, (boolean) whether the order involes an address in the wallet\n" - " \"confirmations\" : nnnnnnnnnn, (number) the number of transaction confirmations\n" - " \"fee\" : \"n.nnnnnnnn\", (string) the transaction fee in firos\n" - " \"blocktime\" : nnnnnnnnnn, (number) the timestamp of the block that contains the transaction\n" - " \"valid\" : true|false, (boolean) whether the transaction is valid\n" - " \"version\" : n, (number) the transaction version\n" - " \"type_int\" : n, (number) the transaction type as number\n" - " \"type\" : \"type\", (string) the transaction type as string\n" - " \"propertyidforsale\" : n, (number) the identifier of the tokens put up for sale\n" - " \"propertyidforsaleisdivisible\" : true|false, (boolean) whether the tokens for sale are divisible\n" - " \"amountforsale\" : \"n.nnnnnnnn\", (string) the amount of tokens initially offered\n" - " \"propertyiddesired\" : n, (number) the identifier of the tokens desired in exchange\n" - " \"propertyiddesiredisdivisible\" : true|false, (boolean) whether the desired tokens are divisible\n" - " \"amountdesired\" : \"n.nnnnnnnn\", (string) the amount of tokens initially desired\n" - " \"unitprice\" : \"n.nnnnnnnnnnn...\" (string) the unit price (shown in the property desired)\n" - " \"status\" : \"status\" (string) the status of the order (\"open\", \"cancelled\", \"filled\", ...)\n" - " \"canceltxid\" : \"hash\", (string) the hash of the transaction that cancelled the order (if cancelled)\n" - " \"matches\": [ (array of JSON objects) a list of matched orders and executed trades\n" - " {\n" - " \"txid\" : \"hash\", (string) the hash of the transaction that was matched against\n" - " \"block\" : nnnnnn, (number) the index of the block that contains this transaction\n" - " \"address\" : \"address\", (string) the Firo address of the other trader\n" - " \"amountsold\" : \"n.nnnnnnnn\", (string) the number of tokens sold in this trade\n" - " \"amountreceived\" : \"n.nnnnnnnn\" (string) the number of tokens traded in exchange\n" - " },\n" - " ...\n" - " ]\n" - " },\n" - " ...\n" - "]\n" - "\nNote:\n" - "The documentation only covers the output for a trade, but there are also cancel transactions with different properties.\n" - "\nExamples:\n" - + HelpExampleCli("elysium_gettradehistoryforaddress", "\"1MCHESTptvd2LnNp7wmr2sGTpRomteAkq8\"") - + HelpExampleRpc("elysium_gettradehistoryforaddress", "\"1MCHESTptvd2LnNp7wmr2sGTpRomteAkq8\"") - ); - - std::string address = ParseAddress(request.params[0]); - uint64_t count = (request.params.size() > 1) ? request.params[1].get_int64() : 10; - uint32_t propertyId = 0; - - if (request.params.size() > 2) { - propertyId = ParsePropertyId(request.params[2]); - RequireExistingProperty(propertyId); - } - - // Obtain a sorted vector of txids for the address trade history - std::vector vecTransactions; - { - LOCK(cs_main); - t_tradelistdb->getTradesForAddress(address, vecTransactions, propertyId); - } - - // Populate the address trade history into JSON objects until we have processed count transactions - UniValue response(UniValue::VARR); - uint32_t processed = 0; - for(std::vector::reverse_iterator it = vecTransactions.rbegin(); it != vecTransactions.rend(); ++it) { - UniValue txobj(UniValue::VOBJ); - int populateResult = populateRPCTransactionObject(*it, txobj, "", true); - if (0 == populateResult) { - response.push_back(txobj); - processed++; - if (processed >= count) break; - } - } - - return response; -} - -UniValue elysium_gettradehistoryforpair(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw runtime_error( - "elysium_gettradehistoryforpair propertyid propertyid ( count )\n" - "\nRetrieves the history of trades on the distributed token exchange for the specified market.\n" - "\nArguments:\n" - "1. propertyid (number, required) the first side of the traded pair\n" - "2. propertyid (number, required) the second side of the traded pair\n" - "3. count (number, optional) number of trades to retrieve (default: 10)\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"block\" : nnnnnn, (number) the index of the block that contains the trade match\n" - " \"unitprice\" : \"n.nnnnnnnnnnn...\" , (string) the unit price used to execute this trade (received/sold)\n" - " \"inverseprice\" : \"n.nnnnnnnnnnn...\", (string) the inverse unit price (sold/received)\n" - " \"sellertxid\" : \"hash\", (string) the hash of the transaction of the seller\n" - " \"address\" : \"address\", (string) the Firo address of the seller\n" - " \"amountsold\" : \"n.nnnnnnnn\", (string) the number of tokens sold in this trade\n" - " \"amountreceived\" : \"n.nnnnnnnn\", (string) the number of tokens traded in exchange\n" - " \"matchingtxid\" : \"hash\", (string) the hash of the transaction that was matched against\n" - " \"matchingaddress\" : \"address\" (string) the Firo address of the other party of this trade\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_gettradehistoryforpair", "1 12 500") - + HelpExampleRpc("elysium_gettradehistoryforpair", "1, 12, 500") - ); - - // obtain property identifiers for pair & check valid parameters - uint32_t propertyIdSideA = ParsePropertyId(request.params[0]); - uint32_t propertyIdSideB = ParsePropertyId(request.params[1]); - uint64_t count = (request.params.size() > 2) ? request.params[2].get_int64() : 10; - - RequireExistingProperty(propertyIdSideA); - RequireExistingProperty(propertyIdSideB); - RequireSameEcosystem(propertyIdSideA, propertyIdSideB); - RequireDifferentIds(propertyIdSideA, propertyIdSideB); - - // request pair trade history from trade db - UniValue response(UniValue::VARR); - LOCK(cs_main); - t_tradelistdb->getTradesForPair(propertyIdSideA, propertyIdSideB, response, count); - return response; -} - -UniValue elysium_getactivedexsells(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() > 1) - throw runtime_error( - "elysium_getactivedexsells ( address )\n" - "\nReturns currently active offers on the distributed exchange.\n" - "\nArguments:\n" - "1. address (string, optional) address filter (default: include any)\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"txid\" : \"hash\", (string) the hash of the transaction of this offer\n" - " \"propertyid\" : n, (number) the identifier of the tokens for sale\n" - " \"seller\" : \"address\", (string) the Firo address of the seller\n" - " \"amountavailable\" : \"n.nnnnnnnn\", (string) the number of tokens still listed for sale and currently available\n" - " \"firodesired\" : \"n.nnnnnnnn\", (string) the number of firos desired in exchange\n" - " \"unitprice\" : \"n.nnnnnnnn\" , (string) the unit price (FIRO/token)\n" - " \"timelimit\" : nn, (number) the time limit in blocks a buyer has to pay following a successful accept\n" - " \"minimumfee\" : \"n.nnnnnnnn\", (string) the minimum mining fee a buyer has to pay to accept this offer\n" - " \"amountaccepted\" : \"n.nnnnnnnn\", (string) the number of tokens currently reserved for pending \"accept\" orders\n" - " \"accepts\": [ (array of JSON objects) a list of pending \"accept\" orders\n" - " {\n" - " \"buyer\" : \"address\", (string) the Firo address of the buyer\n" - " \"block\" : nnnnnn, (number) the index of the block that contains the \"accept\" order\n" - " \"blocksleft\" : nn, (number) the number of blocks left to pay\n" - " \"amount\" : \"n.nnnnnnnn\" (string) the amount of tokens accepted and reserved\n" - " \"amounttopay\" : \"n.nnnnnnnn\" (string) the amount in firos needed finalize the trade\n" - " },\n" - " ...\n" - " ]\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getactivedexsells", "") - + HelpExampleRpc("elysium_getactivedexsells", "") - ); - - std::string addressFilter; - - if (request.params.size() > 0) { - addressFilter = ParseAddressOrEmpty(request.params[0]); - } - - UniValue response(UniValue::VARR); - - int curBlock = GetHeight(); - - LOCK(cs_main); - - for (OfferMap::iterator it = my_offers.begin(); it != my_offers.end(); ++it) { - const CMPOffer& selloffer = it->second; - const std::string& sellCombo = it->first; - std::string seller = sellCombo.substr(0, sellCombo.size() - 2); - - // filtering - if (!addressFilter.empty() && seller != addressFilter) continue; - - std::string txid = selloffer.getHash().GetHex(); - uint32_t propertyId = selloffer.getProperty(); - int64_t minFee = selloffer.getMinFee(); - uint8_t timeLimit = selloffer.getBlockTimeLimit(); - int64_t sellOfferAmount = selloffer.getOfferAmountOriginal(); //badly named - "Original" implies off the wire, but is amended amount - int64_t sellBitcoinDesired = selloffer.getXZCDesiredOriginal(); //badly named - "Original" implies off the wire, but is amended amount - int64_t amountAvailable = getMPbalance(seller, propertyId, SELLOFFER_RESERVE); - int64_t amountAccepted = getMPbalance(seller, propertyId, ACCEPT_RESERVE); - - // TODO: no math, and especially no rounding here (!) - // TODO: no math, and especially no rounding here (!) - // TODO: no math, and especially no rounding here (!) - - // calculate unit price and updated amount of firo desired - double unitPriceFloat = 0.0; - if ((sellOfferAmount > 0) && (sellBitcoinDesired > 0)) { - unitPriceFloat = (double) sellBitcoinDesired / (double) sellOfferAmount; // divide by zero protection - } - int64_t unitPrice = rounduint64(unitPriceFloat * COIN); - int64_t bitcoinDesired = calculateDesiredBTC(sellOfferAmount, sellBitcoinDesired, amountAvailable); - - UniValue responseObj(UniValue::VOBJ); - responseObj.push_back(Pair("txid", txid)); - responseObj.push_back(Pair("propertyid", (uint64_t) propertyId)); - responseObj.push_back(Pair("seller", seller)); - responseObj.push_back(Pair("amountavailable", FormatDivisibleMP(amountAvailable))); - responseObj.push_back(Pair("firodesired", FormatDivisibleMP(bitcoinDesired))); - responseObj.push_back(Pair("unitprice", FormatDivisibleMP(unitPrice))); - responseObj.push_back(Pair("timelimit", timeLimit)); - responseObj.push_back(Pair("minimumfee", FormatDivisibleMP(minFee))); - - // display info about accepts related to sell - responseObj.push_back(Pair("amountaccepted", FormatDivisibleMP(amountAccepted))); - UniValue acceptsMatched(UniValue::VARR); - for (AcceptMap::const_iterator ait = my_accepts.begin(); ait != my_accepts.end(); ++ait) { - UniValue matchedAccept(UniValue::VOBJ); - const CMPAccept& accept = ait->second; - const std::string& acceptCombo = ait->first; - - // does this accept match the sell? - if (accept.getHash() == selloffer.getHash()) { - // split acceptCombo out to get the buyer address - std::string buyer = acceptCombo.substr((acceptCombo.find("+") + 1), (acceptCombo.size()-(acceptCombo.find("+") + 1))); - int blockOfAccept = accept.getAcceptBlock(); - int blocksLeftToPay = (blockOfAccept + selloffer.getBlockTimeLimit()) - curBlock; - int64_t amountAccepted = accept.getAcceptAmountRemaining(); - // TODO: don't recalculate! - int64_t amountToPayInBTC = calculateDesiredBTC(accept.getOfferAmountOriginal(), accept.getXZCDesiredOriginal(), amountAccepted); - matchedAccept.push_back(Pair("buyer", buyer)); - matchedAccept.push_back(Pair("block", blockOfAccept)); - matchedAccept.push_back(Pair("blocksleft", blocksLeftToPay)); - matchedAccept.push_back(Pair("amount", FormatDivisibleMP(amountAccepted))); - matchedAccept.push_back(Pair("amounttopay", FormatDivisibleMP(amountToPayInBTC))); - acceptsMatched.push_back(matchedAccept); - } - } - responseObj.push_back(Pair("accepts", acceptsMatched)); - - // add sell object into response array - response.push_back(responseObj); - } - - return response; -} - -UniValue elysium_listblocktransactions(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_listblocktransactions index\n" - "\nLists all Elysium transactions in a block.\n" - "\nArguments:\n" - "1. index (number, required) the block height or block index\n" - "\nResult:\n" - "[ (array of string)\n" - " \"hash\", (string) the hash of the transaction\n" - " ...\n" - "]\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_listblocktransactions", "279007") - + HelpExampleRpc("elysium_listblocktransactions", "279007") - ); - - int blockHeight = request.params[0].get_int(); - - RequireHeightInChain(blockHeight); - - // next let's obtain the block for this height - CBlock block; - { - LOCK(cs_main); - CBlockIndex* pBlockIndex = chainActive[blockHeight]; - - if (!ReadBlockFromDisk(block, pBlockIndex, Params().GetConsensus())) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed to read block from disk"); - } - } - - UniValue response(UniValue::VARR); - - // now we want to loop through each of the transactions in the block and run against CMPTxList::exists - // those that return positive add to our response array - - LOCK(cs_main); - - BOOST_FOREACH(CTransactionRef tx, block.vtx) { - if (p_txlistdb->exists(tx->GetHash())) { - // later we can add a verbose flag to decode here, but for now callers can send returned txids into gettransaction_MP - // add the txid into the response as it's an MP transaction - response.push_back(tx->GetHash().GetHex()); - } - } - - return response; -} - -UniValue elysium_gettransaction(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_gettransaction \"txid\"\n" - "\nGet detailed information about an Elysium transaction.\n" - "\nArguments:\n" - "1. txid (string, required) the hash of the transaction to lookup\n" - "\nResult:\n" - "{\n" - " \"txid\" : \"hash\", (string) the hex-encoded hash of the transaction\n" - " \"sendingaddress\" : \"address\", (string) the Firo address of the sender\n" - " \"referenceaddress\" : \"address\", (string) a Firo address used as reference (if any)\n" - " \"ismine\" : true|false, (boolean) whether the transaction involes an address in the wallet\n" - " \"confirmations\" : nnnnnnnnnn, (number) the number of transaction confirmations\n" - " \"fee\" : \"n.nnnnnnnn\", (string) the transaction fee in firos\n" - " \"blocktime\" : nnnnnnnnnn, (number) the timestamp of the block that contains the transaction\n" - " \"valid\" : true|false, (boolean) whether the transaction is valid\n" - " \"invalidreason\" : \"reason\", (string) if a transaction is invalid, the reason \n" - " \"version\" : n, (number) the transaction version\n" - " \"type_int\" : n, (number) the transaction type as number\n" - " \"type\" : \"type\", (string) the transaction type as string\n" - " [...] (mixed) other transaction type specific properties\n" - "}\n" - "\nbExamples:\n" - + HelpExampleCli("elysium_gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") - + HelpExampleRpc("elysium_gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") - ); - - uint256 hash = ParseHashV(request.params[0], "txid"); - - UniValue txobj(UniValue::VOBJ); - int populateResult = populateRPCTransactionObject(hash, txobj); - if (populateResult != 0) PopulateFailure(populateResult); - - return txobj; -} - -UniValue elysium_listtransactions(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() > 5) - throw runtime_error( - "elysium_listtransactions ( \"address\" count skip startblock endblock )\n" - "\nList wallet transactions, optionally filtered by an address and block boundaries.\n" - "\nArguments:\n" - "1. address (string, optional) address filter (default: \"*\")\n" - "2. count (number, optional) show at most n transactions (default: 10)\n" - "3. skip (number, optional) skip the first n transactions (default: 0)\n" - "4. startblock (number, optional) first block to begin the search (default: 0)\n" - "5. endblock (number, optional) last block to include in the search (default: 999999)\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"txid\" : \"hash\", (string) the hex-encoded hash of the transaction\n" - " \"sendingaddress\" : \"address\", (string) the Firo address of the sender\n" - " \"referenceaddress\" : \"address\", (string) a Firo address used as reference (if any)\n" - " \"ismine\" : true|false, (boolean) whether the transaction involes an address in the wallet\n" - " \"confirmations\" : nnnnnnnnnn, (number) the number of transaction confirmations\n" - " \"fee\" : \"n.nnnnnnnn\", (string) the transaction fee in firos\n" - " \"blocktime\" : nnnnnnnnnn, (number) the timestamp of the block that contains the transaction\n" - " \"valid\" : true|false, (boolean) whether the transaction is valid\n" - " \"version\" : n, (number) the transaction version\n" - " \"type_int\" : n, (number) the transaction type as number\n" - " \"type\" : \"type\", (string) the transaction type as string\n" - " [...] (mixed) other transaction type specific properties\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_listtransactions", "") - + HelpExampleRpc("elysium_listtransactions", "") - ); - - // obtains parameters - default all wallet addresses & last 10 transactions - std::string addressParam; - if (request.params.size() > 0) { - if (("*" != request.params[0].get_str()) && ("" != request.params[0].get_str())) addressParam = request.params[0].get_str(); - } - int64_t nCount = 10; - if (request.params.size() > 1) nCount = request.params[1].get_int64(); - if (nCount < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); - int64_t nFrom = 0; - if (request.params.size() > 2) nFrom = request.params[2].get_int64(); - if (nFrom < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); - int64_t nStartBlock = 0; - if (request.params.size() > 3) nStartBlock = request.params[3].get_int64(); - if (nStartBlock < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative start block"); - int64_t nEndBlock = 999999; - if (request.params.size() > 4) nEndBlock = request.params[4].get_int64(); - if (nEndBlock < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative end block"); - - // obtain a sorted list of Elysium layer wallet transactions (including STO receipts and pending) - std::map walletTransactions = FetchWalletElysiumTransactions(nFrom+nCount, nStartBlock, nEndBlock); - - // reverse iterate over (now ordered) transactions and populate RPC objects for each one - UniValue response(UniValue::VARR); - for (std::map::reverse_iterator it = walletTransactions.rbegin(); it != walletTransactions.rend(); it++) { - uint256 txHash = it->second; - UniValue txobj(UniValue::VOBJ); - int populateResult = populateRPCTransactionObject(txHash, txobj, addressParam); - if (0 == populateResult) response.push_back(txobj); - } - - // TODO: reenable cutting! -/* - // cut on nFrom and nCount - if (nFrom > (int)response.size()) nFrom = response.size(); - if ((nFrom + nCount) > (int)response.size()) nCount = response.size() - nFrom; - UniValue::iterator first = response.begin(); - std::advance(first, nFrom); - UniValue::iterator last = response.begin(); - std::advance(last, nFrom+nCount); - if (last != response.end()) response.erase(last, response.end()); - if (first != response.begin()) response.erase(response.begin(), first); - std::reverse(response.begin(), response.end()); -*/ - return response; -} - -#ifdef ENABLE_WALLET -UniValue elysium_listmints(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() > 3) { - throw std::runtime_error( - "elysium_listmints ( propertyid denomination verbose )\n" - "\nList all non-pending unused sigma mints in the wallet, optionally filtered by property and denomination.\n" - "\nArguments:\n" - "1. propertyid (number, optional) show only mints that belonged to this property\n" - "2. denomination (number, optional) show only mints with this denomination\n" - "3. verbose (boolean, optional) show additional information (default: false)\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"propertyid\" : n, (number) property identifier that mint belonged to\n" - " \"denomination\" : n, (number) denomination identifier of the mint\n" - " \"value\" : \"n.nnnnnnnn\" (string) value of the mint\n" - " \"block\" : n (number) the block number that mint got mined (if verbose enabled)\n" - " \"group\" : n (number) group identifier that mint belonged to (if verbose enabled)\n" - " \"index\" : n (number) index of the mint in the group (if verbose enabled)\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_listmints", "") - + HelpExampleRpc("elysium_listmints", "") - ); - } - - // Get parameters. - boost::optional property; - boost::optional denomination; - bool verbose = false; - - if (request.params.size() > 0) { - property = ParsePropertyId(request.params[0]); - RequireExistingProperty(property.get()); - } - - if (request.params.size() > 1) { - denomination = ParseSigmaDenomination(request.params[1]); - RequireExistingDenomination(property.get(), denomination.get()); - } - - if (request.params.size() > 2) { - verbose = request.params[2].get_bool(); - } - - // Get mints that meet criteria. - std::vector mints; - - wallet->ListSigmaMintsV1(boost::make_function_output_iterator([&] (const std::pair& m) { - if (m.second.IsSpent() || !m.second.IsOnChain()) { - return; - } - - if (property && m.second.property != property.get()) { - return; - } - - if (denomination && m.second.denomination != denomination.get()) { - return; - } - - mints.push_back(m.second); - })); - - return SigmaMintsToJson(mints.begin(), mints.end(), verbose); -} - -UniValue elysium_listpendingmints(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 0) { - throw std::runtime_error( - "elysium_listpendingmints\n" - "\nList all pending sigma mints in the wallet.\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"propertyid\" : n, (number) property identifier that mint belonged to\n" - " \"denomination\" : n, (number) denomination identifier of the mint\n" - " \"value\" : \"n.nnnnnnnn\" (string) value of the mint\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_listpendingmints", "") - + HelpExampleRpc("elysium_listpendingmints", "") - ); - } - - std::vector mints; - - wallet->ListSigmaMintsV1(boost::make_function_output_iterator([&] (const std::pair& m) { - if (m.second.IsOnChain()) { - return; - } - - mints.push_back(m.second); - })); - - return SigmaMintsToJson(mints.begin(), mints.end()); -} -#endif - -UniValue elysium_listpendingtransactions(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() > 1) - throw runtime_error( - "elysium_listpendingtransactions ( \"address\" )\n" - "\nReturns a list of unconfirmed Elysium transactions, pending in the memory pool.\n" - "\nAn optional filter can be provided to only include transactions which involve the given address.\n" - "\nNote: the validity of pending transactions is uncertain, and the state of the memory pool may " - "change at any moment. It is recommended to check transactions after confirmation, and pending " - "transactions should be considered as invalid.\n" - "\nArguments:\n" - "1. address (string, optional) address filter (default: \"\" for no filter)\n" - "\nResult:\n" - "[ (array of JSON objects)\n" - " {\n" - " \"txid\" : \"hash\", (string) the hex-encoded hash of the transaction\n" - " \"sendingaddress\" : \"address\", (string) the Firo address of the sender\n" - " \"referenceaddress\" : \"address\", (string) a Firo address used as reference (if any)\n" - " \"ismine\" : true|false, (boolean) whether the transaction involes an address in the wallet\n" - " \"fee\" : \"n.nnnnnnnn\", (string) the transaction fee in firos\n" - " \"version\" : n, (number) the transaction version\n" - " \"type_int\" : n, (number) the transaction type as number\n" - " \"type\" : \"type\", (string) the transaction type as string\n" - " [...] (mixed) other transaction type specific properties\n" - " },\n" - " ...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("elysium_listpendingtransactions", "") - + HelpExampleRpc("elysium_listpendingtransactions", "") - ); - - std::string filterAddress; - if (request.params.size() > 0) { - filterAddress = ParseAddressOrEmpty(request.params[0]); - } - - std::vector vTxid; - mempool.queryHashes(vTxid); - - UniValue result(UniValue::VARR); - BOOST_FOREACH(const uint256& hash, vTxid) { - UniValue txObj(UniValue::VOBJ); - if (populateRPCTransactionObject(hash, txObj, filterAddress) == 0) { - result.push_back(txObj); - } - } - - return result; -} - -UniValue elysium_getinfo(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 0) - throw runtime_error( - "elysium_getinfo\n" - "Returns various state information of the client and protocol.\n" - "\nResult:\n" - "{\n" - " \"elysiumversion_int\" : xxxxxxx, (number) client version as integer\n" - " \"elysiumversion\" : \"x.x.x.x-xxx\", (string) client version\n" - " \"firocoreversion\" : \"x.x.x\", (string) Firo Core version\n" - " \"block\" : nnnnnn, (number) index of the last processed block\n" - " \"blocktime\" : nnnnnnnnnn, (number) timestamp of the last processed block\n" - " \"blocktransactions\" : nnnn, (number) Elysium transactions found in the last processed block\n" - " \"totaltransactions\" : nnnnnnnn, (number) Elysium transactions processed in total\n" - " \"alerts\" : [ (array of JSON objects) active protocol alert (if any)\n" - " {\n" - " \"alerttypeint\" : n, (number) alert type as integer\n" - " \"alerttype\" : \"xxx\", (string) alert type\n" - " \"alertexpiry\" : \"nnnnnnnnnn\", (string) expiration criteria\n" - " \"alertmessage\" : \"xxx\" (string) information about the alert\n" - " },\n" - " ...\n" - " ]\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getinfo", "") - + HelpExampleRpc("elysium_getinfo", "") - ); - - UniValue infoResponse(UniValue::VOBJ); - - // provide the Elysium and Firo version - infoResponse.push_back(Pair("elysiumversion_int", ELYSIUM_VERSION)); - infoResponse.push_back(Pair("elysiumversion", ElysiumVersion())); - infoResponse.push_back(Pair("firocoreversion", FiroCoreVersion())); - - // provide the current block details - int block = GetHeight(); - int64_t blockTime = GetLatestBlockTime(); - - LOCK(cs_main); - - int blockMPTransactions = p_txlistdb->getMPTransactionCountBlock(block); - int totalMPTransactions = p_txlistdb->getMPTransactionCountTotal(); - int totalMPTrades = t_tradelistdb->getMPTradeCountTotal(); - infoResponse.push_back(Pair("block", block)); - infoResponse.push_back(Pair("blocktime", blockTime)); - infoResponse.push_back(Pair("blocktransactions", blockMPTransactions)); - - // provide the number of trades completed - infoResponse.push_back(Pair("totaltrades", totalMPTrades)); - // provide the number of transactions parsed - infoResponse.push_back(Pair("totaltransactions", totalMPTransactions)); - - // handle alerts - UniValue alerts(UniValue::VARR); - std::vector elysiumAlerts = GetElysiumAlerts(); - for (std::vector::iterator it = elysiumAlerts.begin(); it != elysiumAlerts.end(); it++) { - AlertData alert = *it; - UniValue alertResponse(UniValue::VOBJ); - std::string alertTypeStr; - switch (alert.alert_type) { - case 1: alertTypeStr = "alertexpiringbyblock"; - break; - case 2: alertTypeStr = "alertexpiringbyblocktime"; - break; - case 3: alertTypeStr = "alertexpiringbyclientversion"; - break; - default: alertTypeStr = "error"; - } - alertResponse.push_back(Pair("alerttypeint", alert.alert_type)); - alertResponse.push_back(Pair("alerttype", alertTypeStr)); - alertResponse.push_back(Pair("alertexpiry", FormatIndivisibleMP(alert.alert_expiry))); - alertResponse.push_back(Pair("alertmessage", alert.alert_message)); - alerts.push_back(alertResponse); - } - infoResponse.push_back(Pair("alerts", alerts)); - - return infoResponse; -} - -UniValue elysium_getactivations(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 0) - throw runtime_error( - "elysium_getactivations\n" - "Returns pending and completed feature activations.\n" - "\nResult:\n" - "{\n" - " \"pendingactivations\": [ (array of JSON objects) a list of pending feature activations\n" - " {\n" - " \"featureid\" : n, (number) the id of the feature\n" - " \"featurename\" : \"xxxxxxxx\", (string) the name of the feature\n" - " \"activationblock\" : n, (number) the block the feature will be activated\n" - " \"minimumversion\" : n (number) the minimum client version needed to support this feature\n" - " },\n" - " ...\n" - " ]\n" - " \"completedactivations\": [ (array of JSON objects) a list of completed feature activations\n" - " {\n" - " \"featureid\" : n, (number) the id of the feature\n" - " \"featurename\" : \"xxxxxxxx\", (string) the name of the feature\n" - " \"activationblock\" : n, (number) the block the feature will be activated\n" - " \"minimumversion\" : n (number) the minimum client version needed to support this feature\n" - " },\n" - " ...\n" - " ]\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getactivations", "") - + HelpExampleRpc("elysium_getactivations", "") - ); - - UniValue response(UniValue::VOBJ); - - UniValue arrayPendingActivations(UniValue::VARR); - std::vector vecPendingActivations = GetPendingActivations(); - for (std::vector::iterator it = vecPendingActivations.begin(); it != vecPendingActivations.end(); ++it) { - UniValue actObj(UniValue::VOBJ); - FeatureActivation pendingAct = *it; - actObj.push_back(Pair("featureid", pendingAct.featureId)); - actObj.push_back(Pair("featurename", pendingAct.featureName)); - actObj.push_back(Pair("activationblock", pendingAct.activationBlock)); - actObj.push_back(Pair("minimumversion", (uint64_t)pendingAct.minClientVersion)); - arrayPendingActivations.push_back(actObj); - } - - UniValue arrayCompletedActivations(UniValue::VARR); - std::vector vecCompletedActivations = GetCompletedActivations(); - for (std::vector::iterator it = vecCompletedActivations.begin(); it != vecCompletedActivations.end(); ++it) { - UniValue actObj(UniValue::VOBJ); - FeatureActivation completedAct = *it; - actObj.push_back(Pair("featureid", completedAct.featureId)); - actObj.push_back(Pair("featurename", completedAct.featureName)); - actObj.push_back(Pair("activationblock", completedAct.activationBlock)); - actObj.push_back(Pair("minimumversion", (uint64_t)completedAct.minClientVersion)); - arrayCompletedActivations.push_back(actObj); - } - - response.push_back(Pair("pendingactivations", arrayPendingActivations)); - response.push_back(Pair("completedactivations", arrayCompletedActivations)); - - return response; -} - -UniValue elysium_getsto(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( - "elysium_getsto \"txid\" \"recipientfilter\"\n" - "\nGet information and recipients of a send-to-owners transaction.\n" - "\nArguments:\n" - "1. txid (string, required) the hash of the transaction to lookup\n" - "2. recipientfilter (string, optional) a filter for recipients (wallet by default, \"*\" for all)\n" - "\nResult:\n" - "{\n" - " \"txid\" : \"hash\", (string) the hex-encoded hash of the transaction\n" - " \"sendingaddress\" : \"address\", (string) the Firo address of the sender\n" - " \"ismine\" : true|false, (boolean) whether the transaction involes an address in the wallet\n" - " \"confirmations\" : nnnnnnnnnn, (number) the number of transaction confirmations\n" - " \"fee\" : \"n.nnnnnnnn\", (string) the transaction fee in firos\n" - " \"blocktime\" : nnnnnnnnnn, (number) the timestamp of the block that contains the transaction\n" - " \"valid\" : true|false, (boolean) whether the transaction is valid\n" - " \"version\" : n, (number) the transaction version\n" - " \"type_int\" : n, (number) the transaction type as number\n" - " \"type\" : \"type\", (string) the transaction type as string\n" - " \"propertyid\" : n, (number) the identifier of sent tokens\n" - " \"divisible\" : true|false, (boolean) whether the sent tokens are divisible\n" - " \"amount\" : \"n.nnnnnnnn\", (string) the number of tokens sent to owners\n" - " \"totalstofee\" : \"n.nnnnnnnn\", (string) the fee paid by the sender, nominated in ELYSIUM or TELYSIUM\n" - " \"recipients\": [ (array of JSON objects) a list of recipients\n" - " {\n" - " \"address\" : \"address\", (string) the Firo address of the recipient\n" - " \"amount\" : \"n.nnnnnnnn\" (string) the number of tokens sent to this recipient\n" - " },\n" - " ...\n" - " ]\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("elysium_getsto", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" \"*\"") - + HelpExampleRpc("elysium_getsto", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\", \"*\"") - ); - - uint256 hash = ParseHashV(request.params[0], "txid"); - std::string filterAddress; - if (request.params.size() > 1) filterAddress = ParseAddressOrWildcard(request.params[1]); - - UniValue txobj(UniValue::VOBJ); - int populateResult = populateRPCTransactionObject(hash, txobj, "", true, filterAddress); - if (populateResult != 0) PopulateFailure(populateResult); - - return txobj; -} - -UniValue elysium_gettrade(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_gettrade \"txid\"\n" - "\nGet detailed information and trade matches for orders on the distributed token exchange.\n" - "\nArguments:\n" - "1. txid (string, required) the hash of the order to lookup\n" - "\nResult:\n" - "{\n" - " \"txid\" : \"hash\", (string) the hex-encoded hash of the transaction of the order\n" - " \"sendingaddress\" : \"address\", (string) the Firo address of the trader\n" - " \"ismine\" : true|false, (boolean) whether the order involes an address in the wallet\n" - " \"confirmations\" : nnnnnnnnnn, (number) the number of transaction confirmations\n" - " \"fee\" : \"n.nnnnnnnn\", (string) the transaction fee in firos\n" - " \"blocktime\" : nnnnnnnnnn, (number) the timestamp of the block that contains the transaction\n" - " \"valid\" : true|false, (boolean) whether the transaction is valid\n" - " \"version\" : n, (number) the transaction version\n" - " \"type_int\" : n, (number) the transaction type as number\n" - " \"type\" : \"type\", (string) the transaction type as string\n" - " \"propertyidforsale\" : n, (number) the identifier of the tokens put up for sale\n" - " \"propertyidforsaleisdivisible\" : true|false, (boolean) whether the tokens for sale are divisible\n" - " \"amountforsale\" : \"n.nnnnnnnn\", (string) the amount of tokens initially offered\n" - " \"propertyiddesired\" : n, (number) the identifier of the tokens desired in exchange\n" - " \"propertyiddesiredisdivisible\" : true|false, (boolean) whether the desired tokens are divisible\n" - " \"amountdesired\" : \"n.nnnnnnnn\", (string) the amount of tokens initially desired\n" - " \"unitprice\" : \"n.nnnnnnnnnnn...\" (string) the unit price (shown in the property desired)\n" - " \"status\" : \"status\" (string) the status of the order (\"open\", \"cancelled\", \"filled\", ...)\n" - " \"canceltxid\" : \"hash\", (string) the hash of the transaction that cancelled the order (if cancelled)\n" - " \"matches\": [ (array of JSON objects) a list of matched orders and executed trades\n" - " {\n" - " \"txid\" : \"hash\", (string) the hash of the transaction that was matched against\n" - " \"block\" : nnnnnn, (number) the index of the block that contains this transaction\n" - " \"address\" : \"address\", (string) the Firo address of the other trader\n" - " \"amountsold\" : \"n.nnnnnnnn\", (string) the number of tokens sold in this trade\n" - " \"amountreceived\" : \"n.nnnnnnnn\" (string) the number of tokens traded in exchange\n" - " },\n" - " ...\n" - " ]\n" - "}\n" - "\nNote:\n" - "The documentation only covers the output for a trade, but there are also cancel transactions with different properties.\n" - "\nExamples:\n" - + HelpExampleCli("elysium_gettrade", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") - + HelpExampleRpc("elysium_gettrade", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") - ); - - uint256 hash = ParseHashV(request.params[0], "txid"); - - UniValue txobj(UniValue::VOBJ); - int populateResult = populateRPCTransactionObject(hash, txobj, "", true); - if (populateResult != 0) PopulateFailure(populateResult); - - return txobj; -} - -UniValue elysium_getcurrentconsensushash(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 0) - throw runtime_error( - "elysium_getcurrentconsensushash\n" - "\nReturns the consensus hash for all balances for the current block.\n" - "\nResult:\n" - "{\n" - " \"block\" : nnnnnn, (number) the index of the block this consensus hash applies to\n" - " \"blockhash\" : \"hash\", (string) the hash of the corresponding block\n" - " \"consensushash\" : \"hash\" (string) the consensus hash for the block\n" - "}\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_getcurrentconsensushash", "") - + HelpExampleRpc("elysium_getcurrentconsensushash", "") - ); - - LOCK(cs_main); // TODO - will this ensure we don't take in a new block in the couple of ms it takes to calculate the consensus hash? - - int block = GetHeight(); - - CBlockIndex* pblockindex = chainActive[block]; - uint256 blockHash = pblockindex->GetBlockHash(); - - uint256 consensusHash = GetConsensusHash(); - - UniValue response(UniValue::VOBJ); - response.push_back(Pair("block", block)); - response.push_back(Pair("blockhash", blockHash.GetHex())); - response.push_back(Pair("consensushash", consensusHash.GetHex())); - - return response; -} - -UniValue elysium_getmetadexhash(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() > 1) - throw runtime_error( - "elysium_getmetadexhash propertyId\n" - "\nReturns a hash of the current state of the MetaDEx (default) or orderbook.\n" - "\nArguments:\n" - "1. propertyid (number, optional) hash orderbook (only trades selling propertyid)\n" - "\nResult:\n" - "{\n" - " \"block\" : nnnnnn, (number) the index of the block this hash applies to\n" - " \"blockhash\" : \"hash\", (string) the hash of the corresponding block\n" - " \"propertyid\" : nnnnnn, (number) the market this hash applies to (or 0 for all markets)\n" - " \"metadexhash\" : \"hash\" (string) the hash for the state of the MetaDEx/orderbook\n" - "}\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_getmetadexhash", "3") - + HelpExampleRpc("elysium_getmetadexhash", "3") - ); - - LOCK(cs_main); - - uint32_t propertyId = 0; - if (request.params.size() > 0) { - propertyId = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyId); - } - - int block = GetHeight(); - CBlockIndex* pblockindex = chainActive[block]; - uint256 blockHash = pblockindex->GetBlockHash(); - - uint256 metadexHash = GetMetaDExHash(propertyId); - - UniValue response(UniValue::VOBJ); - response.push_back(Pair("block", block)); - response.push_back(Pair("blockhash", blockHash.GetHex())); - response.push_back(Pair("propertyid", (uint64_t)propertyId)); - response.push_back(Pair("metadexhash", metadexHash.GetHex())); - - return response; -} - -UniValue elysium_getbalanceshash(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_getbalanceshash propertyid\n" - "\nReturns a hash of the balances for the property.\n" - "\nArguments:\n" - "1. propertyid (number, required) the property to hash balances for\n" - "\nResult:\n" - "{\n" - " \"block\" : nnnnnn, (number) the index of the block this hash applies to\n" - " \"blockhash\" : \"hash\", (string) the hash of the corresponding block\n" - " \"propertyid\" : nnnnnn, (number) the property id of the hashed balances\n" - " \"balanceshash\" : \"hash\" (string) the hash for the balances\n" - "}\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_getbalanceshash", "31") - + HelpExampleRpc("elysium_getbalanceshash", "31") - ); - - LOCK(cs_main); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyId); - - int block = GetHeight(); - CBlockIndex* pblockindex = chainActive[block]; - uint256 blockHash = pblockindex->GetBlockHash(); - - uint256 balancesHash = GetBalancesHash(propertyId); - - UniValue response(UniValue::VOBJ); - response.push_back(Pair("block", block)); - response.push_back(Pair("blockhash", blockHash.GetHex())); - response.push_back(Pair("propertyid", (uint64_t)propertyId)); - response.push_back(Pair("balanceshash", balancesHash.GetHex())); - - return response; -} - -static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode - // ------------------------------------ ------------------------------- ------------------------------ ---------- - { "elysium (data retrieval)", "elysium_getinfo", &elysium_getinfo, true }, - { "elysium (data retrieval)", "elysium_getactivations", &elysium_getactivations, true }, - { "elysium (data retrieval)", "elysium_getallbalancesforid", &elysium_getallbalancesforid, false }, - { "elysium (data retrieval)", "elysium_getbalance", &elysium_getbalance, false }, - { "elysium (data retrieval)", "elysium_gettransaction", &elysium_gettransaction, false }, - { "elysium (data retrieval)", "elysium_getproperty", &elysium_getproperty, false }, - { "elysium (data retrieval)", "elysium_listproperties", &elysium_listproperties, false }, - { "elysium (data retrieval)", "elysium_getcrowdsale", &elysium_getcrowdsale, false }, - { "elysium (data retrieval)", "elysium_getgrants", &elysium_getgrants, false }, - { "elysium (data retrieval)", "elysium_getactivedexsells", &elysium_getactivedexsells, false }, - { "elysium (data retrieval)", "elysium_getactivecrowdsales", &elysium_getactivecrowdsales, false }, - { "elysium (data retrieval)", "elysium_getorderbook", &elysium_getorderbook, false }, - { "elysium (data retrieval)", "elysium_gettrade", &elysium_gettrade, false }, - { "elysium (data retrieval)", "elysium_getsto", &elysium_getsto, false }, - { "elysium (data retrieval)", "elysium_listblocktransactions", &elysium_listblocktransactions, false }, - { "elysium (data retrieval)", "elysium_listpendingtransactions", &elysium_listpendingtransactions, false }, - { "elysium (data retrieval)", "elysium_getallbalancesforaddress", &elysium_getallbalancesforaddress, false }, - { "elysium (data retrieval)", "elysium_gettradehistoryforaddress", &elysium_gettradehistoryforaddress, false }, - { "elysium (data retrieval)", "elysium_gettradehistoryforpair", &elysium_gettradehistoryforpair, false }, - { "elysium (data retrieval)", "elysium_getcurrentconsensushash", &elysium_getcurrentconsensushash, false }, - { "elysium (data retrieval)", "elysium_getpayload", &elysium_getpayload, false }, - { "elysium (data retrieval)", "elysium_getseedblocks", &elysium_getseedblocks, false }, - { "elysium (data retrieval)", "elysium_getmetadexhash", &elysium_getmetadexhash, false }, - { "elysium (data retrieval)", "elysium_getfeecache", &elysium_getfeecache, false }, - { "elysium (data retrieval)", "elysium_getfeetrigger", &elysium_getfeetrigger, false }, - { "elysium (data retrieval)", "elysium_getfeedistribution", &elysium_getfeedistribution, false }, - { "elysium (data retrieval)", "elysium_getfeedistributions", &elysium_getfeedistributions, false }, - { "elysium (data retrieval)", "elysium_getbalanceshash", &elysium_getbalanceshash, false }, -#ifdef ENABLE_WALLET - { "elysium (data retrieval)", "elysium_listtransactions", &elysium_listtransactions, false }, - { "elysium (data retrieval)", "elysium_listmints", &elysium_listmints, false }, - { "elysium (data retrieval)", "elysium_listpendingmints", &elysium_listpendingmints, false }, - { "elysium (data retrieval)", "elysium_getfeeshare", &elysium_getfeeshare, false }, - { "elysium (configuration)", "elysium_setautocommit", &elysium_setautocommit, true }, -#endif - { "hidden", "elysiumrpc", &elysiumrpc, true }, - - /* depreciated: */ - { "hidden", "getinfo_MP", &elysium_getinfo, true }, - { "hidden", "getbalance_MP", &elysium_getbalance, false }, - { "hidden", "getallbalancesforaddress_MP", &elysium_getallbalancesforaddress, false }, - { "hidden", "getallbalancesforid_MP", &elysium_getallbalancesforid, false }, - { "hidden", "getproperty_MP", &elysium_getproperty, false }, - { "hidden", "listproperties_MP", &elysium_listproperties, false }, - { "hidden", "getcrowdsale_MP", &elysium_getcrowdsale, false }, - { "hidden", "getgrants_MP", &elysium_getgrants, false }, - { "hidden", "getactivedexsells_MP", &elysium_getactivedexsells, false }, - { "hidden", "getactivecrowdsales_MP", &elysium_getactivecrowdsales, false }, - { "hidden", "getsto_MP", &elysium_getsto, false }, - { "hidden", "getorderbook_MP", &elysium_getorderbook, false }, - { "hidden", "gettrade_MP", &elysium_gettrade, false }, - { "hidden", "gettransaction_MP", &elysium_gettransaction, false }, - { "hidden", "listblocktransactions_MP", &elysium_listblocktransactions, false }, -#ifdef ENABLE_WALLET - { "hidden", "listtransactions_MP", &elysium_listtransactions, false }, -#endif -}; - -void RegisterElysiumDataRetrievalRPCCommands(CRPCTable &tableRPC) -{ - for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); -} diff --git a/src/elysium/rpc.h b/src/elysium/rpc.h deleted file mode 100644 index aa79e484ba..0000000000 --- a/src/elysium/rpc.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ - -/* - * File: rpc.h - * Author: dexx - * - * Created on 13. Oktober 2016, 23:32 - */ - -#ifndef RPC_H -#define RPC_H - -/** Throws a JSONRPCError, depending on error code. */ -void PopulateFailure(int error); - - - -#endif /* RPC_H */ - diff --git a/src/elysium/rpcpayload.cpp b/src/elysium/rpcpayload.cpp deleted file mode 100644 index fff6e27722..0000000000 --- a/src/elysium/rpcpayload.cpp +++ /dev/null @@ -1,719 +0,0 @@ -#include "elysium/rpcpayload.h" - -#include "elysium/createpayload.h" -#include "elysium/rpcvalues.h" -#include "elysium/rpcrequirements.h" -#include "elysium/elysium.h" -#include "elysium/sp.h" -#include "elysium/tx.h" - -#include "rpc/server.h" -#include "utilstrencodings.h" - -#include - -using std::runtime_error; -using namespace elysium; - -UniValue elysium_createpayload_simplesend(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_createpayload_simplesend propertyid \"amount\"\n" - - "\nCreate the payload for a simple send transaction.\n" - - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the tokens to send\n" - "2. amount (string, required) the amount to send\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_simplesend", "1 \"100.0\"") - + HelpExampleRpc("elysium_createpayload_simplesend", "1, \"100.0\"") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyId); - int64_t amount = ParseAmount(request.params[1], isPropertyDivisible(propertyId)); - - std::vector payload = CreatePayload_SimpleSend(propertyId, amount); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_sendall(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_createpayload_sendall ecosystem\n" - - "\nCreate the payload for a send all transaction.\n" - - "\nArguments:\n" - "1. ecosystem (number, required) the ecosystem of the tokens to send (1 for main ecosystem, 2 for test ecosystem)\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_sendall", "2") - + HelpExampleRpc("elysium_createpayload_sendall", "2") - ); - - uint8_t ecosystem = ParseEcosystem(request.params[0]); - - std::vector payload = CreatePayload_SendAll(ecosystem); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_dexsell(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 6) - throw runtime_error( - "elysium_createpayload_dexsell propertyidforsale \"amountforsale\" \"amountdesired\" paymentwindow minacceptfee action\n" - - "\nCreate a payload to place, update or cancel a sell offer on the traditional distributed ELYSIUM/FIRO exchange.\n" - - "\nArguments:\n" - - "1. propertyidforsale (number, required) the identifier of the tokens to list for sale (must be 1 for ELYSIUM or 2 for TELYSIUM)\n" - "2. amountforsale (string, required) the amount of tokens to list for sale\n" - "3. amountdesired (string, required) the amount of bitcoins desired\n" - "4. paymentwindow (number, required) a time limit in blocks a buyer has to pay following a successful accepting order\n" - "5. minacceptfee (string, required) a minimum mining fee a buyer has to pay to accept the offer\n" - "6. action (number, required) the action to take (1 for new offers, 2 to update\", 3 to cancel)\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_dexsell", "1 \"1.5\" \"0.75\" 25 \"0.0005\" 1") - + HelpExampleRpc("elysium_createpayload_dexsell", "1, \"1.5\", \"0.75\", 25, \"0.0005\", 1") - ); - - uint32_t propertyIdForSale = ParsePropertyId(request.params[0]); - uint8_t action = ParseDExAction(request.params[5]); - - int64_t amountForSale = 0; // depending on action - int64_t amountDesired = 0; // depending on action - uint8_t paymentWindow = 0; // depending on action - int64_t minAcceptFee = 0; // depending on action - - if (action <= CMPTransaction::UPDATE) { // actions 3 permit zero values, skip check - amountForSale = ParseAmount(request.params[1], true); // TELYSIUM/ELYSIUM is divisible - amountDesired = ParseAmount(request.params[2], true); // FIRO is divisible - paymentWindow = ParseDExPaymentWindow(request.params[3]); - minAcceptFee = ParseDExFee(request.params[4]); - } - - std::vector payload = CreatePayload_DExSell(propertyIdForSale, amountForSale, amountDesired, paymentWindow, minAcceptFee, action); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_dexaccept(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_createpayload_dexaccept propertyid \"amount\"\n" - - "\nCreate the payload for an accept offer for the specified token and amount.\n" - - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the token to purchase\n" - "2. amount (string, required) the amount to accept\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_dexaccept", "1 \"15.0\"") - + HelpExampleRpc("elysium_createpayload_dexaccept", "1, \"15.0\"") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - RequirePrimaryToken(propertyId); - int64_t amount = ParseAmount(request.params[1], true); - - std::vector payload = CreatePayload_DExAccept(propertyId, amount); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_sto(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw runtime_error( - "elysium_createpayload_sto propertyid \"amount\" ( distributionproperty )\n" - - "\nCreates the payload for a send-to-owners transaction.\n" - - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the tokens to distribute\n" - "2. amount (string, required) the amount to distribute\n" - "3. distributionproperty (number, optional) the identifier of the property holders to distribute to\n" - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_sto", "3 \"5000\"") - + HelpExampleRpc("elysium_createpayload_sto", "3, \"5000\"") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyId); - int64_t amount = ParseAmount(request.params[1], isPropertyDivisible(propertyId)); - uint32_t distributionPropertyId = (request.params.size() > 2) ? ParsePropertyId(request.params[2]) : propertyId; - - std::vector payload = CreatePayload_SendToOwners(propertyId, amount, distributionPropertyId); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_issuancefixed(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 9) - throw runtime_error( - "elysium_createpayload_issuancefixed ecosystem type previousid \"category\" \"subcategory\" \"name\" \"url\" \"data\" \"amount\"\n" - - "\nCreates the payload for a new tokens issuance with fixed supply.\n" - - "\nArguments:\n" - "1. ecosystem (string, required) the ecosystem to create the tokens in (1 for main ecosystem, 2 for test ecosystem)\n" - "2. type (number, required) the type of the tokens to create: (1 for indivisible tokens, 2 for divisible tokens)\n" - "3. previousid (number, required) an identifier of a predecessor token (use 0 for new tokens)\n" - "4. category (string, required) a category for the new tokens (can be \"\")\n" - "5. subcategory (string, required) a subcategory for the new tokens (can be \"\")\n" - "6. name (string, required) the name of the new tokens to create\n" - "7. url (string, required) an URL for further information about the new tokens (can be \"\")\n" - "8. data (string, required) a description for the new tokens (can be \"\")\n" - "9. amount (string, required) the number of tokens to create\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_issuancefixed", "2 1 0 \"Companies\" \"Firo Mining\" \"Quantum Miner\" \"\" \"\" \"1000000\"") - + HelpExampleRpc("elysium_createpayload_issuancefixed", "2, 1, 0, \"Companies\", \"Firo Mining\", \"Quantum Miner\", \"\", \"\", \"1000000\"") - ); - - uint8_t ecosystem = ParseEcosystem(request.params[0]); - uint16_t type = ParsePropertyType(request.params[1]); - uint32_t previousId = ParsePreviousPropertyId(request.params[2]); - std::string category = ParseText(request.params[3]); - std::string subcategory = ParseText(request.params[4]); - std::string name = ParseText(request.params[5]); - std::string url = ParseText(request.params[6]); - std::string data = ParseText(request.params[7]); - int64_t amount = ParseAmount(request.params[8], type); - - RequirePropertyName(name); - - std::vector payload = CreatePayload_IssuanceFixed(ecosystem, type, previousId, category, subcategory, name, url, data, amount); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_issuancecrowdsale(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 13) - throw runtime_error( - "elysium_createpayload_issuancecrowdsale ecosystem type previousid \"category\" \"subcategory\" \"name\" \"url\" \"data\" propertyiddesired tokensperunit deadline earlybonus issuerpercentage\n" - - "\nCreates the payload for a new tokens issuance with crowdsale.\n" - - "\nArguments:\n" - "1. ecosystem (string, required) the ecosystem to create the tokens in (1 for main ecosystem, 2 for test ecosystem)\n" - "2. type (number, required) the type of the tokens to create: (1 for indivisible tokens, 2 for divisible tokens)\n" - "3. previousid (number, required) an identifier of a predecessor token (0 for new crowdsales)\n" - "4. category (string, required) a category for the new tokens (can be \"\")\n" - "5. subcategory (string, required) a subcategory for the new tokens (can be \"\")\n" - "6. name (string, required) the name of the new tokens to create\n" - "7. url (string, required) an URL for further information about the new tokens (can be \"\")\n" - "8. data (string, required) a description for the new tokens (can be \"\")\n" - "9. propertyiddesired (number, required) the identifier of a token eligible to participate in the crowdsale\n" - "10. tokensperunit (string, required) the amount of tokens granted per unit invested in the crowdsale\n" - "11. deadline (number, required) the deadline of the crowdsale as Unix timestamp\n" - "12. earlybonus (number, required) an early bird bonus for participants in percent per week\n" - "13. issuerpercentage (number, required) a percentage of tokens that will be granted to the issuer\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_issuancecrowdsale", "2 1 0 \"Companies\" \"Firo Mining\" \"Quantum Miner\" \"\" \"\" 2 \"100\" 1483228800 30 2") - + HelpExampleRpc("elysium_createpayload_issuancecrowdsale", "2, 1, 0, \"Companies\", \"Firo Mining\", \"Quantum Miner\", \"\", \"\", 2, \"100\", 1483228800, 30, 2") - ); - - uint8_t ecosystem = ParseEcosystem(request.params[0]); - uint16_t type = ParsePropertyType(request.params[1]); - uint32_t previousId = ParsePreviousPropertyId(request.params[2]); - std::string category = ParseText(request.params[3]); - std::string subcategory = ParseText(request.params[4]); - std::string name = ParseText(request.params[5]); - std::string url = ParseText(request.params[6]); - std::string data = ParseText(request.params[7]); - uint32_t propertyIdDesired = ParsePropertyId(request.params[8]); - int64_t numTokens = ParseAmount(request.params[9], type); - int64_t deadline = ParseDeadline(request.params[10]); - uint8_t earlyBonus = ParseEarlyBirdBonus(request.params[11]); - uint8_t issuerPercentage = ParseIssuerBonus(request.params[12]); - - RequirePropertyName(name); - RequireExistingProperty(propertyIdDesired); - RequireSameEcosystem(ecosystem, propertyIdDesired); - - std::vector payload = CreatePayload_IssuanceVariable(ecosystem, type, previousId, category, subcategory, name, url, data, propertyIdDesired, numTokens, deadline, earlyBonus, issuerPercentage); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_issuancemanaged(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 8) - throw runtime_error( - "elysium_createpayload_issuancemanaged ecosystem type previousid \"category\" \"subcategory\" \"name\" \"url\" \"data\"\n" - - "\nCreates the payload for a new tokens issuance with manageable supply.\n" - - "\nArguments:\n" - "1. ecosystem (string, required) the ecosystem to create the tokens in (1 for main ecosystem, 2 for test ecosystem)\n" - "2. type (number, required) the type of the tokens to create: (1 for indivisible tokens, 2 for divisible tokens)\n" - "3. previousid (number, required) an identifier of a predecessor token (use 0 for new tokens)\n" - "4. category (string, required) a category for the new tokens (can be \"\")\n" - "5. subcategory (string, required) a subcategory for the new tokens (can be \"\")\n" - "6. name (string, required) the name of the new tokens to create\n" - "7. url (string, required) an URL for further information about the new tokens (can be \"\")\n" - "8. data (string, required) a description for the new tokens (can be \"\")\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_issuancemanaged", "2 1 0 \"Companies\" \"Firo Mining\" \"Quantum Miner\" \"\" \"\"") - + HelpExampleRpc("elysium_createpayload_issuancemanaged", "2, 1, 0, \"Companies\", \"Firo Mining\", \"Quantum Miner\", \"\", \"\"") - ); - - uint8_t ecosystem = ParseEcosystem(request.params[0]); - uint16_t type = ParsePropertyType(request.params[1]); - uint32_t previousId = ParsePreviousPropertyId(request.params[2]); - std::string category = ParseText(request.params[3]); - std::string subcategory = ParseText(request.params[4]); - std::string name = ParseText(request.params[5]); - std::string url = ParseText(request.params[6]); - std::string data = ParseText(request.params[7]); - - RequirePropertyName(name); - - std::vector payload = CreatePayload_IssuanceManaged(ecosystem, type, previousId, category, subcategory, name, url, data); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_closecrowdsale(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_createpayload_closecrowdsale propertyid\n" - - "\nCreates the payload to manually close a crowdsale.\n" - - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the crowdsale to close\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_closecrowdsale", "70") - + HelpExampleRpc("elysium_createpayload_closecrowdsale", "70") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - - // checks bypassed because someone may wish to prepare the payload to close a crowdsale creation not yet broadcast - - std::vector payload = CreatePayload_CloseCrowdsale(propertyId); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_grant(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw runtime_error( - "elysium_createpayload_grant propertyid \"amount\" ( \"memo\" )\n" - - "\nCreates the payload to issue or grant new units of managed tokens.\n" - - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the tokens to grant\n" - "2. amount (string, required) the amount of tokens to create\n" - "3. memo (string, optional) a text note attached to this transaction (none by default)\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_grant", "51 \"7000\"") - + HelpExampleRpc("elysium_createpayload_grant", "51, \"7000\"") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - int64_t amount = ParseAmount(request.params[1], isPropertyDivisible(propertyId)); - std::string memo = (request.params.size() > 2) ? ParseText(request.params[2]): ""; - - std::vector payload = CreatePayload_Grant(propertyId, amount, memo); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_revoke(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw runtime_error( - "elysium_createpayload_revoke propertyid \"amount\" ( \"memo\" )\n" - - "\nCreates the payload to revoke units of managed tokens.\n" - - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the tokens to revoke\n" - "2. amount (string, required) the amount of tokens to revoke\n" - "3. memo (string, optional) a text note attached to this transaction (none by default)\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_revoke", "51 \"100\"") - + HelpExampleRpc("elysium_createpayload_revoke", "51, \"100\"") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - int64_t amount = ParseAmount(request.params[1], isPropertyDivisible(propertyId)); - std::string memo = (request.params.size() > 2) ? ParseText(request.params[2]): ""; - - std::vector payload = CreatePayload_Revoke(propertyId, amount, memo); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_changeissuer(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_createpayload_changeissuer propertyid\n" - - "\nCreats the payload to change the issuer on record of the given tokens.\n" - - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the tokens\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_changeissuer", "3") - + HelpExampleRpc("elysium_createpayload_changeissuer", "3") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyId); - - std::vector payload = CreatePayload_ChangeIssuer(propertyId); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_trade(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 4) - throw runtime_error( - "elysium_createpayload_trade propertyidforsale \"amountforsale\" propertiddesired \"amountdesired\"\n" - - "\nCreates the payload to place a trade offer on the distributed token exchange.\n" - - "\nArguments:\n" - "1. propertyidforsale (number, required) the identifier of the tokens to list for sale\n" - "2. amountforsale (string, required) the amount of tokens to list for sale\n" - "3. propertiddesired (number, required) the identifier of the tokens desired in exchange\n" - "4. amountdesired (string, required) the amount of tokens desired in exchange\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_trade", "31 \"250.0\" 1 \"10.0\"") - + HelpExampleRpc("elysium_createpayload_trade", "31, \"250.0\", 1, \"10.0\"") - ); - - uint32_t propertyIdForSale = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyIdForSale); - int64_t amountForSale = ParseAmount(request.params[1], isPropertyDivisible(propertyIdForSale)); - uint32_t propertyIdDesired = ParsePropertyId(request.params[2]); - RequireExistingProperty(propertyIdDesired); - int64_t amountDesired = ParseAmount(request.params[3], isPropertyDivisible(propertyIdDesired)); - RequireSameEcosystem(propertyIdForSale, propertyIdDesired); - RequireDifferentIds(propertyIdForSale, propertyIdDesired); - RequireDifferentIds(propertyIdForSale, propertyIdDesired); - - std::vector payload = CreatePayload_MetaDExTrade(propertyIdForSale, amountForSale, propertyIdDesired, amountDesired); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_canceltradesbyprice(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 4) - throw runtime_error( - "elysium_createpayload_canceltradesbyprice propertyidforsale \"amountforsale\" propertiddesired \"amountdesired\"\n" - - "\nCreates the payload to cancel offers on the distributed token exchange with the specified price.\n" - - "\nArguments:\n" - "1. propertyidforsale (number, required) the identifier of the tokens listed for sale\n" - "2. amountforsale (string, required) the amount of tokens to listed for sale\n" - "3. propertiddesired (number, required) the identifier of the tokens desired in exchange\n" - "4. amountdesired (string, required) the amount of tokens desired in exchange\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_canceltradesbyprice", "31 \"100.0\" 1 \"5.0\"") - + HelpExampleRpc("elysium_createpayload_canceltradesbyprice", "31, \"100.0\", 1, \"5.0\"") - ); - - uint32_t propertyIdForSale = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyIdForSale); - int64_t amountForSale = ParseAmount(request.params[1], isPropertyDivisible(propertyIdForSale)); - uint32_t propertyIdDesired = ParsePropertyId(request.params[2]); - RequireExistingProperty(propertyIdDesired); - int64_t amountDesired = ParseAmount(request.params[3], isPropertyDivisible(propertyIdDesired)); - RequireSameEcosystem(propertyIdForSale, propertyIdDesired); - RequireDifferentIds(propertyIdForSale, propertyIdDesired); - - std::vector payload = CreatePayload_MetaDExCancelPrice(propertyIdForSale, amountForSale, propertyIdDesired, amountDesired); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_canceltradesbypair(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_createpayload_canceltradesbypair propertyidforsale propertiddesired\n" - - "\nCreates the payload to cancel all offers on the distributed token exchange with the given currency pair.\n" - - "\nArguments:\n" - "1. propertyidforsale (number, required) the identifier of the tokens listed for sale\n" - "2. propertiddesired (number, required) the identifier of the tokens desired in exchange\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_canceltradesbypair", "1 31") - + HelpExampleRpc("elysium_createpayload_canceltradesbypair", "1, 31") - ); - - uint32_t propertyIdForSale = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyIdForSale); - uint32_t propertyIdDesired = ParsePropertyId(request.params[1]); - RequireExistingProperty(propertyIdDesired); - RequireSameEcosystem(propertyIdForSale, propertyIdDesired); - RequireDifferentIds(propertyIdForSale, propertyIdDesired); - - std::vector payload = CreatePayload_MetaDExCancelPair(propertyIdForSale, propertyIdDesired); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_cancelalltrades(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_createpayload_cancelalltrades ecosystem\n" - - "\nCreates the payload to cancel all offers on the distributed token exchange.\n" - - "\nArguments:\n" - "1. ecosystem (number, required) the ecosystem of the offers to cancel (1 for main ecosystem, 2 for test ecosystem)\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_cancelalltrades", "1") - + HelpExampleRpc("elysium_createpayload_cancelalltrades", "1") - ); - - uint8_t ecosystem = ParseEcosystem(request.params[0]); - - std::vector payload = CreatePayload_MetaDExCancelEcosystem(ecosystem); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_enablefreezing(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_createpayload_enablefreezing propertyid\n" - - "\nCreates the payload to enable address freezing for a centrally managed property.\n" - - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the tokens\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_enablefreezing", "3") - + HelpExampleRpc("elysium_createpayload_enablefreezing", "3") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - - std::vector payload = CreatePayload_EnableFreezing(propertyId); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_disablefreezing(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "elysium_createpayload_disablefreezing propertyid\n" - - "\nCreates the payload to disable address freezing for a centrally managed property.\n" - "\nIMPORTANT NOTE: Disabling freezing for a property will UNFREEZE all frozen addresses for that property!" - - "\nArguments:\n" - "1. propertyid (number, required) the identifier of the tokens\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_disablefreezing", "3") - + HelpExampleRpc("elysium_createpayload_disablefreezing", "3") - ); - - uint32_t propertyId = ParsePropertyId(request.params[0]); - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - - std::vector payload = CreatePayload_DisableFreezing(propertyId); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_freeze(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 3) - throw runtime_error( - "elysium_createpayload_freeze \"toaddress\" propertyid amount \n" - - "\nCreates the payload to freeze an address for a centrally managed token.\n" - - "\nArguments:\n" - "1. toaddress (string, required) the address to freeze tokens for\n" - "2. propertyid (number, required) the property to freeze tokens for (must be managed type and have freezing option enabled)\n" - "3. amount (number, required) the amount of tokens to freeze (note: this is unused - once frozen an address cannot send any transactions)\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_freeze", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\" 1 0") - + HelpExampleRpc("elysium_createpayload_freeze", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\", 1, 0") - ); - - std::string refAddress = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - int64_t amount = ParseAmount(request.params[2], isPropertyDivisible(propertyId)); - - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - - std::vector payload = CreatePayload_FreezeTokens(propertyId, amount, refAddress); - - return HexStr(payload.begin(), payload.end()); -} - -UniValue elysium_createpayload_unfreeze(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 3) - throw runtime_error( - "elysium_createpayload_unfreeze \"toaddress\" propertyid amount \n" - - "\nCreates the payload to unfreeze an address for a centrally managed token.\n" - - "\nArguments:\n" - "1. toaddress (string, required) the address to unfreeze tokens for\n" - "2. propertyid (number, required) the property to unfreeze tokens for (must be managed type and have freezing option enabled)\n" - "3. amount (number, required) the amount of tokens to unfreeze (note: this is unused)\n" - - "\nResult:\n" - "\"payload\" (string) the hex-encoded payload\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_createpayload_unfreeze", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\" 1 0") - + HelpExampleRpc("elysium_createpayload_unfreeze", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\", 1, 0") - ); - - std::string refAddress = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - int64_t amount = ParseAmount(request.params[2], isPropertyDivisible(propertyId)); - - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - - std::vector payload = CreatePayload_UnfreezeTokens(propertyId, amount, refAddress); - - return HexStr(payload.begin(), payload.end()); -} - -static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode - // -------------------------------- ----------------------------------------- ---------------------------------------- ---------- - { "elysium (payload creation)", "elysium_createpayload_simplesend", &elysium_createpayload_simplesend, true }, - { "elysium (payload creation)", "elysium_createpayload_sendall", &elysium_createpayload_sendall, true }, - { "elysium (payload creation)", "elysium_createpayload_dexsell", &elysium_createpayload_dexsell, true }, - { "elysium (payload creation)", "elysium_createpayload_dexaccept", &elysium_createpayload_dexaccept, true }, - { "elysium (payload creation)", "elysium_createpayload_sto", &elysium_createpayload_sto, true }, - { "elysium (payload creation)", "elysium_createpayload_grant", &elysium_createpayload_grant, true }, - { "elysium (payload creation)", "elysium_createpayload_revoke", &elysium_createpayload_revoke, true }, - { "elysium (payload creation)", "elysium_createpayload_changeissuer", &elysium_createpayload_changeissuer, true }, - { "elysium (payload creation)", "elysium_createpayload_trade", &elysium_createpayload_trade, true }, - { "elysium (payload creation)", "elysium_createpayload_issuancefixed", &elysium_createpayload_issuancefixed, true }, - { "elysium (payload creation)", "elysium_createpayload_issuancecrowdsale", &elysium_createpayload_issuancecrowdsale, true }, - { "elysium (payload creation)", "elysium_createpayload_issuancemanaged", &elysium_createpayload_issuancemanaged, true }, - { "elysium (payload creation)", "elysium_createpayload_closecrowdsale", &elysium_createpayload_closecrowdsale, true }, - { "elysium (payload creation)", "elysium_createpayload_canceltradesbyprice", &elysium_createpayload_canceltradesbyprice, true }, - { "elysium (payload creation)", "elysium_createpayload_canceltradesbypair", &elysium_createpayload_canceltradesbypair, true }, - { "elysium (payload creation)", "elysium_createpayload_cancelalltrades", &elysium_createpayload_cancelalltrades, true }, - { "elysium (payload creation)", "elysium_createpayload_enablefreezing", &elysium_createpayload_enablefreezing, true }, - { "elysium (payload creation)", "elysium_createpayload_disablefreezing", &elysium_createpayload_disablefreezing, true }, - { "elysium (payload creation)", "elysium_createpayload_freeze", &elysium_createpayload_freeze, true }, - { "elysium (payload creation)", "elysium_createpayload_unfreeze", &elysium_createpayload_unfreeze, true }, -}; - -void RegisterElysiumPayloadCreationRPCCommands(CRPCTable &tableRPC) -{ - for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); -} diff --git a/src/elysium/rpcpayload.h b/src/elysium/rpcpayload.h deleted file mode 100644 index d944f8917d..0000000000 --- a/src/elysium/rpcpayload.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ELYSIUM_RPCPAYLOAD_H -#define ELYSIUM_RPCPAYLOAD_H - -#include -#include "rpc/server.h" - -UniValue elysium_createpayload_simplesend(const JSONRPCRequest& request); -UniValue elysium_createpayload_sendall(const JSONRPCRequest& request); -UniValue elysium_createpayload_dexsell(const JSONRPCRequest& request); -UniValue elysium_createpayload_dexaccept(const JSONRPCRequest& request); -UniValue elysium_createpayload_sto(const JSONRPCRequest& request); -UniValue elysium_createpayload_issuancefixed(const JSONRPCRequest& request); -UniValue elysium_createpayload_issuancecrowdsale(const JSONRPCRequest& request); -UniValue elysium_createpayload_issuancemanaged(const JSONRPCRequest& request); -UniValue elysium_createpayload_closecrowdsale(const JSONRPCRequest& request); -UniValue elysium_createpayload_grant(const JSONRPCRequest& request); -UniValue elysium_createpayload_revoke(const JSONRPCRequest& request); -UniValue elysium_createpayload_changeissuer(const JSONRPCRequest& request); -UniValue elysium_createpayload_trade(const JSONRPCRequest& request); -UniValue elysium_createpayload_canceltradesbyprice(const JSONRPCRequest& request); -UniValue elysium_createpayload_canceltradesbypair(const JSONRPCRequest& request); -UniValue elysium_createpayload_cancelalltrades(const JSONRPCRequest& request); - -#endif // ELYSIUM_RPCPAYLOAD_H diff --git a/src/elysium/rpcrawtx.cpp b/src/elysium/rpcrawtx.cpp deleted file mode 100644 index 36a3d49904..0000000000 --- a/src/elysium/rpcrawtx.cpp +++ /dev/null @@ -1,335 +0,0 @@ -#include "elysium/rpcrawtx.h" - -#include "elysium/createtx.h" -#include "elysium/elysium.h" -#include "elysium/rpc.h" -#include "elysium/rpctxobject.h" -#include "elysium/rpcvalues.h" - -#include "coins.h" -#include "core_io.h" -#include "primitives/transaction.h" -#include "pubkey.h" -#include "rpc/server.h" -#include "sync.h" -#include "uint256.h" -#include "utilstrencodings.h" - -#include - -#include -#include -#include - -extern CCriticalSection cs_main; - -using elysium::cs_tx_cache; -using elysium::view; - - -UniValue elysium_decodetransaction(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) - throw std::runtime_error( - "elysium_decodetransaction \"rawtx\" ( \"prevtxs\" height )\n" - - "\nDecodes an Elysium transaction.\n" - - "\nIf the inputs of the transaction are not in the chain, then they must be provided, because " - "the transaction inputs are used to identify the sender of a transaction.\n" - - "\nA block height can be provided, which is used to determine the parsing rules.\n" - - "\nArguments:\n" - "1. rawtx (string, required) the raw transaction to decode\n" - "2. prevtxs (string, optional) a JSON array of transaction inputs (default: none)\n" - " [\n" - " {\n" - " \"txid\":\"hash\", (string, required) the transaction hash\n" - " \"vout\":n, (number, required) the output number\n" - " \"scriptPubKey\":\"hex\", (string, required) the output script\n" - " \"value\":n.nnnnnnnn (number, required) the output value\n" - " }\n" - " ,...\n" - " ]\n" - "3. height (number, optional) the parsing block height (default: 0 for chain height)\n" - - "\nResult:\n" - "{\n" - " \"txid\" : \"hash\", (string) the hex-encoded hash of the transaction\n" - " \"fee\" : \"n.nnnnnnnn\", (string) the transaction fee in firos\n" - " \"sendingaddress\" : \"address\", (string) the Firo address of the sender\n" - " \"referenceaddress\" : \"address\", (string) a Firo address used as reference (if any)\n" - " \"ismine\" : true|false, (boolean) whether the transaction involes an address in the wallet\n" - " \"version\" : n, (number) the transaction version\n" - " \"type_int\" : n, (number) the transaction type as number\n" - " \"type\" : \"type\", (string) the transaction type as string\n" - " [...] (mixed) other transaction type specific properties\n" - "}\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_decodetransaction", "\"010000000163af14ce6d477e1c793507e32a5b7696288fa89705c0d02a3f66beb3c5b8afee0100000000ffffffff02ac020000000000004751210261ea979f6a06f9dafe00fb1263ea0aca959875a7073556a088cdfadcd494b3752102a3fd0a8a067e06941e066f78d930bfc47746f097fcd3f7ab27db8ddf37168b6b52ae22020000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000\" \"[{\\\"txid\\\":\\\"eeafb8c5b3be663f2ad0c00597a88f2896765b2ae30735791c7e476dce14af63\\\",\\\"vout\\\":1,\\\"scriptPubKey\\\":\\\"76a9149084c0bd89289bc025d0264f7f23148fb683d56c88ac\\\",\\\"value\\\":0.0001123}]\"") - + HelpExampleRpc("elysium_decodetransaction", "\"010000000163af14ce6d477e1c793507e32a5b7696288fa89705c0d02a3f66beb3c5b8afee0100000000ffffffff02ac020000000000004751210261ea979f6a06f9dafe00fb1263ea0aca959875a7073556a088cdfadcd494b3752102a3fd0a8a067e06941e066f78d930bfc47746f097fcd3f7ab27db8ddf37168b6b52ae22020000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000\", [{\"txid\":\"eeafb8c5b3be663f2ad0c00597a88f2896765b2ae30735791c7e476dce14af63\",\"vout\":1,\"scriptPubKey\":\"76a9149084c0bd89289bc025d0264f7f23148fb683d56c88ac\",\"value\":0.0001123}]") - ); - - CTransaction tx = ParseTransaction(request.params[0]); - - // use a dummy coins view to store the user provided transaction inputs - CCoinsView viewDummyTemp; - CCoinsViewCache viewTemp(&viewDummyTemp); - - if (request.params.size() > 1) { - std::vector prevTxsParsed = ParsePrevTxs(request.params[1]); - InputsToView(prevTxsParsed, viewTemp); - } - - int blockHeight = 0; - if (request.params.size() > 2) { - blockHeight = request.params[2].get_int(); - } - - UniValue txObj(UniValue::VOBJ); - int populateResult = -3331; - { - //TODO: The swaps below are temporarily commented out - throw std::runtime_error("Not implemented"); - LOCK2(cs_main, cs_tx_cache); - // temporarily switch global coins view cache for transaction inputs -// std::swap(view, viewTemp); - // then get the results - populateResult = populateRPCTransactionObject(tx, uint256(), txObj, "", false, "", blockHeight); - // and restore the original, unpolluted coins view cache -// std::swap(viewTemp, view); - } - - if (populateResult != 0) PopulateFailure(populateResult); - - return txObj; -} - -UniValue elysium_createrawtx_opreturn(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw std::runtime_error( - "elysium_createrawtx_opreturn \"rawtx\" \"payload\"\n" - - "\nAdds a payload with class C (op-return) encoding to the transaction.\n" - - "\nIf no raw transaction is provided, a new transaction is created.\n" - - "\nIf the data encoding fails, then the transaction is not modified.\n" - - "\nArguments:\n" - "1. rawtx (string, required) the raw transaction to extend (can be null)\n" - "2. payload (string, required) the hex-encoded payload to add\n" - - "\nResult:\n" - "\"rawtx\" (string) the hex-encoded modified raw transaction\n" - - "\nExamples\n" - + HelpExampleCli("elysium_createrawtx_opreturn", "\"01000000000000000000\" \"00000000000000020000000006dac2c0\"") - + HelpExampleRpc("elysium_createrawtx_opreturn", "\"01000000000000000000\", \"00000000000000020000000006dac2c0\"") - ); - - CMutableTransaction tx = ParseMutableTransaction(request.params[0]); - std::vector payload = ParseHexV(request.params[1], "payload"); - - // extend the transaction - tx = ElysiumTxBuilder(tx) - .addOpReturn(payload) - .build(); - - return EncodeHexTx(tx); -} - -UniValue elysium_createrawtx_multisig(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 4) - throw std::runtime_error( - "elysium_createrawtx_multisig \"rawtx\" \"payload\" \"seed\" \"redeemkey\"\n" - - "\nAdds a payload with class B (bare-multisig) encoding to the transaction.\n" - - "\nIf no raw transaction is provided, a new transaction is created.\n" - - "\nIf the data encoding fails, then the transaction is not modified.\n" - - "\nArguments:\n" - "1. rawtx (string, required) the raw transaction to extend (can be null)\n" - "2. payload (string, required) the hex-encoded payload to add\n" - "3. seed (string, required) the seed for obfuscation\n" - "4. redeemkey (string, required) a public key or address for dust redemption\n" - - "\nResult:\n" - "\"rawtx\" (string) the hex-encoded modified raw transaction\n" - - "\nExamples\n" - + HelpExampleCli("elysium_createrawtx_multisig", "\"0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff01aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac00000000\" \"00000000000000020000000000989680\" \"1LifmeXYHeUe2qdKWBGVwfbUCMMrwYtoMm\" \"0252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3\"") - + HelpExampleRpc("elysium_createrawtx_multisig", "\"0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff01aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac00000000\", \"00000000000000020000000000989680\", \"1LifmeXYHeUe2qdKWBGVwfbUCMMrwYtoMm\", \"0252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3\"") - ); - - CMutableTransaction tx = ParseMutableTransaction(request.params[0]); - std::vector payload = ParseHexV(request.params[1], "payload"); - std::string obfuscationSeed = ParseAddressOrEmpty(request.params[2]); - CPubKey redeemKey = ParsePubKeyOrAddress(request.params[3]); - - // extend the transaction - tx = ElysiumTxBuilder(tx) - .addMultisig(payload, obfuscationSeed, redeemKey) - .build(); - - return EncodeHexTx(tx); -} - -UniValue elysium_createrawtx_input(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 3) - throw std::runtime_error( - "elysium_createrawtx_input \"rawtx\" \"txid\" n\n" - - "\nAdds a transaction input to the transaction.\n" - - "\nIf no raw transaction is provided, a new transaction is created.\n" - - "\nArguments:\n" - "1. rawtx (string, required) the raw transaction to extend (can be null)\n" - "2. txid (string, required) the hash of the input transaction\n" - "3. n (number, required) the index of the transaction output used as input\n" - - "\nResult:\n" - "\"rawtx\" (string) the hex-encoded modified raw transaction\n" - - "\nExamples\n" - + HelpExampleCli("elysium_createrawtx_input", "\"01000000000000000000\" \"b006729017df05eda586df9ad3f8ccfee5be340aadf88155b784d1fc0e8342ee\" 0") - + HelpExampleRpc("elysium_createrawtx_input", "\"01000000000000000000\", \"b006729017df05eda586df9ad3f8ccfee5be340aadf88155b784d1fc0e8342ee\", 0") - ); - - CMutableTransaction tx = ParseMutableTransaction(request.params[0]); - uint256 txid = ParseHashV(request.params[1], "txid"); - uint32_t nOut = ParseOutputIndex(request.params[2]); - - // extend the transaction - tx = ElysiumTxBuilder(tx) - .addInput(txid, nOut) - .build(); - - return EncodeHexTx(tx); -} - -UniValue elysium_createrawtx_reference(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw std::runtime_error( - "elysium_createrawtx_reference \"rawtx\" \"destination\" ( amount )\n" - - "\nAdds a reference output to the transaction.\n" - - "\nIf no raw transaction is provided, a new transaction is created.\n" - - "\nThe output value is set to at least the dust threshold.\n" - - "\nArguments:\n" - "1. rawtx (string, required) the raw transaction to extend (can be null)\n" - "2. destination (string, required) the reference address or destination\n" - "3. amount (number, optional) the optional reference amount (minimal by default)\n" - - "\nResult:\n" - "\"rawtx\" (string) the hex-encoded modified raw transaction\n" - - "\nExamples\n" - + HelpExampleCli("elysium_createrawtx_reference", "\"0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff03aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a5121f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000\" \"1CE8bBr1dYZRMnpmyYsFEoexa1YoPz2mfB\" 0.005") - + HelpExampleRpc("elysium_createrawtx_reference", "\"0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff03aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a5121f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000\", \"1CE8bBr1dYZRMnpmyYsFEoexa1YoPz2mfB\", 0.005") - ); - - CMutableTransaction tx = ParseMutableTransaction(request.params[0]); - std::string destination = ParseAddress(request.params[1]); - int64_t amount = (request.params.size() > 2) ? AmountFromValue(request.params[2]) : 0; - - // extend the transaction - tx = ElysiumTxBuilder(tx) - .addReference(destination, amount) - .build(); - - return EncodeHexTx(tx); -} - -UniValue elysium_createrawtx_change(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 4 || request.params.size() > 5) - throw std::runtime_error( - "elysium_createrawtx_change \"rawtx\" \"prevtxs\" \"destination\" fee ( position )\n" - - "\nAdds a change output to the transaction.\n" - - "\nThe provided inputs are not added to the transaction, but only used to " - "determine the change. It is assumed that the inputs were previously added, " - "for example via \"createrawtransaction\".\n" - - "\nOptionally a position can be provided, where the change output should be " - "inserted, starting with 0. If the number of outputs is smaller than the position, " - "then the change output is added to the end. Change outputs should be inserted " - "before reference outputs, and as per default, the change output is added to the " - "first position.\n" - - "\nIf the change amount would be considered as dust, then no change output is added.\n" - - "\nArguments:\n" - "1. rawtx (string, required) the raw transaction to extend\n" - "2. prevtxs (string, required) a JSON array of transaction inputs\n" - " [\n" - " {\n" - " \"txid\":\"hash\", (string, required) the transaction hash\n" - " \"vout\":n, (number, required) the output number\n" - " \"scriptPubKey\":\"hex\", (string, required) the output script\n" - " \"value\":n.nnnnnnnn (number, required) the output value\n" - " }\n" - " ,...\n" - " ]\n" - "3. destination (string, required) the destination for the change\n" - "4. fee (number, required) the desired transaction fees\n" - "5. position (number, optional) the position of the change output (default: first position)\n" - - "\nResult:\n" - "\"rawtx\" (string) the hex-encoded modified raw transaction\n" - - "\nExamples\n" - + HelpExampleCli("elysium_createrawtx_change", "\"0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff025c0d00000000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000\" \"[{\\\"txid\\\":\\\"6779a710fcd5f6fb0883ea3306360c3ad8c0a3c5de902768ec57ef3104e65eb1\\\",\\\"vout\\\":4,\\\"scriptPubKey\\\":\\\"76a9147b25205fd98d462880a3e5b0541235831ae959e588ac\\\",\\\"value\\\":0.00068257}]\" \"1CE8bBr1dYZRMnpmyYsFEoexa1YoPz2mfB\" 0.00003500 1") - + HelpExampleRpc("elysium_createrawtx_change", "\"0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff025c0d00000000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000\", [{\"txid\":\"6779a710fcd5f6fb0883ea3306360c3ad8c0a3c5de902768ec57ef3104e65eb1\",\"vout\":4,\"scriptPubKey\":\"76a9147b25205fd98d462880a3e5b0541235831ae959e588ac\",\"value\":0.00068257}], \"1CE8bBr1dYZRMnpmyYsFEoexa1YoPz2mfB\", 0.00003500, 1") - ); - - CMutableTransaction tx = ParseMutableTransaction(request.params[0]); - std::vector prevTxsParsed = ParsePrevTxs(request.params[1]); - std::string destination = ParseAddress(request.params[2]); - int64_t txFee = AmountFromValue(request.params[3]); - uint32_t nOut = request.params.size() > 4 ? request.params[4].get_int64() : 0; - - // use a dummy coins view to store the user provided transaction inputs - CCoinsView viewDummy; - CCoinsViewCache viewTemp(&viewDummy); - InputsToView(prevTxsParsed, viewTemp); - - // extend the transaction - tx = ElysiumTxBuilder(tx) - .addChange(destination, viewTemp, txFee, nOut) - .build(); - - return EncodeHexTx(tx); -} - -static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode - // -------------------------------- ----------------------------- ---------------------------- ---------- - { "elysium (raw transactions)", "elysium_decodetransaction", &elysium_decodetransaction, true }, - { "elysium (raw transactions)", "elysium_createrawtx_opreturn", &elysium_createrawtx_opreturn, true }, - { "elysium (raw transactions)", "elysium_createrawtx_multisig", &elysium_createrawtx_multisig, true }, - { "elysium (raw transactions)", "elysium_createrawtx_input", &elysium_createrawtx_input, true }, - { "elysium (raw transactions)", "elysium_createrawtx_reference", &elysium_createrawtx_reference, true }, - { "elysium (raw transactions)", "elysium_createrawtx_change", &elysium_createrawtx_change, true }, - -}; - -void RegisterElysiumRawTransactionRPCCommands(CRPCTable &tableRPC) -{ - for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); -} diff --git a/src/elysium/rpcrawtx.h b/src/elysium/rpcrawtx.h deleted file mode 100644 index 003e1a43fb..0000000000 --- a/src/elysium/rpcrawtx.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ELYSIUM_RPCRAWTX_H -#define ELYSIUM_RPCRAWTX_H - -#include -#include "rpc/server.h" - -UniValue elysium_decodetransaction(const JSONRPCRequest& request); -UniValue elysium_createrawtx_opreturn(const JSONRPCRequest& request); -UniValue elysium_createrawtx_multisig(const JSONRPCRequest& request); -UniValue elysium_createrawtx_input(const JSONRPCRequest& request); -UniValue elysium_createrawtx_reference(const JSONRPCRequest& request); -UniValue elysium_createrawtx_change(const JSONRPCRequest& request); - -#endif // ELYSIUM_RPCRAWTX_H diff --git a/src/elysium/rpcrequirements.cpp b/src/elysium/rpcrequirements.cpp deleted file mode 100644 index 1dab8e3329..0000000000 --- a/src/elysium/rpcrequirements.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include "rpcrequirements.h" - -#include "dex.h" -#include "elysium.h" -#include "rules.h" -#include "sp.h" -#include "utilsbitcoin.h" - -#include "../amount.h" -#include "../validation.h" -#include "../rpc/protocol.h" -#include "../sync.h" -#include "../tinyformat.h" - -#include - -#include - -void RequireBalance(const std::string& address, uint32_t propertyId, int64_t amount) -{ - int64_t balance = getMPbalance(address, propertyId, BALANCE); - if (balance < amount) { - throw JSONRPCError(RPC_TYPE_ERROR, "Sender has insufficient balance"); - } - int64_t balanceUnconfirmed = getUserAvailableMPbalance(address, propertyId); - if (balanceUnconfirmed < amount) { - throw JSONRPCError(RPC_TYPE_ERROR, "Sender has insufficient balance (due to pending transactions)"); - } -} - -void RequirePrimaryToken(uint32_t propertyId) -{ - if (propertyId < 1 || 2 < propertyId) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property identifier must be 1 (ELYSIUM) or 2 (TELYSIUM)"); - } -} - -void RequirePropertyName(const std::string& name) -{ - if (name.empty()) { - throw JSONRPCError(RPC_TYPE_ERROR, "Property name must not be empty"); - } -} - -void RequireExistingProperty(uint32_t propertyId) -{ - LOCK(cs_main); - if (!elysium::IsPropertyIdValid(propertyId)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property identifier does not exist"); - } -} - -void RequireSameEcosystem(uint32_t propertyId, uint32_t otherId) -{ - if (elysium::isTestEcosystemProperty(propertyId) != elysium::isTestEcosystemProperty(otherId)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Properties must be in the same ecosystem"); - } -} - -void RequireDifferentIds(uint32_t propertyId, uint32_t otherId) -{ - if (propertyId == otherId) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property identifiers must not be the same"); - } -} - -void RequireCrowdsale(uint32_t propertyId) -{ - LOCK(cs_main); - CMPSPInfo::Entry sp; - if (!elysium::_my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_DATABASE_ERROR, "Failed to retrieve property"); - } - if (sp.fixed || sp.manual) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property identifier does not refer to a crowdsale"); - } -} - -void RequireActiveCrowdsale(uint32_t propertyId) -{ - LOCK(cs_main); - if (!elysium::isCrowdsaleActive(propertyId)) { - throw JSONRPCError(RPC_TYPE_ERROR, "Property identifier does not refer to an active crowdsale"); - } -} - -void RequireManagedProperty(uint32_t propertyId) -{ - LOCK(cs_main); - CMPSPInfo::Entry sp; - if (!elysium::_my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_DATABASE_ERROR, "Failed to retrieve property"); - } - if (sp.fixed || !sp.manual) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property identifier does not refer to a managed property"); - } -} - -void RequireTokenIssuer(const std::string& address, uint32_t propertyId) -{ - LOCK(cs_main); - CMPSPInfo::Entry sp; - if (!elysium::_my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_DATABASE_ERROR, "Failed to retrieve property"); - } - if (address != sp.issuer) { - throw JSONRPCError(RPC_TYPE_ERROR, "Sender is not authorized to manage the property"); - } -} - -void RequireMatchingDExOffer(const std::string& address, uint32_t propertyId) -{ - LOCK(cs_main); - if (!elysium::DEx_offerExists(address, propertyId)) { - throw JSONRPCError(RPC_TYPE_ERROR, "No matching sell offer on the distributed exchange"); - } -} - -void RequireNoOtherDExOffer(const std::string& address, uint32_t propertyId) -{ - LOCK(cs_main); - if (elysium::DEx_offerExists(address, propertyId)) { - throw JSONRPCError(RPC_TYPE_ERROR, "Another active sell offer from the given address already exists on the distributed exchange"); - } -} - -void RequireSaneReferenceAmount(int64_t amount) -{ - if ((0.01 * COIN) < amount) { - throw JSONRPCError(RPC_TYPE_ERROR, "Reference amount higher is than 0.01 FIRO"); - } -} - -void RequireSaneDExPaymentWindow(const std::string& address, uint32_t propertyId) -{ - LOCK(cs_main); - const CMPOffer* poffer = elysium::DEx_getOffer(address, propertyId); - if (poffer == NULL) { - throw JSONRPCError(RPC_DATABASE_ERROR, "Unable to load sell offer from the distributed exchange"); - } - if (poffer->getBlockTimeLimit() < 10) { - throw JSONRPCError(RPC_TYPE_ERROR, "Payment window is less than 10 blocks (use override = true to continue)"); - } -} - -void RequireSaneDExFee(const std::string& address, uint32_t propertyId) -{ - LOCK(cs_main); - const CMPOffer* poffer = elysium::DEx_getOffer(address, propertyId); - if (poffer == NULL) { - throw JSONRPCError(RPC_DATABASE_ERROR, "Unable to load sell offer from the distributed exchange"); - } - if (poffer->getMinFee() > 1000000) { - throw JSONRPCError(RPC_TYPE_ERROR, "Minimum accept fee is higher than 0.01 FIRO (use override = true to continue)"); - } -} - -void RequireHeightInChain(int blockHeight) -{ - if (blockHeight < 0 || elysium::GetHeight() < blockHeight) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height is out of range"); - } -} - -void RequireSigmaStatus(elysium::SigmaStatus status) -{ - if (!elysium::IsSigmaStatusValid(status)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Sigma status is not valid"); - } - - if (!elysium::IsFeatureActivated(elysium::FEATURE_SIGMA, elysium::GetHeight())) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Sigma feature is not activated yet"); - } -} - -namespace elysium { - -void RequireSigma(PropertyId property) -{ - if (!IsFeatureActivated(FEATURE_SIGMA, GetHeight())) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Sigma feature is not activated yet"); - } - - if (!IsSigmaEnabled(property)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property has not enabled Sigma"); - } -} - -void RequireExistingDenomination(PropertyId property, SigmaDenomination denomination) -{ - if (!IsDenominationValid(property, denomination)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Denomination is not valid"); - } -} - -void RequireSigmaSpendV1Feature() -{ - if (!IsFeatureActivated(FEATURE_SIGMA_SPENDV1, GetHeight())) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Sigma spend v1 feature is not activated yet"); - } -} - -} diff --git a/src/elysium/rpcrequirements.h b/src/elysium/rpcrequirements.h deleted file mode 100644 index a9d63ef0fc..0000000000 --- a/src/elysium/rpcrequirements.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef FIRO_ELYSIUM_RPCREQUIREMENTS_H -#define FIRO_ELYSIUM_RPCREQUIREMENTS_H - -#include "property.h" -#include "sigmaprimitives.h" - -#include -#include - -void RequireBalance(const std::string& address, uint32_t propertyId, int64_t amount); -void RequirePrimaryToken(uint32_t propertyId); -void RequirePropertyName(const std::string& name); -void RequireExistingProperty(uint32_t propertyId); -void RequireSameEcosystem(uint32_t propertyId, uint32_t otherId); -void RequireDifferentIds(uint32_t propertyId, uint32_t otherId); -void RequireCrowdsale(uint32_t propertyId); -void RequireActiveCrowdsale(uint32_t propertyId); -void RequireManagedProperty(uint32_t propertyId); -void RequireTokenIssuer(const std::string& address, uint32_t propertyId); -void RequireMatchingDExOffer(const std::string& address, uint32_t propertyId); -void RequireNoOtherDExOffer(const std::string& address, uint32_t propertyId); -void RequireSaneReferenceAmount(int64_t amount); -void RequireSaneDExPaymentWindow(const std::string& address, uint32_t propertyId); -void RequireSaneDExFee(const std::string& address, uint32_t propertyId); -void RequireHeightInChain(int blockHeight); -void RequireSigmaStatus(elysium::SigmaStatus status); - -namespace elysium { - -void RequireSigma(PropertyId property); -void RequireExistingDenomination(PropertyId property, SigmaDenomination denomination); -void RequireSigmaSpendV1Feature(); - -} - -// TODO: -// Checks for MetaDEx orders for cancel operations - - -#endif // FIRO_ELYSIUM_RPCREQUIREMENTS_H diff --git a/src/elysium/rpctx.cpp b/src/elysium/rpctx.cpp deleted file mode 100644 index eb30d4a504..0000000000 --- a/src/elysium/rpctx.cpp +++ /dev/null @@ -1,1866 +0,0 @@ -#include "rpctx.h" - -#include "createpayload.h" -#include "dex.h" -#include "errors.h" -#include "elysium.h" -#include "pending.h" -#include "rpcrequirements.h" -#include "rpcvalues.h" -#include "rules.h" -#include "signaturebuilder.h" -#include "sp.h" -#include "tx.h" -#include "utilsbitcoin.h" -#include "wallet.h" - -#include "../init.h" -#include "../validation.h" -#include "../rpc/server.h" -#include "../sync.h" -#include "../wallet/wallet.h" -#include "../wallet/walletexcept.h" - -#include - -#include -#include - -#include -#include - -#include - -using std::runtime_error; -using namespace elysium; - - -UniValue elysium_sendrawtx(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) - throw runtime_error( - "elysium_sendrawtx \"fromaddress\" \"rawtransaction\" ( \"referenceaddress\" \"redeemaddress\" \"referenceamount\" )\n" - "\nBroadcasts a raw Elysium Layer transaction.\n" - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. rawtransaction (string, required) the hex-encoded raw transaction\n" - "3. referenceaddress (string, optional) a reference address (none by default)\n" - "4. redeemaddress (string, optional) an address that can spent the transaction dust (sender by default)\n" - "5. referenceamount (string, optional) a firo amount that is sent to the receiver (minimal by default)\n" - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - "\nExamples:\n" - + HelpExampleCli("elysium_sendrawtx", "\"1MCHESTptvd2LnNp7wmr2sGTpRomteAkq8\" \"000000000000000100000000017d7840\" \"1EqTta1Rt8ixAA32DuC29oukbsSWU62qAV\"") - + HelpExampleRpc("elysium_sendrawtx", "\"1MCHESTptvd2LnNp7wmr2sGTpRomteAkq8\", \"000000000000000100000000017d7840\", \"1EqTta1Rt8ixAA32DuC29oukbsSWU62qAV\"") - ); - - std::string fromAddress = ParseAddress(request.params[0]); - std::vector data = ParseHexV(request.params[1], "raw transaction"); - std::string toAddress = (request.params.size() > 2) ? ParseAddressOrEmpty(request.params[2]): ""; - std::string redeemAddress = (request.params.size() > 3) ? ParseAddressOrEmpty(request.params[3]): ""; - int64_t referenceAmount = (request.params.size() > 4) ? ParseAmount(request.params[4], true): 0; - - //some sanity checking of the data supplied? - uint256 newTX; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, toAddress, redeemAddress, referenceAmount, data, newTX, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return newTX.GetHex(); - } - } -} - - -UniValue elysium_send(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 4 || request.params.size() > 6) - throw runtime_error( - "elysium_send \"fromaddress\" \"toaddress\" propertyid \"amount\" ( \"redeemaddress\" \"referenceamount\" )\n" - - "\nCreate and broadcast a simple send transaction.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. toaddress (string, required) the address of the receiver\n" - "3. propertyid (number, required) the identifier of the tokens to send\n" - "4. amount (string, required) the amount to send\n" - "5. redeemaddress (string, optional) an address that can spend the transaction dust (sender by default)\n" - "6. referenceamount (string, optional) a firo amount that is sent to the receiver (minimal by default)\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_send", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\" \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\" 1 \"100.0\"") - + HelpExampleRpc("elysium_send", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\", \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\", 1, \"100.0\"") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - std::string toAddress = ParseAddress(request.params[1]); - uint32_t propertyId = ParsePropertyId(request.params[2]); - int64_t amount = ParseAmount(request.params[3], isPropertyDivisible(propertyId)); - std::string redeemAddress = (request.params.size() > 4 && !ParseText(request.params[4]).empty()) ? ParseAddress(request.params[4]): ""; - int64_t referenceAmount = (request.params.size() > 5) ? ParseAmount(request.params[5], true): 0; - - // perform checks - RequireExistingProperty(propertyId); - RequireBalance(fromAddress, propertyId, amount); - RequireSaneReferenceAmount(referenceAmount); - - // create a payload for the transaction - std::vector payload = CreatePayload_SimpleSend(propertyId, amount); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, toAddress, redeemAddress, referenceAmount, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - PendingAdd(txid, fromAddress, ELYSIUM_TYPE_SIMPLE_SEND, propertyId, amount); - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendall(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 3 || request.params.size() > 5) - throw runtime_error( - "elysium_sendall \"fromaddress\" \"toaddress\" ecosystem ( \"redeemaddress\" \"referenceamount\" )\n" - - "\nTransfers all available tokens in the given ecosystem to the recipient.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. toaddress (string, required) the address of the receiver\n" - "3. ecosystem (number, required) the ecosystem of the tokens to send (1 for main ecosystem, 2 for test ecosystem)\n" - "4. redeemaddress (string, optional) an address that can spend the transaction dust (sender by default)\n" - "5. referenceamount (string, optional) a firo amount that is sent to the receiver (minimal by default)\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendall", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\" \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\" 2") - + HelpExampleRpc("elysium_sendall", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\", \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\" 2") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - std::string toAddress = ParseAddress(request.params[1]); - uint8_t ecosystem = ParseEcosystem(request.params[2]); - std::string redeemAddress = (request.params.size() > 3 && !ParseText(request.params[3]).empty()) ? ParseAddress(request.params[3]): ""; - int64_t referenceAmount = (request.params.size() > 4) ? ParseAmount(request.params[4], true): 0; - - // perform checks - RequireSaneReferenceAmount(referenceAmount); - - // create a payload for the transaction - std::vector payload = CreatePayload_SendAll(ecosystem); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, toAddress, redeemAddress, referenceAmount, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - // TODO: pending - return txid.GetHex(); - } - } -} - - -UniValue elysium_senddexsell(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 7) - throw runtime_error( - "elysium_senddexsell \"fromaddress\" propertyidforsale \"amountforsale\" \"amountdesired\" paymentwindow minacceptfee action\n" - - "\nPlace, update or cancel a sell offer on the traditional distributed ELYSIUM/BTC exchange.\n" - - "\nArguments:\n" - - "1. fromaddress (string, required) the address to send from\n" - "2. propertyidforsale (number, required) the identifier of the tokens to list for sale (must be 1 for ELYSIUM or 2 for TELYSIUM)\n" - "3. amountforsale (string, required) the amount of tokens to list for sale\n" - "4. amountdesired (string, required) the amount of firos desired\n" - "5. paymentwindow (number, required) a time limit in blocks a buyer has to pay following a successful accepting order\n" - "6. minacceptfee (string, required) a minimum mining fee a buyer has to pay to accept the offer\n" - "7. action (number, required) the action to take (1 for new offers, 2 to update\", 3 to cancel)\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_senddexsell", "\"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\" 1 \"1.5\" \"0.75\" 25 \"0.0005\" 1") - + HelpExampleRpc("elysium_senddexsell", "\"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\", 1, \"1.5\", \"0.75\", 25, \"0.0005\", 1") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyIdForSale = ParsePropertyId(request.params[1]); - int64_t amountForSale = 0; // depending on action - int64_t amountDesired = 0; // depending on action - uint8_t paymentWindow = 0; // depending on action - int64_t minAcceptFee = 0; // depending on action - uint8_t action = ParseDExAction(request.params[6]); - - // perform conversions - if (action <= CMPTransaction::UPDATE) { // actions 3 permit zero values, skip check - amountForSale = ParseAmount(request.params[2], true); // TMSC/MSC is divisible - amountDesired = ParseAmount(request.params[3], true); // BTC is divisible - paymentWindow = ParseDExPaymentWindow(request.params[4]); - minAcceptFee = ParseDExFee(request.params[5]); - } - - // perform checks - switch (action) { - case CMPTransaction::NEW: - { - RequirePrimaryToken(propertyIdForSale); - RequireBalance(fromAddress, propertyIdForSale, amountForSale); - RequireNoOtherDExOffer(fromAddress, propertyIdForSale); - break; - } - case CMPTransaction::UPDATE: - { - RequirePrimaryToken(propertyIdForSale); - RequireBalance(fromAddress, propertyIdForSale, amountForSale); - RequireMatchingDExOffer(fromAddress, propertyIdForSale); - break; - } - case CMPTransaction::CANCEL: - { - RequirePrimaryToken(propertyIdForSale); - RequireMatchingDExOffer(fromAddress, propertyIdForSale); - break; - } - } - - // create a payload for the transaction - std::vector payload = CreatePayload_DExSell(propertyIdForSale, amountForSale, amountDesired, paymentWindow, minAcceptFee, action); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - bool fSubtract = (action <= CMPTransaction::UPDATE); // no pending balances for cancels - PendingAdd(txid, fromAddress, ELYSIUM_TYPE_TRADE_OFFER, propertyIdForSale, amountForSale, fSubtract); - return txid.GetHex(); - } - } -} - - -UniValue elysium_senddexaccept(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 4 || request.params.size() > 5) - throw runtime_error( - "elysium_senddexaccept \"fromaddress\" \"toaddress\" propertyid \"amount\" ( override )\n" - - "\nCreate and broadcast an accept offer for the specified token and amount.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. toaddress (string, required) the address of the seller\n" - "3. propertyid (number, required) the identifier of the token to purchase\n" - "4. amount (string, required) the amount to accept\n" - "5. override (boolean, optional) override minimum accept fee and payment window checks (use with caution!)\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_senddexaccept", "\"35URq1NN3xL6GeRKUP6vzaQVcxoJiiJKd8\" \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\" 1 \"15.0\"") - + HelpExampleRpc("elysium_senddexaccept", "\"35URq1NN3xL6GeRKUP6vzaQVcxoJiiJKd8\", \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\", 1, \"15.0\"") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - std::string toAddress = ParseAddress(request.params[1]); - uint32_t propertyId = ParsePropertyId(request.params[2]); - int64_t amount = ParseAmount(request.params[3], true); // MSC/TMSC is divisible - bool override = (request.params.size() > 4) ? request.params[4].get_bool(): false; - - // perform checks - RequirePrimaryToken(propertyId); - RequireMatchingDExOffer(toAddress, propertyId); - - if (!override) { // reject unsafe accepts - note client maximum tx fee will always be respected regardless of override here - RequireSaneDExFee(toAddress, propertyId); - RequireSaneDExPaymentWindow(toAddress, propertyId); - } - - - // use new 0.10 custom fee to set the accept minimum fee appropriately - int64_t nMinimumAcceptFee = 0; - { - LOCK(cs_main); - const CMPOffer* sellOffer = DEx_getOffer(toAddress, propertyId); - if (sellOffer == NULL) throw JSONRPCError(RPC_TYPE_ERROR, "Unable to load sell offer from the distributed exchange"); - nMinimumAcceptFee = sellOffer->getMinFee(); - } - - LOCK2(cs_main, pwalletMain->cs_wallet); - - // temporarily update the global transaction fee to pay enough for the accept fee - CFeeRate payTxFeeOriginal = payTxFee; - payTxFee = CFeeRate(nMinimumAcceptFee, 225); // TODO: refine! - // fPayAtLeastCustomFee = true; - - // create a payload for the transaction - std::vector payload = CreatePayload_DExAccept(propertyId, amount); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, toAddress, "", 0, payload, txid, rawHex, autoCommit); - - // set the custom fee back to original - payTxFee = payTxFeeOriginal; - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendissuancecrowdsale(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 14) - throw runtime_error( - "elysium_sendissuancecrowdsale \"fromaddress\" ecosystem type previousid \"category\" \"subcategory\" \"name\" \"url\" \"data\" propertyiddesired tokensperunit deadline ( earlybonus issuerpercentage )\n" - - "Create new tokens as crowdsale." - - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. ecosystem (string, required) the ecosystem to create the tokens in (1 for main ecosystem, 2 for test ecosystem)\n" - "3. type (number, required) the type of the tokens to create: (1 for indivisible tokens, 2 for divisible tokens)\n" - "4. previousid (number, required) an identifier of a predecessor token (0 for new crowdsales)\n" - "5. category (string, required) a category for the new tokens (can be \"\")\n" - "6. subcategory (string, required) a subcategory for the new tokens (can be \"\")\n" - "7. name (string, required) the name of the new tokens to create\n" - "8. url (string, required) an URL for further information about the new tokens (can be \"\")\n" - "9. data (string, required) a description for the new tokens (can be \"\")\n" - "10. propertyiddesired (number, required) the identifier of a token eligible to participate in the crowdsale\n" - "11. tokensperunit (string, required) the amount of tokens granted per unit invested in the crowdsale\n" - "12. deadline (number, required) the deadline of the crowdsale as Unix timestamp\n" - "13. earlybonus (number, required) an early bird bonus for participants in percent per week\n" - "14. issuerpercentage (number, required) a percentage of tokens that will be granted to the issuer\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendissuancecrowdsale", "\"aGoK6MF87K2SgT7cnJFhSWt7u2cAS5m18p\" 2 1 0 \"Companies\" \"Firo Mining\" \"Quantum Miner\" \"\" \"\" 2 \"100\" 1483228800 30 2") - + HelpExampleRpc("elysium_sendissuancecrowdsale", "\"aGoK6MF87K2SgT7cnJFhSWt7u2cAS5m18p\", 2, 1, 0, \"Companies\", \"Firo Mining\", \"Quantum Miner\", \"\", \"\", 2, \"100\", 1483228800, 30, 2") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint8_t ecosystem = ParseEcosystem(request.params[1]); - uint16_t type = ParsePropertyType(request.params[2]); - uint32_t previousId = ParsePreviousPropertyId(request.params[3]); - std::string category = ParseText(request.params[4]); - std::string subcategory = ParseText(request.params[5]); - std::string name = ParseText(request.params[6]); - std::string url = ParseText(request.params[7]); - std::string data = ParseText(request.params[8]); - uint32_t propertyIdDesired = ParsePropertyId(request.params[9]); - int64_t numTokens = ParseAmount(request.params[10], type); - int64_t deadline = ParseDeadline(request.params[11]); - uint8_t earlyBonus = ParseEarlyBirdBonus(request.params[12]); - uint8_t issuerPercentage = ParseIssuerBonus(request.params[13]); - - // perform checks - RequirePropertyName(name); - RequireExistingProperty(propertyIdDesired); - RequireSameEcosystem(ecosystem, propertyIdDesired); - - // create a payload for the transaction - std::vector payload = CreatePayload_IssuanceVariable(ecosystem, type, previousId, category, subcategory, name, url, data, propertyIdDesired, numTokens, deadline, earlyBonus, issuerPercentage); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendissuancefixed(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 10 || request.params.size() > 11) - throw runtime_error( - "elysium_sendissuancefixed \"fromaddress\" ecosystem type previousid \"category\" \"subcategory\" \"name\" \"url\" \"data\" \"amount\" ( sigma )\n" - - "\nCreate new tokens with fixed supply.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. ecosystem (string, required) the ecosystem to create the tokens in (1 for main ecosystem, 2 for test ecosystem)\n" - "3. type (number, required) the type of the tokens to create: (1 for indivisible tokens, 2 for divisible tokens)\n" - "4. previousid (number, required) an identifier of a predecessor token (use 0 for new tokens)\n" - "5. category (string, required) a category for the new tokens (can be \"\")\n" - "6. subcategory (string, required) a subcategory for the new tokens (can be \"\")\n" - "7. name (string, required) the name of the new tokens to create\n" - "8. url (string, required) an URL for further information about the new tokens (can be \"\")\n" - "9. data (string, required) a description for the new tokens (can be \"\")\n" - "10. amount (string, required) the number of tokens to create\n" - "11. sigma (number, optional, default=0) flag to control sigma feature for the new tokens: (0 for soft disabled, 1 for soft enabled, 2 for hard disabled, 3 for hard enabled)\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendissuancefixed", "\"aGoK6MF87K2SgT7cnJFhSWt7u2cAS5m18p\" 2 1 0 \"Companies\" \"Firo Mining\" \"Quantum Miner\" \"\" \"\" \"1000000\"") - + HelpExampleRpc("elysium_sendissuancefixed", "\"aGoK6MF87K2SgT7cnJFhSWt7u2cAS5m18p\", 2, 1, 0, \"Companies\", \"Firo Mining\", \"Quantum Miner\", \"\", \"\", \"1000000\"") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint8_t ecosystem = ParseEcosystem(request.params[1]); - uint16_t type = ParsePropertyType(request.params[2]); - uint32_t previousId = ParsePreviousPropertyId(request.params[3]); - std::string category = ParseText(request.params[4]); - std::string subcategory = ParseText(request.params[5]); - std::string name = ParseText(request.params[6]); - std::string url = ParseText(request.params[7]); - std::string data = ParseText(request.params[8]); - int64_t amount = ParseAmount(request.params[9], type); - boost::optional sigma; - - if (request.params.size() > 10) { - sigma = static_cast(request.params[10].get_int()); - } - - // perform checks - RequirePropertyName(name); - - if (sigma) { - RequireSigmaStatus(sigma.get()); - } - - // create a payload for the transaction - std::vector payload = CreatePayload_IssuanceFixed( - ecosystem, - type, - previousId, - category, - subcategory, - name, - url, - data, - amount, - sigma - ); - - // request the wallet build the transaction (and if needed commit it) - auto& consensus = ConsensusParams(); - uint256 txid; - std::string rawHex; - std::string receiver; - CAmount fee = 0; - - if (IsRequireCreationFee(ecosystem)) { - receiver = consensus.PROPERTY_CREATION_FEE_RECEIVER.ToString(); - fee = consensus.PROPERTY_CREATION_FEE; - } - - int result = WalletTxBuilder(fromAddress, receiver, "", fee, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendissuancemanaged(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 9 || request.params.size() > 10) - throw runtime_error( - "elysium_sendissuancemanaged \"fromaddress\" ecosystem type previousid \"category\" \"subcategory\" \"name\" \"url\" \"data\" ( sigma )\n" - - "\nCreate new tokens with manageable supply.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. ecosystem (string, required) the ecosystem to create the tokens in (1 for main ecosystem, 2 for test ecosystem)\n" - "3. type (number, required) the type of the tokens to create: (1 for indivisible tokens, 2 for divisible tokens)\n" - "4. previousid (number, required) an identifier of a predecessor token (use 0 for new tokens)\n" - "5. category (string, required) a category for the new tokens (can be \"\")\n" - "6. subcategory (string, required) a subcategory for the new tokens (can be \"\")\n" - "7. name (string, required) the name of the new tokens to create\n" - "8. url (string, required) an URL for further information about the new tokens (can be \"\")\n" - "9. data (string, required) a description for the new tokens (can be \"\")\n" - "10. sigma (number, optional, default=0) flag to control sigma feature for the new tokens: (0 for soft disabled, 1 for soft enabled, 2 for hard disabled, 3 for hard enabled)\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendissuancemanaged", "\"aGoK6MF87K2SgT7cnJFhSWt7u2cAS5m18p\" 2 1 0 \"Companies\" \"Firo Mining\" \"Quantum Miner\" \"\" \"\"") - + HelpExampleRpc("elysium_sendissuancemanaged", "\"aGoK6MF87K2SgT7cnJFhSWt7u2cAS5m18p\", 2, 1, 0, \"Companies\", \"Firo Mining\", \"Quantum Miner\", \"\", \"\"") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint8_t ecosystem = ParseEcosystem(request.params[1]); - uint16_t type = ParsePropertyType(request.params[2]); - uint32_t previousId = ParsePreviousPropertyId(request.params[3]); - std::string category = ParseText(request.params[4]); - std::string subcategory = ParseText(request.params[5]); - std::string name = ParseText(request.params[6]); - std::string url = ParseText(request.params[7]); - std::string data = ParseText(request.params[8]); - boost::optional sigma; - - if (request.params.size() > 9) { - sigma = static_cast(request.params[9].get_int()); - } - - // perform checks - RequirePropertyName(name); - - if (sigma) { - RequireSigmaStatus(sigma.get()); - } - - // create a payload for the transaction - std::vector payload = CreatePayload_IssuanceManaged( - ecosystem, - type, - previousId, - category, - subcategory, - name, - url, - data, - sigma - ); - - // request the wallet build the transaction (and if needed commit it) - auto& consensus = ConsensusParams(); - uint256 txid; - std::string rawHex; - std::string receiver; - CAmount fee = 0; - - if (IsRequireCreationFee(ecosystem)) { - receiver = consensus.PROPERTY_CREATION_FEE_RECEIVER.ToString(); - fee = consensus.PROPERTY_CREATION_FEE; - } - - int result = WalletTxBuilder(fromAddress, receiver, "", fee, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendsto(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 3 || request.params.size() > 5) - throw runtime_error( - "elysium_sendsto \"fromaddress\" propertyid \"amount\" ( \"redeemaddress\" distributionproperty )\n" - - "\nCreate and broadcast a send-to-owners transaction.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. propertyid (number, required) the identifier of the tokens to distribute\n" - "3. amount (string, required) the amount to distribute\n" - "4. redeemaddress (string, optional) an address that can spend the transaction dust (sender by default)\n" - "5. distributionproperty (number, optional) the identifier of the property holders to distribute to\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendsto", "\"32Z3tJccZuqQZ4PhJR2hxHC3tjgjA8cbqz\" \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\" 3 \"5000\"") - + HelpExampleRpc("elysium_sendsto", "\"32Z3tJccZuqQZ4PhJR2hxHC3tjgjA8cbqz\", \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\", 3, \"5000\"") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - int64_t amount = ParseAmount(request.params[2], isPropertyDivisible(propertyId)); - std::string redeemAddress = (request.params.size() > 3 && !ParseText(request.params[3]).empty()) ? ParseAddress(request.params[3]): ""; - uint32_t distributionPropertyId = (request.params.size() > 4) ? ParsePropertyId(request.params[4]) : propertyId; - - // perform checks - RequireBalance(fromAddress, propertyId, amount); - - // create a payload for the transaction - std::vector payload = CreatePayload_SendToOwners(propertyId, amount, distributionPropertyId); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", redeemAddress, 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - PendingAdd(txid, fromAddress, ELYSIUM_TYPE_SEND_TO_OWNERS, propertyId, amount); - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendgrant(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 4 || request.params.size() > 5) - throw runtime_error( - "elysium_sendgrant \"fromaddress\" \"toaddress\" propertyid \"amount\" ( \"memo\" )\n" - - "\nIssue or grant new units of managed tokens.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. toaddress (string, required) the receiver of the tokens (sender by default, can be \"\")\n" - "3. propertyid (number, required) the identifier of the tokens to grant\n" - "4. amount (string, required) the amount of tokens to create\n" - "5. memo (string, optional) a text note attached to this transaction (none by default)\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendgrant", "\"3HsJvhr9qzgRe3ss97b1QHs38rmaLExLcH\" \"\" 51 \"7000\"") - + HelpExampleRpc("elysium_sendgrant", "\"3HsJvhr9qzgRe3ss97b1QHs38rmaLExLcH\", \"\", 51, \"7000\"") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - std::string toAddress = !ParseText(request.params[1]).empty() ? ParseAddress(request.params[1]): ""; - uint32_t propertyId = ParsePropertyId(request.params[2]); - int64_t amount = ParseAmount(request.params[3], isPropertyDivisible(propertyId)); - std::string memo = (request.params.size() > 4) ? ParseText(request.params[4]): ""; - - // perform checks - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - RequireTokenIssuer(fromAddress, propertyId); - - // create a payload for the transaction - std::vector payload = CreatePayload_Grant(propertyId, amount, memo); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, toAddress, "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendrevoke(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 3 || request.params.size() > 4) - throw runtime_error( - "elysium_sendrevoke \"fromaddress\" propertyid \"amount\" ( \"memo\" )\n" - - "\nRevoke units of managed tokens.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to revoke the tokens from\n" - "2. propertyid (number, required) the identifier of the tokens to revoke\n" - "3. amount (string, required) the amount of tokens to revoke\n" - "4. memo (string, optional) a text note attached to this transaction (none by default)\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendrevoke", "\"3HsJvhr9qzgRe3ss97b1QHs38rmaLExLcH\" \"\" 51 \"100\"") - + HelpExampleRpc("elysium_sendrevoke", "\"3HsJvhr9qzgRe3ss97b1QHs38rmaLExLcH\", \"\", 51, \"100\"") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - int64_t amount = ParseAmount(request.params[2], isPropertyDivisible(propertyId)); - std::string memo = (request.params.size() > 3) ? ParseText(request.params[3]): ""; - - // perform checks - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - RequireTokenIssuer(fromAddress, propertyId); - RequireBalance(fromAddress, propertyId, amount); - - // create a payload for the transaction - std::vector payload = CreatePayload_Revoke(propertyId, amount, memo); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendclosecrowdsale(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_sendclosecrowdsale \"fromaddress\" propertyid\n" - - "\nManually close a crowdsale.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address associated with the crowdsale to close\n" - "2. propertyid (number, required) the identifier of the crowdsale to close\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendclosecrowdsale", "\"3JYd75REX3HXn1vAU83YuGfmiPXW7BpYXo\" 70") - + HelpExampleRpc("elysium_sendclosecrowdsale", "\"3JYd75REX3HXn1vAU83YuGfmiPXW7BpYXo\", 70") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - - // perform checks - RequireExistingProperty(propertyId); - RequireCrowdsale(propertyId); - RequireActiveCrowdsale(propertyId); - RequireTokenIssuer(fromAddress, propertyId); - - // create a payload for the transaction - std::vector payload = CreatePayload_CloseCrowdsale(propertyId); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - -UniValue trade_MP(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 6) - throw runtime_error( - "trade_MP \"fromaddress\" propertyidforsale \"amountforsale\" propertiddesired \"amountdesired\" action\n" - "\nNote: this command is depreciated, and was replaced by:\n" - " - sendtrade_ELYSIUM\n" - " - sendcanceltradebyprice_ELYSIUM\n" - " - sendcanceltradebypair_ELYSIUM\n" - " - sendcanceltradebypair_ELYSIUM\n" - ); - - JSONRPCRequest newRequest; - newRequest.params = UniValue(UniValue::VARR); - UniValue &values = newRequest.params; - uint8_t action = ParseMetaDExAction(request.params[5]); - - // Forward to the new commands, based on action value - switch (action) { - case CMPTransaction::ADD: - { - values.push_back(request.params[0]); // fromAddress - values.push_back(request.params[1]); // propertyIdForSale - values.push_back(request.params[2]); // amountForSale - values.push_back(request.params[3]); // propertyIdDesired - values.push_back(request.params[4]); // amountDesired - return elysium_sendtrade(newRequest); - } - case CMPTransaction::CANCEL_AT_PRICE: - { - values.push_back(request.params[0]); // fromAddress - values.push_back(request.params[1]); // propertyIdForSale - values.push_back(request.params[2]); // amountForSale - values.push_back(request.params[3]); // propertyIdDesired - values.push_back(request.params[4]); // amountDesired - return elysium_sendcanceltradesbyprice(newRequest); - } - case CMPTransaction::CANCEL_ALL_FOR_PAIR: - { - values.push_back(request.params[0]); // fromAddress - values.push_back(request.params[1]); // propertyIdForSale - values.push_back(request.params[3]); // propertyIdDesired - return elysium_sendcanceltradesbypair(newRequest); - } - case CMPTransaction::CANCEL_EVERYTHING: - { - uint8_t ecosystem = 0; - if (isMainEcosystemProperty(request.params[1].get_int64()) - && isMainEcosystemProperty(request.params[3].get_int64())) { - ecosystem = ELYSIUM_PROPERTY_ELYSIUM; - } - if (isTestEcosystemProperty(request.params[1].get_int64()) - && isTestEcosystemProperty(request.params[3].get_int64())) { - ecosystem = ELYSIUM_PROPERTY_TELYSIUM; - } - values.push_back(request.params[0]); // fromAddress - values.push_back(ecosystem); - return elysium_sendcancelalltrades(newRequest); - } - } - - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid action (1,2,3,4 only)"); -} - - -UniValue elysium_sendtrade(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 5) - throw runtime_error( - "elysium_sendtrade \"fromaddress\" propertyidforsale \"amountforsale\" propertiddesired \"amountdesired\"\n" - - "\nPlace a trade offer on the distributed token exchange.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to trade with\n" - "2. propertyidforsale (number, required) the identifier of the tokens to list for sale\n" - "3. amountforsale (string, required) the amount of tokens to list for sale\n" - "4. propertiddesired (number, required) the identifier of the tokens desired in exchange\n" - "5. amountdesired (string, required) the amount of tokens desired in exchange\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendtrade", "\"3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR\" 31 \"250.0\" 1 \"10.0\"") - + HelpExampleRpc("elysium_sendtrade", "\"3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR\", 31, \"250.0\", 1, \"10.0\"") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyIdForSale = ParsePropertyId(request.params[1]); - int64_t amountForSale = ParseAmount(request.params[2], isPropertyDivisible(propertyIdForSale)); - uint32_t propertyIdDesired = ParsePropertyId(request.params[3]); - int64_t amountDesired = ParseAmount(request.params[4], isPropertyDivisible(propertyIdDesired)); - - // perform checks - RequireExistingProperty(propertyIdForSale); - RequireExistingProperty(propertyIdDesired); - RequireBalance(fromAddress, propertyIdForSale, amountForSale); - RequireSameEcosystem(propertyIdForSale, propertyIdDesired); - RequireDifferentIds(propertyIdForSale, propertyIdDesired); - - // create a payload for the transaction - std::vector payload = CreatePayload_MetaDExTrade(propertyIdForSale, amountForSale, propertyIdDesired, amountDesired); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - PendingAdd(txid, fromAddress, ELYSIUM_TYPE_METADEX_TRADE, propertyIdForSale, amountForSale); - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendcanceltradesbyprice(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 5) - throw runtime_error( - "elysium_sendcanceltradesbyprice \"fromaddress\" propertyidforsale \"amountforsale\" propertiddesired \"amountdesired\"\n" - - "\nCancel offers on the distributed token exchange with the specified price.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to trade with\n" - "2. propertyidforsale (number, required) the identifier of the tokens listed for sale\n" - "3. amountforsale (string, required) the amount of tokens to listed for sale\n" - "4. propertiddesired (number, required) the identifier of the tokens desired in exchange\n" - "5. amountdesired (string, required) the amount of tokens desired in exchange\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendcanceltradesbyprice", "\"3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR\" 31 \"100.0\" 1 \"5.0\"") - + HelpExampleRpc("elysium_sendcanceltradesbyprice", "\"3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR\", 31, \"100.0\", 1, \"5.0\"") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyIdForSale = ParsePropertyId(request.params[1]); - int64_t amountForSale = ParseAmount(request.params[2], isPropertyDivisible(propertyIdForSale)); - uint32_t propertyIdDesired = ParsePropertyId(request.params[3]); - int64_t amountDesired = ParseAmount(request.params[4], isPropertyDivisible(propertyIdDesired)); - - // perform checks - RequireExistingProperty(propertyIdForSale); - RequireExistingProperty(propertyIdDesired); - RequireSameEcosystem(propertyIdForSale, propertyIdDesired); - RequireDifferentIds(propertyIdForSale, propertyIdDesired); - // TODO: check, if there are matching offers to cancel - - // create a payload for the transaction - std::vector payload = CreatePayload_MetaDExCancelPrice(propertyIdForSale, amountForSale, propertyIdDesired, amountDesired); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - PendingAdd(txid, fromAddress, ELYSIUM_TYPE_METADEX_CANCEL_PRICE, propertyIdForSale, amountForSale, false); - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendcanceltradesbypair(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 3) - throw runtime_error( - "elysium_sendcanceltradesbypair \"fromaddress\" propertyidforsale propertiddesired\n" - - "\nCancel all offers on the distributed token exchange with the given currency pair.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to trade with\n" - "2. propertyidforsale (number, required) the identifier of the tokens listed for sale\n" - "3. propertiddesired (number, required) the identifier of the tokens desired in exchange\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendcanceltradesbypair", "\"3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR\" 1 31") - + HelpExampleRpc("elysium_sendcanceltradesbypair", "\"3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR\", 1, 31") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyIdForSale = ParsePropertyId(request.params[1]); - uint32_t propertyIdDesired = ParsePropertyId(request.params[2]); - - // perform checks - RequireExistingProperty(propertyIdForSale); - RequireExistingProperty(propertyIdDesired); - RequireSameEcosystem(propertyIdForSale, propertyIdDesired); - RequireDifferentIds(propertyIdForSale, propertyIdDesired); - // TODO: check, if there are matching offers to cancel - - // create a payload for the transaction - std::vector payload = CreatePayload_MetaDExCancelPair(propertyIdForSale, propertyIdDesired); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - PendingAdd(txid, fromAddress, ELYSIUM_TYPE_METADEX_CANCEL_PAIR, propertyIdForSale, 0, false); - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendcancelalltrades(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_sendcancelalltrades \"fromaddress\" ecosystem\n" - - "\nCancel all offers on the distributed token exchange.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address to trade with\n" - "2. ecosystem (number, required) the ecosystem of the offers to cancel (1 for main ecosystem, 2 for test ecosystem)\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendcancelalltrades", "\"3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR\" 1") - + HelpExampleRpc("elysium_sendcancelalltrades", "\"3BydPiSLPP3DR5cf726hDQ89fpqWLxPKLR\", 1") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint8_t ecosystem = ParseEcosystem(request.params[1]); - - // perform checks - // TODO: check, if there are matching offers to cancel - - // create a payload for the transaction - std::vector payload = CreatePayload_MetaDExCancelEcosystem(ecosystem); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - PendingAdd(txid, fromAddress, ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM, ecosystem, 0, false); - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendchangeissuer(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 3) - throw runtime_error( - "elysium_sendchangeissuer \"fromaddress\" \"toaddress\" propertyid\n" - - "\nChange the issuer on record of the given tokens.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the address associated with the tokens\n" - "2. toaddress (string, required) the address to transfer administrative control to\n" - "3. propertyid (number, required) the identifier of the tokens\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendchangeissuer", "\"1ARjWDkZ7kT9fwjPrjcQyvbXDkEySzKHwu\" \"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\" 3") - + HelpExampleRpc("elysium_sendchangeissuer", "\"1ARjWDkZ7kT9fwjPrjcQyvbXDkEySzKHwu\", \"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\", 3") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - std::string toAddress = ParseAddress(request.params[1]); - uint32_t propertyId = ParsePropertyId(request.params[2]); - - // perform checks - RequireExistingProperty(propertyId); - RequireTokenIssuer(fromAddress, propertyId); - - // create a payload for the transaction - std::vector payload = CreatePayload_ChangeIssuer(propertyId); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, toAddress, "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendenablefreezing(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_sendenablefreezing \"fromaddress\" propertyid\n" - - "\nEnables address freezing for a centrally managed property.\n" - - "\nArguments:\n" - "1. fromaddress (string, required) the issuer of the tokens\n" - "2. propertyid (number, required) the identifier of the tokens\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_sendenablefreezing", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\" 3") - + HelpExampleRpc("elysium_sendenablefreezing", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\", 3") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - - // perform checks - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - RequireTokenIssuer(fromAddress, propertyId); - - // create a payload for the transaction - std::vector payload = CreatePayload_EnableFreezing(propertyId); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_senddisablefreezing(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_senddisablefreezing \"fromaddress\" propertyid\n" - - "\nDisables address freezing for a centrally managed property.\n" - "\nIMPORTANT NOTE: Disabling freezing for a property will UNFREEZE all frozen addresses for that property!" - - "\nArguments:\n" - "1. fromaddress (string, required) the issuer of the tokens\n" - "2. propertyid (number, required) the identifier of the tokens\n" - - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - - "\nExamples:\n" - + HelpExampleCli("elysium_senddisablefreezing", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\" 3") - + HelpExampleRpc("elysium_senddisablefreezing", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\", 3") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - - // perform checks - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - RequireTokenIssuer(fromAddress, propertyId); - - // create a payload for the transaction - std::vector payload = CreatePayload_DisableFreezing(propertyId); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendfreeze(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 4) - throw runtime_error( - "elysium_sendfreeze \"fromaddress\" \"toaddress\" propertyid amount \n" - "\nFreeze an address for a centrally managed token.\n" - "\nNote: Only the issuer may freeze tokens, and only if the token is of the managed type with the freezing option enabled.\n" - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from (must be the issuer of the property)\n" - "2. toaddress (string, required) the address to freeze tokens for\n" - "3. propertyid (number, required) the property to freeze tokens for (must be managed type and have freezing option enabled)\n" - "4. amount (number, required) the amount of tokens to freeze (note: this is unused - once frozen an address cannot send any transactions for the property)\n" - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - "\nExamples:\n" - + HelpExampleCli("elysium_sendfreeze", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\" \"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\" 1 0") - + HelpExampleRpc("elysium_sendfreeze", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\", \"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\", 1, 0") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - std::string refAddress = ParseAddress(request.params[1]); - uint32_t propertyId = ParsePropertyId(request.params[2]); - int64_t amount = ParseAmount(request.params[3], isPropertyDivisible(propertyId)); - - // perform checks - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - RequireTokenIssuer(fromAddress, propertyId); - - // create a payload for the transaction - std::vector payload = CreatePayload_FreezeTokens(propertyId, amount, refAddress); - - // request the wallet build the transaction (and if needed commit it) - // Note: no ref address is sent to WalletTxBuilder as the ref address is contained within the payload - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendunfreeze(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 4) - throw runtime_error( - "elysium_sendunfreeze \"fromaddress\" \"toaddress\" propertyid amount \n" - "\nUnfreezes an address for a centrally managed token.\n" - "\nNote: Only the issuer may unfreeze tokens.\n" - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from (must be the issuer of the property)\n" - "2. toaddress (string, required) the address to unfreeze tokens for\n" - "3. propertyid (number, required) the property to unfreeze tokens for (must be managed type and have freezing option enabled)\n" - "4. amount (number, required) the amount of tokens to unfreeze (note: this is unused - once frozen an address cannot send any transactions for the property)\n" - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - "\nExamples:\n" - + HelpExampleCli("elysium_sendunfreeze", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\" \"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\" 1 0") - + HelpExampleRpc("elysium_sendunfreeze", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\", \"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\", 1, 0") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - std::string refAddress = ParseAddress(request.params[1]); - uint32_t propertyId = ParsePropertyId(request.params[2]); - int64_t amount = ParseAmount(request.params[3], isPropertyDivisible(propertyId)); - - // perform checks - RequireExistingProperty(propertyId); - RequireManagedProperty(propertyId); - RequireTokenIssuer(fromAddress, propertyId); - - // create a payload for the transaction - std::vector payload = CreatePayload_UnfreezeTokens(propertyId, amount, refAddress); - - // request the wallet build the transaction (and if needed commit it) - // Note: no ref address is sent to WalletTxBuilder as the ref address is contained within the payload - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendactivation(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 4) - throw runtime_error( - "elysium_sendactivation \"fromaddress\" featureid block minclientversion\n" - "\nActivate a protocol feature.\n" - "\nNote: Elysium Core ignores activations from unauthorized sources.\n" - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. featureid (number, required) the identifier of the feature to activate\n" - "3. block (number, required) the activation block\n" - "4. minclientversion (number, required) the minimum supported client version\n" - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - "\nExamples:\n" - + HelpExampleCli("elysium_sendactivation", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\" 1 370000 999") - + HelpExampleRpc("elysium_sendactivation", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\", 1, 370000, 999") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint16_t featureId = request.params[1].get_int(); - uint32_t activationBlock = request.params[2].get_int(); - uint32_t minClientVersion = request.params[3].get_int(); - - // create a payload for the transaction - std::vector payload = CreatePayload_ActivateFeature(featureId, activationBlock, minClientVersion); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_senddeactivation(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 2) - throw runtime_error( - "elysium_senddeactivation \"fromaddress\" featureid\n" - "\nDeactivate a protocol feature. For Emergency Use Only.\n" - "\nNote: Elysium Core ignores deactivations from unauthorized sources.\n" - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. featureid (number, required) the identifier of the feature to activate\n" - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - "\nExamples:\n" - + HelpExampleCli("elysium_senddeactivation", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\" 1") - + HelpExampleRpc("elysium_senddeactivation", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\", 1") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint16_t featureId = request.params[1].get_int64(); - - // create a payload for the transaction - std::vector payload = CreatePayload_DeactivateFeature(featureId); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendalert(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 4) - throw runtime_error( - "elysium_sendalert \"fromaddress\" alerttype expiryvalue typecheck versioncheck \"message\"\n" - "\nCreates and broadcasts an Elysium Core alert.\n" - "\nNote: Elysium Core ignores alerts from unauthorized sources.\n" - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. alerttype (number, required) the alert type\n" - "3. expiryvalue (number, required) the value when the alert expires (depends on alert type)\n" - "4. message (string, required) the user-faced alert message\n" - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - "\nExamples:\n" - + HelpExampleCli("elysium_sendalert", "") - + HelpExampleRpc("elysium_sendalert", "") - ); - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - int64_t tempAlertType = request.params[1].get_int64(); - if (tempAlertType < 1 || 65535 < tempAlertType) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Alert type is out of range"); - } - uint16_t alertType = static_cast(tempAlertType); - int64_t tempExpiryValue = request.params[2].get_int64(); - if (tempExpiryValue < 1 || 4294967295LL < tempExpiryValue) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Expiry value is out of range"); - } - uint32_t expiryValue = static_cast(tempExpiryValue); - std::string alertMessage = ParseText(request.params[3]); - - // create a payload for the transaction - std::vector payload = CreatePayload_ElysiumAlert(alertType, expiryValue, alertMessage); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendcreatedenomination(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 3) { - throw std::runtime_error( - "elysium_sendcreatedenomination \"fromaddress\" propertyid \"value\"\n" - "\nCreate a new denomination for the given property.\n" - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. propertyid (number, required) the property to create a new denomination\n" - "3. value (string, required) the value of denomination to create\n" - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - "\nExamples:\n" - + HelpExampleCli("elysium_sendcreatedenomination", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\" 1 \"100.0\"") - + HelpExampleRpc("elysium_sendcreatedenomination", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\", 1, \"100.0\"") - ); - } - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - int64_t value = ParseAmount(request.params[2], isPropertyDivisible(propertyId)); - - // perform checks - RequireExistingProperty(propertyId); - RequireTokenIssuer(fromAddress, propertyId); - RequireSigma(propertyId); - - { - LOCK(cs_main); - - CMPSPInfo::Entry info; - assert(_my_sps->getSP(propertyId, info)); - - if (info.denominations.size() >= MAX_DENOMINATIONS) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "No more room for new denomination"); - } - - if (std::find(info.denominations.begin(), info.denominations.end(), value) != info.denominations.end()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Denomination with value " + FormatMP(propertyId, value) + " already exists"); - } - } - - // create a payload for the transaction - std::vector payload = CreatePayload_CreateDenomination(propertyId, value); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - if (!autoCommit) { - return rawHex; - } else { - return txid.GetHex(); - } - } -} - - -UniValue elysium_sendmint(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 3 || request.params.size() > 4) { - throw std::runtime_error( - "elysium_sendmint \"fromaddress\" propertyid {\"denomination\":amount,...} ( denomminconf )\n" - "\nCreate mints.\n" - "\nArguments:\n" - "1. fromaddress (string, required) the address to send from\n" - "2. propertyid (number, required) the property to create mints\n" - "3. denominations (string, required) A json object with denomination and amount\n" - " {\n" - " denomination:amount (number) The denomination id, the amount of mints\n" - " ,...\n" - " }\n" - "4. denomminconf (number, optional, default=6) Allow only denominations with at least this many confirmations\n" - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - "\nExamples:\n" - + HelpExampleCli("elysium_sendmint", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\" 1 \"{\"0\":1, \"1\":2}\"") - + HelpExampleRpc("elysium_sendmint", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\", 1, \"{\"0\":1, \"1\":2}\"") - ); - } - - // obtain parameters & info - std::string fromAddress = ParseAddress(request.params[0]); - uint32_t propertyId = ParsePropertyId(request.params[1]); - UniValue denominations = request.params[2].get_obj(); - int minConfirms = 6; - if (request.params.size() > 3) { - minConfirms = request.params[3].get_int(); - } - - // perform checks - RequireExistingProperty(propertyId); - RequireSigma(propertyId); - auto keys = denominations.getKeys(); - - // collect all mints need to be created - std::vector denoms; - for (const auto& denom : keys) { - auto denomId = std::stoul(denom); - if (denomId > UINT8_MAX) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid denomination"); - } - - auto amount = denominations[denom].get_int(); - if (amount < 0 || amount > UINT8_MAX) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid amount of mints"); - } - - denoms.insert(denoms.end(), static_cast(amount), static_cast(denomId)); - - int remainingConfirms; - try { - LOCK(cs_main); - remainingConfirms = _my_sps->getDenominationRemainingConfirmation(propertyId, denomId, minConfirms); - } catch (std::invalid_argument const &e) { - throw JSONRPCError(RPC_INVALID_PARAMETER, e.what()); - } - - if (remainingConfirms) { - throw JSONRPCError(RPC_INVALID_PARAMETER, - "confirmations of the denomination is less than required"); - } - } - - int64_t amount; - try { - amount = SumDenominationsValue(propertyId, denoms.begin(), denoms.end()); - } catch (std::invalid_argument const &e) { - throw JSONRPCError(RPC_INVALID_PARAMETER, e.what()); - } catch (std::overflow_error const &e) { - throw JSONRPCError(RPC_INVALID_PARAMETER, e.what()); - } - - RequireBalance(fromAddress, propertyId, amount); - - // Create mints. - std::vector ids; - std::vector> mints; - uint256 txid; - std::string rawHex; - - ids.reserve(denoms.size()); - mints.reserve(denoms.size()); - - try { - try { - wallet->CreateSigmaMints(propertyId, denoms.begin(), denoms.end(), boost::make_function_output_iterator([&] (const SigmaMintId& m) { - ids.push_back(m); - mints.push_back(std::make_pair(m.denomination, m.pubKey)); - })); - } catch (WalletLocked const &e) { - throw JSONRPCError(RPC_WALLET_ERROR, e.what()); - } - - // Create transaction. - auto payload = CreatePayload_SimpleMint(propertyId, mints); - auto result = WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } - } catch (const std::exception &) { - for (auto& id : ids) { - wallet->DeleteUnconfirmedSigmaMint(id); - } - throw; - } - - // Assign transaction ID. - for (auto& id : ids) { - wallet->SetSigmaMintCreatedTransaction(id, txid); - } - - if (!autoCommit) { - return rawHex; - } else { - PendingAdd(txid, fromAddress, ELYSIUM_TYPE_SIMPLE_MINT, propertyId, amount); - return txid.GetHex(); - } -} - - -UniValue elysium_sendspend(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 3 || request.params.size() > 4) { - throw std::runtime_error( - "elysium_sendspend \"toaddress\" propertyid denomination ( \"referenceamount\" )\n" - "\nCreate spend.\n" - "\nArguments:\n" - "1. toaddress (string, required) the address to spend to\n" - "2. propertyid (number, required) the property to spend\n" - "3. denomination (number, required) the id of the denomination need to spend\n" - "4. referenceamount (string, optional) a firo amount that is sent to the receiver (minimal by default)\n" - "\nResult:\n" - "\"hash\" (string) the hex-encoded transaction hash\n" - "\nExamples:\n" - + HelpExampleCli("elysium_sendspend", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\" 1 1") - + HelpExampleRpc("elysium_sendspend", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\", 1, 1") - ); - } - - // obtain parameters & info - auto toAddress = ParseAddress(request.params[0]); - auto propertyId = ParsePropertyId(request.params[1]); - auto denomination = ParseSigmaDenomination(request.params[2]); - auto referenceAmount = (request.params.size() > 3) ? ParseAmount(request.params[3], true): 0; - - // perform checks - RequireExistingProperty(propertyId); - RequireExistingDenomination(propertyId, denomination); - RequireSaneReferenceAmount(referenceAmount); - RequireSigmaSpendV1Feature(); - - // create spend - SigmaMintId mint; - std::vector payload; - - // calculate reference amount - CBitcoinAddress address(toAddress); - if (referenceAmount <= 0) { - CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(address).Get()); - referenceAmount = GetDustThreshold(scriptPubKey); - } - - try { - - bool fPadding = true; - - auto spend = wallet->CreateSigmaSpendV1(propertyId, denomination, fPadding); - auto key = wallet->GetSigmaSignatureKey(spend.mint); - auto pubkey = key.GetPubKey(); - - SigmaV1SignatureBuilder sigBuilder(address, referenceAmount, spend.proof); - auto signature = sigBuilder.Sign(key); - - if (!sigBuilder.Verify(pubkey, signature)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Fail to create valid signature to spend."); - } - - mint = spend.mint; - payload = CreatePayload_SimpleSpend( - mint.property, - mint.denomination, - spend.group, - spend.groupSize, - spend.proof, - signature, - pubkey); - - } catch (InsufficientFunds& e) { - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, e.what()); - } catch (WalletError &e) { - throw JSONRPCError(RPC_WALLET_ERROR, e.what()); - } - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder( - "", - toAddress, - "", - referenceAmount, - payload, - txid, - rawHex, - autoCommit, - InputMode::SIGMA - ); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - throw JSONRPCError(result, error_str(result)); - } else { - // mark the coin as used - wallet->SetSigmaMintUsedTransaction(mint, txid); - - if (!autoCommit) { - return rawHex; - } else { - PendingAdd( - txid, - "Spend", - ELYSIUM_TYPE_SIMPLE_SPEND, - propertyId, - GetDenominationValue(mint.property, mint.denomination), - false, - toAddress); - return txid.GetHex(); - } - } -} - -static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode - // ------------------------------------ ------------------------------- ------------------------------ ---------- - { "elysium (transaction creation)", "elysium_sendrawtx", &elysium_sendrawtx, false }, - { "elysium (transaction creation)", "elysium_send", &elysium_send, false }, - { "hidden", "elysium_senddexsell", &elysium_senddexsell, false }, - { "hidden", "elysium_senddexaccept", &elysium_senddexaccept, false }, - { "hidden", "elysium_sendissuancecrowdsale", &elysium_sendissuancecrowdsale, false }, - { "elysium (transaction creation)", "elysium_sendissuancefixed", &elysium_sendissuancefixed, false }, - { "elysium (transaction creation)", "elysium_sendissuancemanaged", &elysium_sendissuancemanaged, false }, - { "elysium (transaction creation)", "elysium_sendtrade", &elysium_sendtrade, false }, - { "elysium (transaction creation)", "elysium_sendcanceltradesbyprice", &elysium_sendcanceltradesbyprice, false }, - { "elysium (transaction creation)", "elysium_sendcanceltradesbypair", &elysium_sendcanceltradesbypair, false }, - { "elysium (transaction creation)", "elysium_sendcancelalltrades", &elysium_sendcancelalltrades, false }, - { "elysium (transaction creation)", "elysium_sendsto", &elysium_sendsto, false }, - { "elysium (transaction creation)", "elysium_sendgrant", &elysium_sendgrant, false }, - { "elysium (transaction creation)", "elysium_sendrevoke", &elysium_sendrevoke, false }, - { "hidden", "elysium_sendclosecrowdsale", &elysium_sendclosecrowdsale, false }, - { "elysium (transaction creation)", "elysium_sendchangeissuer", &elysium_sendchangeissuer, false }, - { "hidden", "elysium_sendall", &elysium_sendall, false }, - { "hidden", "elysium_sendenablefreezing", &elysium_sendenablefreezing, false }, - { "hidden", "elysium_senddisablefreezing", &elysium_senddisablefreezing, false }, - { "hidden", "elysium_sendfreeze", &elysium_sendfreeze, false }, - { "hidden", "elysium_sendunfreeze", &elysium_sendunfreeze, false }, - { "hidden", "elysium_senddeactivation", &elysium_senddeactivation, true }, - { "hidden", "elysium_sendactivation", &elysium_sendactivation, false }, - { "hidden", "elysium_sendalert", &elysium_sendalert, true }, - { "elysium (transaction creation)", "elysium_sendcreatedenomination", &elysium_sendcreatedenomination, false }, - { "elysium (transaction creation)", "elysium_sendmint", &elysium_sendmint, false }, - { "elysium (transaction creation)", "elysium_sendspend", &elysium_sendspend, false }, - - /* depreciated: */ - { "hidden", "sendrawtx_MP", &elysium_sendrawtx, false }, - { "hidden", "send_MP", &elysium_send, false }, - { "hidden", "sendtoowners_MP", &elysium_sendsto, false }, - { "hidden", "trade_MP", &trade_MP, false }, -}; - -void RegisterElysiumTransactionCreationRPCCommands(CRPCTable &tableRPC) -{ - for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); -} diff --git a/src/elysium/rpctx.h b/src/elysium/rpctx.h deleted file mode 100644 index 4c7f22a32a..0000000000 --- a/src/elysium/rpctx.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef ELYSIUM_RPCTX -#define ELYSIUM_RPCTX - -#include -#include "rpc/server.h" - -UniValue elysium_sendrawtx(const JSONRPCRequest& request); -UniValue elysium_send(const JSONRPCRequest& request); -UniValue elysium_sendall(const JSONRPCRequest& request); -UniValue elysium_senddexsell(const JSONRPCRequest& request); -UniValue elysium_senddexaccept(const JSONRPCRequest& request); -UniValue elysium_sendissuancecrowdsale(const JSONRPCRequest& request); -UniValue elysium_sendissuancefixed(const JSONRPCRequest& request); -UniValue elysium_sendissuancemanaged(const JSONRPCRequest& request); -UniValue elysium_sendsto(const JSONRPCRequest& request); -UniValue elysium_sendgrant(const JSONRPCRequest& request); -UniValue elysium_sendrevoke(const JSONRPCRequest& request); -UniValue elysium_sendclosecrowdsale(const JSONRPCRequest& request); -UniValue trade_MP(const JSONRPCRequest& request); -UniValue elysium_sendtrade(const JSONRPCRequest& request); -UniValue elysium_sendcanceltradesbyprice(const JSONRPCRequest& request); -UniValue elysium_sendcanceltradesbypair(const JSONRPCRequest& request); -UniValue elysium_sendcancelalltrades(const JSONRPCRequest& request); -UniValue elysium_sendchangeissuer(const JSONRPCRequest& request); -UniValue elysium_sendactivation(const JSONRPCRequest& request); -UniValue elysium_sendalert(const JSONRPCRequest& request); - -#endif // ELYSIUM_RPCTX diff --git a/src/elysium/rpctxobject.cpp b/src/elysium/rpctxobject.cpp deleted file mode 100644 index 3c6c4f34e5..0000000000 --- a/src/elysium/rpctxobject.cpp +++ /dev/null @@ -1,646 +0,0 @@ -/** - * @file rpctxobject.cpp - * - * Handler for populating RPC transaction objects. - */ - -#include "elysium/rpctxobject.h" - -#include "elysium/dex.h" -#include "elysium/errors.h" -#include "elysium/mdex.h" -#include "elysium/elysium.h" -#include "elysium/pending.h" -#include "elysium/rpctxobject.h" -#include "elysium/sp.h" -#include "elysium/sto.h" -#include "elysium/tx.h" -#include "elysium/utilsbitcoin.h" -#include "elysium/wallettxs.h" - -#include "chainparams.h" -#include "validation.h" -#include "primitives/transaction.h" -#include "sync.h" -#include "uint256.h" - -#include - -#include -#include - -#include -#include -#include - -// Namespaces -using namespace elysium; - -/** - * Function to standardize RPC output for transactions into a JSON object in either basic or extended mode. - * - * Use basic mode for generic calls (e.g. elysium_gettransaction/elysium_listtransaction etc.) - * Use extended mode for transaction specific calls (e.g. elysium_getsto, elysium_gettrade etc.) - * - * DEx payments and the extended mode are only available for confirmed transactions. - */ -int populateRPCTransactionObject(const uint256& txid, UniValue& txobj, std::string filterAddress, bool extendedDetails, std::string extendedDetailsFilter) -{ - // retrieve the transaction from the blockchain and obtain it's height/confs/time - CTransactionRef tx; - uint256 blockHash; - if (!GetTransaction(txid, tx, Params().GetConsensus(), blockHash, true)) { - return MP_TX_NOT_FOUND; - } - - return populateRPCTransactionObject(*tx, blockHash, txobj, filterAddress, extendedDetails, extendedDetailsFilter); -} - -int populateRPCTransactionObject(const CTransaction& tx, const uint256& blockHash, UniValue& txobj, std::string filterAddress, bool extendedDetails, std::string extendedDetailsFilter, int blockHeight) -{ - int confirmations = 0; - int64_t blockTime = 0; - int positionInBlock = 0; - - if (blockHeight == 0) { - blockHeight = GetHeight(); - } - - if (!blockHash.IsNull()) { - CBlockIndex* pBlockIndex = GetBlockIndex(blockHash); - if (NULL != pBlockIndex) { - confirmations = 1 + blockHeight - pBlockIndex->nHeight; - blockTime = pBlockIndex->nTime; - blockHeight = pBlockIndex->nHeight; - } - } - - // attempt to parse the transaction - CMPTransaction mp_obj; - int parseRC = ParseTransaction(tx, blockHeight, 0, mp_obj, blockTime); - if (parseRC < 0) return MP_TX_IS_NOT_ELYSIUM_PROTOCOL; - - const uint256& txid = tx.GetHash(); - - // DEx FIRO payment needs special handling since it's not actually an Elysium message - handle and return - if (parseRC > 0) { - if (confirmations <= 0) { - // only confirmed DEx payments are currently supported - return MP_TX_UNCONFIRMED; - } - std::string tmpBuyer, tmpSeller; - uint64_t tmpVout, tmpNValue, tmpPropertyId; - { - LOCK(cs_main); - p_txlistdb->getPurchaseDetails(txid, 1, &tmpBuyer, &tmpSeller, &tmpVout, &tmpPropertyId, &tmpNValue); - } - UniValue purchases(UniValue::VARR); - if (populateRPCDExPurchases(tx, purchases, filterAddress) <= 0) return -1; - txobj.push_back(Pair("txid", txid.GetHex())); - txobj.push_back(Pair("type", "DEx Purchase")); - txobj.push_back(Pair("sendingaddress", tmpBuyer)); - txobj.push_back(Pair("purchases", purchases)); - txobj.push_back(Pair("blockhash", blockHash.GetHex())); - txobj.push_back(Pair("blocktime", blockTime)); - txobj.push_back(Pair("block", blockHeight)); - txobj.push_back(Pair("confirmations", confirmations)); - return 0; - } - - // check if we're filtering from listtransactions_MP, and if so whether we have a non-match we want to skip - if (!filterAddress.empty() && mp_obj.getSender() != filterAddress && mp_obj.getReceiver() != filterAddress) return -1; - - // parse packet and populate mp_obj - if (!mp_obj.interpret_Transaction()) return MP_TX_IS_NOT_ELYSIUM_PROTOCOL; - - // obtain validity - only confirmed transactions can be valid - bool valid = false; - if (confirmations > 0) { - LOCK(cs_main); - valid = getValidMPTX(txid); - positionInBlock = p_ElysiumTXDB->FetchTransactionPosition(txid); - } - - // populate some initial info for the transaction - bool fMine = false; - if (IsMyAddress(mp_obj.getSender()) || IsMyAddress(mp_obj.getReceiver())) fMine = true; - txobj.push_back(Pair("txid", txid.GetHex())); - txobj.push_back(Pair("fee", FormatDivisibleMP(mp_obj.getFeePaid()))); - txobj.push_back(Pair("sendingaddress", mp_obj.getSender())); - if (showRefForTx(mp_obj.getType())) txobj.push_back(Pair("referenceaddress", mp_obj.getReceiver())); - txobj.push_back(Pair("ismine", fMine)); - txobj.push_back(Pair("version", (uint64_t)mp_obj.getVersion())); - txobj.push_back(Pair("type_int", (uint64_t)mp_obj.getType())); - if (mp_obj.getType() != ELYSIUM_TYPE_SIMPLE_SEND) { // Type 0 will add "Type" attribute during populateRPCTypeSimpleSend - txobj.push_back(Pair("type", mp_obj.getTypeString())); - } - - // populate type specific info and extended details if requested - // extended details are not available for unconfirmed transactions - if (confirmations <= 0) extendedDetails = false; - populateRPCTypeInfo(mp_obj, txobj, mp_obj.getType(), extendedDetails, extendedDetailsFilter, confirmations); - - // state and chain related information - if (confirmations != 0 && !blockHash.IsNull()) { - txobj.push_back(Pair("valid", valid)); - if (!valid) { - txobj.push_back(Pair("invalidreason", p_ElysiumTXDB->FetchInvalidReason(txid))); - } - txobj.push_back(Pair("blockhash", blockHash.GetHex())); - txobj.push_back(Pair("blocktime", blockTime)); - txobj.push_back(Pair("positioninblock", positionInBlock)); - } - if (confirmations != 0) { - txobj.push_back(Pair("block", blockHeight)); - } - txobj.push_back(Pair("confirmations", confirmations)); - - // finished - return 0; -} - -/* Function to call respective populators based on message type - */ -void populateRPCTypeInfo(CMPTransaction& mp_obj, UniValue& txobj, uint32_t txType, bool extendedDetails, std::string extendedDetailsFilter, int confirmations) -{ - switch (txType) { - case ELYSIUM_TYPE_SIMPLE_SEND: - populateRPCTypeSimpleSend(mp_obj, txobj); - break; - case ELYSIUM_TYPE_SEND_TO_OWNERS: - populateRPCTypeSendToOwners(mp_obj, txobj, extendedDetails, extendedDetailsFilter); - break; - case ELYSIUM_TYPE_SEND_ALL: - populateRPCTypeSendAll(mp_obj, txobj, confirmations); - break; - case ELYSIUM_TYPE_TRADE_OFFER: - populateRPCTypeTradeOffer(mp_obj, txobj); - break; - case ELYSIUM_TYPE_METADEX_TRADE: - populateRPCTypeMetaDExTrade(mp_obj, txobj, extendedDetails); - break; - case ELYSIUM_TYPE_METADEX_CANCEL_PRICE: - populateRPCTypeMetaDExCancelPrice(mp_obj, txobj, extendedDetails); - break; - case ELYSIUM_TYPE_METADEX_CANCEL_PAIR: - populateRPCTypeMetaDExCancelPair(mp_obj, txobj, extendedDetails); - break; - case ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM: - populateRPCTypeMetaDExCancelEcosystem(mp_obj, txobj, extendedDetails); - break; - case ELYSIUM_TYPE_ACCEPT_OFFER_BTC: - populateRPCTypeAcceptOffer(mp_obj, txobj); - break; - case ELYSIUM_TYPE_CREATE_PROPERTY_FIXED: - populateRPCTypeCreatePropertyFixed(mp_obj, txobj, confirmations); - break; - case ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE: - populateRPCTypeCreatePropertyVariable(mp_obj, txobj, confirmations); - break; - case ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL: - populateRPCTypeCreatePropertyManual(mp_obj, txobj, confirmations); - break; - case ELYSIUM_TYPE_CLOSE_CROWDSALE: - populateRPCTypeCloseCrowdsale(mp_obj, txobj); - break; - case ELYSIUM_TYPE_GRANT_PROPERTY_TOKENS: - populateRPCTypeGrant(mp_obj, txobj); - break; - case ELYSIUM_TYPE_REVOKE_PROPERTY_TOKENS: - populateRPCTypeRevoke(mp_obj, txobj); - break; - case ELYSIUM_TYPE_CHANGE_ISSUER_ADDRESS: - populateRPCTypeChangeIssuer(mp_obj, txobj); - break; - case ELYSIUM_MESSAGE_TYPE_ACTIVATION: - populateRPCTypeActivation(mp_obj, txobj); - break; - } -} - -/* Function to determine whether to display the reference address based on transaction type - */ -bool showRefForTx(uint32_t txType) -{ - switch (txType) { - case ELYSIUM_TYPE_SIMPLE_SEND: return true; - case ELYSIUM_TYPE_SEND_TO_OWNERS: return false; - case ELYSIUM_TYPE_TRADE_OFFER: return false; - case ELYSIUM_TYPE_METADEX_TRADE: return false; - case ELYSIUM_TYPE_METADEX_CANCEL_PRICE: return false; - case ELYSIUM_TYPE_METADEX_CANCEL_PAIR: return false; - case ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM: return false; - case ELYSIUM_TYPE_ACCEPT_OFFER_BTC: return true; - case ELYSIUM_TYPE_CREATE_PROPERTY_FIXED: return false; - case ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE: return false; - case ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL: return false; - case ELYSIUM_TYPE_CLOSE_CROWDSALE: return false; - case ELYSIUM_TYPE_GRANT_PROPERTY_TOKENS: return true; - case ELYSIUM_TYPE_REVOKE_PROPERTY_TOKENS: return false; - case ELYSIUM_TYPE_CHANGE_ISSUER_ADDRESS: return true; - case ELYSIUM_TYPE_SEND_ALL: return true; - case ELYSIUM_MESSAGE_TYPE_ACTIVATION: return false; - } - return true; // default to true, shouldn't be needed but just in case -} - -void populateRPCTypeSimpleSend(CMPTransaction& elysiumObj, UniValue& txobj) -{ - uint32_t propertyId = elysiumObj.getProperty(); - int64_t crowdPropertyId = 0, crowdTokens = 0, issuerTokens = 0; - LOCK(cs_main); - bool crowdPurchase = isCrowdsalePurchase(elysiumObj.getHash(), elysiumObj.getReceiver(), &crowdPropertyId, &crowdTokens, &issuerTokens); - if (crowdPurchase) { - CMPSPInfo::Entry sp; - if (false == _my_sps->getSP(crowdPropertyId, sp)) { - PrintToLog("SP Error: Crowdsale purchase for non-existent property %d in transaction %s", crowdPropertyId, elysiumObj.getHash().GetHex()); - return; - } - txobj.push_back(Pair("type", "Crowdsale Purchase")); - txobj.push_back(Pair("propertyid", (uint64_t)propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - txobj.push_back(Pair("amount", FormatMP(propertyId, elysiumObj.getAmount()))); - txobj.push_back(Pair("purchasedpropertyid", crowdPropertyId)); - txobj.push_back(Pair("purchasedpropertyname", sp.name)); - txobj.push_back(Pair("purchasedpropertydivisible", sp.isDivisible())); - txobj.push_back(Pair("purchasedtokens", FormatMP(crowdPropertyId, crowdTokens))); - txobj.push_back(Pair("issuertokens", FormatMP(crowdPropertyId, issuerTokens))); - } else { - txobj.push_back(Pair("type", "Simple Send")); - txobj.push_back(Pair("propertyid", (uint64_t)propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - txobj.push_back(Pair("amount", FormatMP(propertyId, elysiumObj.getAmount()))); - } -} - -void populateRPCTypeSendToOwners(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails, std::string extendedDetailsFilter) -{ - uint32_t propertyId = elysiumObj.getProperty(); - txobj.push_back(Pair("propertyid", (uint64_t)propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - txobj.push_back(Pair("amount", FormatMP(propertyId, elysiumObj.getAmount()))); - if (extendedDetails) populateRPCExtendedTypeSendToOwners(elysiumObj.getHash(), extendedDetailsFilter, txobj, elysiumObj.getVersion()); -} - -void populateRPCTypeSendAll(CMPTransaction& elysiumObj, UniValue& txobj, int confirmations) -{ - UniValue subSends(UniValue::VARR); - if (elysiumObj.getEcosystem() == 1) txobj.push_back(Pair("ecosystem", "main")); - if (elysiumObj.getEcosystem() == 2) txobj.push_back(Pair("ecosystem", "test")); - if (confirmations > 0) { - if (populateRPCSendAllSubSends(elysiumObj.getHash(), subSends) > 0) txobj.push_back(Pair("subsends", subSends)); - } -} - -void populateRPCTypeTradeOffer(CMPTransaction& elysiumObj, UniValue& txobj) -{ - CMPOffer temp_offer(elysiumObj); - uint32_t propertyId = elysiumObj.getProperty(); - int64_t amountOffered = elysiumObj.getAmount(); - int64_t amountDesired = temp_offer.getXZCDesiredOriginal(); - uint8_t sellSubAction = temp_offer.getSubaction(); - - { - // NOTE: some manipulation of sell_subaction is needed here - // TODO: interpretPacket should provide reliable data, cleanup at RPC layer is not cool - if (sellSubAction > 3) sellSubAction = 0; // case where subaction byte >3, to have been allowed must be a v0 sell, flip byte to 0 - if (sellSubAction == 0 && amountOffered > 0) sellSubAction = 1; // case where subaction byte=0, must be a v0 sell, amount > 0 means a new sell - if (sellSubAction == 0 && amountOffered == 0) sellSubAction = 3; // case where subaction byte=0. must be a v0 sell, amount of 0 means a cancel - } - { - // Check levelDB to see if the amount for sale has been amended due to a partial purchase - // TODO: DEx phase 1 really needs an overhaul to work like MetaDEx with original amounts for sale and amounts remaining etc - int tmpblock = 0; - unsigned int tmptype = 0; - uint64_t amountNew = 0; - LOCK(cs_main); - bool tmpValid = getValidMPTX(elysiumObj.getHash(), &tmpblock, &tmptype, &amountNew); - if (tmpValid && amountNew > 0) { - amountDesired = calculateDesiredBTC(amountOffered, amountDesired, amountNew); - amountOffered = amountNew; - } - } - - // Populate - txobj.push_back(Pair("propertyid", (uint64_t)propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - txobj.push_back(Pair("amount", FormatMP(propertyId, amountOffered))); - txobj.push_back(Pair("bitcoindesired", FormatDivisibleMP(amountDesired))); - txobj.push_back(Pair("timelimit", temp_offer.getBlockTimeLimit())); - txobj.push_back(Pair("feerequired", FormatDivisibleMP(temp_offer.getMinFee()))); - if (sellSubAction == 1) txobj.push_back(Pair("action", "new")); - if (sellSubAction == 2) txobj.push_back(Pair("action", "update")); - if (sellSubAction == 3) txobj.push_back(Pair("action", "cancel")); -} - -void populateRPCTypeMetaDExTrade(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails) -{ - CMPMetaDEx metaObj(elysiumObj); - - bool propertyIdForSaleIsDivisible = isPropertyDivisible(elysiumObj.getProperty()); - bool propertyIdDesiredIsDivisible = isPropertyDivisible(metaObj.getDesProperty()); - std::string unitPriceStr = metaObj.displayFullUnitPrice(); - - // populate - txobj.push_back(Pair("propertyidforsale", (uint64_t)elysiumObj.getProperty())); - txobj.push_back(Pair("propertyidforsaleisdivisible", propertyIdForSaleIsDivisible)); - txobj.push_back(Pair("amountforsale", FormatMP(elysiumObj.getProperty(), elysiumObj.getAmount()))); - txobj.push_back(Pair("propertyiddesired", (uint64_t)metaObj.getDesProperty())); - txobj.push_back(Pair("propertyiddesiredisdivisible", propertyIdDesiredIsDivisible)); - txobj.push_back(Pair("amountdesired", FormatMP(metaObj.getDesProperty(), metaObj.getAmountDesired()))); - txobj.push_back(Pair("unitprice", unitPriceStr)); - if (extendedDetails) populateRPCExtendedTypeMetaDExTrade(elysiumObj.getHash(), elysiumObj.getProperty(), elysiumObj.getAmount(), txobj); -} - -void populateRPCTypeMetaDExCancelPrice(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails) -{ - CMPMetaDEx metaObj(elysiumObj); - - bool propertyIdForSaleIsDivisible = isPropertyDivisible(elysiumObj.getProperty()); - bool propertyIdDesiredIsDivisible = isPropertyDivisible(metaObj.getDesProperty()); - std::string unitPriceStr = metaObj.displayFullUnitPrice(); - - // populate - txobj.push_back(Pair("propertyidforsale", (uint64_t)elysiumObj.getProperty())); - txobj.push_back(Pair("propertyidforsaleisdivisible", propertyIdForSaleIsDivisible)); - txobj.push_back(Pair("amountforsale", FormatMP(elysiumObj.getProperty(), elysiumObj.getAmount()))); - txobj.push_back(Pair("propertyiddesired", (uint64_t)metaObj.getDesProperty())); - txobj.push_back(Pair("propertyiddesiredisdivisible", propertyIdDesiredIsDivisible)); - txobj.push_back(Pair("amountdesired", FormatMP(metaObj.getDesProperty(), metaObj.getAmountDesired()))); - txobj.push_back(Pair("unitprice", unitPriceStr)); - if (extendedDetails) populateRPCExtendedTypeMetaDExCancel(elysiumObj.getHash(), txobj); -} - -void populateRPCTypeMetaDExCancelPair(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails) -{ - CMPMetaDEx metaObj(elysiumObj); - - // populate - txobj.push_back(Pair("propertyidforsale", (uint64_t)elysiumObj.getProperty())); - txobj.push_back(Pair("propertyiddesired", (uint64_t)metaObj.getDesProperty())); - if (extendedDetails) populateRPCExtendedTypeMetaDExCancel(elysiumObj.getHash(), txobj); -} - -void populateRPCTypeMetaDExCancelEcosystem(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails) -{ - txobj.push_back(Pair("ecosystem", strEcosystem(elysiumObj.getEcosystem()))); - if (extendedDetails) populateRPCExtendedTypeMetaDExCancel(elysiumObj.getHash(), txobj); -} - -void populateRPCTypeAcceptOffer(CMPTransaction& elysiumObj, UniValue& txobj) -{ - uint32_t propertyId = elysiumObj.getProperty(); - int64_t amount = elysiumObj.getAmount(); - - // Check levelDB to see if the amount accepted has been amended due to over accepting amount available - // TODO: DEx phase 1 really needs an overhaul to work like MetaDEx with original amounts for sale and amounts remaining etc - int tmpblock = 0; - uint32_t tmptype = 0; - uint64_t amountNew = 0; - - LOCK(cs_main); - bool tmpValid = getValidMPTX(elysiumObj.getHash(), &tmpblock, &tmptype, &amountNew); - if (tmpValid && amountNew > 0) amount = amountNew; - - txobj.push_back(Pair("propertyid", (uint64_t)propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - txobj.push_back(Pair("amount", FormatMP(propertyId, amount))); -} - -void populateRPCTypeCreatePropertyFixed(CMPTransaction& elysiumObj, UniValue& txobj, int confirmations) -{ - LOCK(cs_main); - if (confirmations > 0) { - uint32_t propertyId = _my_sps->findSPByTX(elysiumObj.getHash()); - if (propertyId > 0) { - txobj.push_back(Pair("propertyid", (uint64_t) propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - } - } - txobj.push_back(Pair("ecosystem", strEcosystem(elysiumObj.getEcosystem()))); - txobj.push_back(Pair("propertytype", strPropertyType(elysiumObj.getPropertyType()))); - txobj.push_back(Pair("category", elysiumObj.getSPCategory())); - txobj.push_back(Pair("subcategory", elysiumObj.getSPSubCategory())); - txobj.push_back(Pair("propertyname", elysiumObj.getSPName())); - txobj.push_back(Pair("data", elysiumObj.getSPData())); - txobj.push_back(Pair("url", elysiumObj.getSPUrl())); - std::string strAmount = FormatByType(elysiumObj.getAmount(), elysiumObj.getPropertyType()); - txobj.push_back(Pair("amount", strAmount)); -} - -void populateRPCTypeCreatePropertyVariable(CMPTransaction& elysiumObj, UniValue& txobj, int confirmations) -{ - LOCK(cs_main); - if (confirmations > 0) { - uint32_t propertyId = _my_sps->findSPByTX(elysiumObj.getHash()); - if (propertyId > 0) { - txobj.push_back(Pair("propertyid", (uint64_t) propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - } - } - txobj.push_back(Pair("propertytype", strPropertyType(elysiumObj.getPropertyType()))); - txobj.push_back(Pair("ecosystem", strEcosystem(elysiumObj.getEcosystem()))); - txobj.push_back(Pair("category", elysiumObj.getSPCategory())); - txobj.push_back(Pair("subcategory", elysiumObj.getSPSubCategory())); - txobj.push_back(Pair("propertyname", elysiumObj.getSPName())); - txobj.push_back(Pair("data", elysiumObj.getSPData())); - txobj.push_back(Pair("url", elysiumObj.getSPUrl())); - txobj.push_back(Pair("propertyiddesired", (uint64_t) elysiumObj.getProperty())); - std::string strPerUnit = FormatMP(elysiumObj.getProperty(), elysiumObj.getAmount()); - txobj.push_back(Pair("tokensperunit", strPerUnit)); - txobj.push_back(Pair("deadline", elysiumObj.getDeadline())); - txobj.push_back(Pair("earlybonus", elysiumObj.getEarlyBirdBonus())); - txobj.push_back(Pair("percenttoissuer", elysiumObj.getIssuerBonus())); - std::string strAmount = FormatByType(0, elysiumObj.getPropertyType()); - txobj.push_back(Pair("amount", strAmount)); // crowdsale token creations don't issue tokens with the create tx -} - -void populateRPCTypeCreatePropertyManual(CMPTransaction& elysiumObj, UniValue& txobj, int confirmations) -{ - LOCK(cs_main); - if (confirmations > 0) { - uint32_t propertyId = _my_sps->findSPByTX(elysiumObj.getHash()); - if (propertyId > 0) { - txobj.push_back(Pair("propertyid", (uint64_t) propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - } - } - txobj.push_back(Pair("propertytype", strPropertyType(elysiumObj.getPropertyType()))); - txobj.push_back(Pair("ecosystem", strEcosystem(elysiumObj.getEcosystem()))); - txobj.push_back(Pair("category", elysiumObj.getSPCategory())); - txobj.push_back(Pair("subcategory", elysiumObj.getSPSubCategory())); - txobj.push_back(Pair("propertyname", elysiumObj.getSPName())); - txobj.push_back(Pair("data", elysiumObj.getSPData())); - txobj.push_back(Pair("url", elysiumObj.getSPUrl())); - std::string strAmount = FormatByType(0, elysiumObj.getPropertyType()); - txobj.push_back(Pair("amount", strAmount)); // managed token creations don't issue tokens with the create tx -} - -void populateRPCTypeCloseCrowdsale(CMPTransaction& elysiumObj, UniValue& txobj) -{ - uint32_t propertyId = elysiumObj.getProperty(); - txobj.push_back(Pair("propertyid", (uint64_t)propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); -} - -void populateRPCTypeGrant(CMPTransaction& elysiumObj, UniValue& txobj) -{ - uint32_t propertyId = elysiumObj.getProperty(); - txobj.push_back(Pair("propertyid", (uint64_t)propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - txobj.push_back(Pair("amount", FormatMP(propertyId, elysiumObj.getAmount()))); -} - -void populateRPCTypeRevoke(CMPTransaction& elysiumObj, UniValue& txobj) -{ - uint32_t propertyId = elysiumObj.getProperty(); - txobj.push_back(Pair("propertyid", (uint64_t)propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - txobj.push_back(Pair("amount", FormatMP(propertyId, elysiumObj.getAmount()))); -} - -void populateRPCTypeChangeIssuer(CMPTransaction& elysiumObj, UniValue& txobj) -{ - uint32_t propertyId = elysiumObj.getProperty(); - txobj.push_back(Pair("propertyid", (uint64_t)propertyId)); - txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); -} - -void populateRPCTypeActivation(CMPTransaction& elysiumObj, UniValue& txobj) -{ - txobj.push_back(Pair("featureid", (uint64_t) elysiumObj.getFeatureId())); - txobj.push_back(Pair("activationblock", (uint64_t) elysiumObj.getActivationBlock())); - txobj.push_back(Pair("minimumversion", (uint64_t) elysiumObj.getMinClientVersion())); -} - -void populateRPCExtendedTypeSendToOwners(const uint256 txid, std::string extendedDetailsFilter, UniValue& txobj, uint16_t version) -{ - UniValue receiveArray(UniValue::VARR); - uint64_t tmpAmount = 0, stoFee = 0, numRecipients = 0; - LOCK(cs_main); - s_stolistdb->getRecipients(txid, extendedDetailsFilter, &receiveArray, &tmpAmount, &numRecipients); - if (version == MP_TX_PKT_V0) { - stoFee = numRecipients * TRANSFER_FEE_PER_OWNER; - } else { - stoFee = numRecipients * TRANSFER_FEE_PER_OWNER_V1; - } - txobj.push_back(Pair("totalstofee", FormatDivisibleMP(stoFee))); // fee always ELYSIUM so always divisible - txobj.push_back(Pair("recipients", receiveArray)); -} - -void populateRPCExtendedTypeMetaDExTrade(const uint256& txid, uint32_t propertyIdForSale, int64_t amountForSale, UniValue& txobj) -{ - UniValue tradeArray(UniValue::VARR); - int64_t totalReceived = 0, totalSold = 0; - LOCK(cs_main); - t_tradelistdb->getMatchingTrades(txid, propertyIdForSale, tradeArray, totalSold, totalReceived); - int tradeStatus = MetaDEx_getStatus(txid, propertyIdForSale, amountForSale, totalSold); - if (tradeStatus == TRADE_OPEN || tradeStatus == TRADE_OPEN_PART_FILLED) { - const CMPMetaDEx* tradeObj = MetaDEx_RetrieveTrade(txid); - if (tradeObj != NULL) { - txobj.push_back(Pair("amountremaining", FormatMP(tradeObj->getProperty(), tradeObj->getAmountRemaining()))); - txobj.push_back(Pair("amounttofill", FormatMP(tradeObj->getDesProperty(), tradeObj->getAmountToFill()))); - } - } - txobj.push_back(Pair("status", MetaDEx_getStatusText(tradeStatus))); - if (tradeStatus == TRADE_CANCELLED || tradeStatus == TRADE_CANCELLED_PART_FILLED) { - txobj.push_back(Pair("canceltxid", p_txlistdb->findMetaDExCancel(txid).GetHex())); - } - txobj.push_back(Pair("matches", tradeArray)); -} - -void populateRPCExtendedTypeMetaDExCancel(const uint256& txid, UniValue& txobj) -{ - UniValue cancelArray(UniValue::VARR); - LOCK(cs_main); - int numberOfCancels = p_txlistdb->getNumberOfMetaDExCancels(txid); - if (0getKeyValue(txid.ToString() + "-C" + strprintf("%d",refNumber)); - if (strValue.empty()) continue; - std::vector vstr; - boost::split(vstr, strValue, boost::is_any_of(":"), boost::token_compress_on); - if (vstr.size() != 3) { - PrintToLog("TXListDB Error - trade cancel number of tokens is not as expected (%s)\n", strValue); - continue; - } - uint32_t propId = boost::lexical_cast(vstr[1]); - int64_t amountUnreserved = boost::lexical_cast(vstr[2]); - cancelTx.push_back(Pair("txid", vstr[0])); - cancelTx.push_back(Pair("propertyid", (uint64_t) propId)); - cancelTx.push_back(Pair("amountunreserved", FormatMP(propId, amountUnreserved))); - cancelArray.push_back(cancelTx); - } - } - txobj.push_back(Pair("cancelledtransactions", cancelArray)); -} - -/* Function to enumerate sub sends for a given txid and add to supplied JSON array - * Note: this function exists as send all has the potential to carry multiple sends in a single transaction. - */ -int populateRPCSendAllSubSends(const uint256& txid, UniValue& subSends) -{ - int numberOfSubSends = 0; - { - LOCK(cs_main); - numberOfSubSends = p_txlistdb->getNumberOfSubRecords(txid); - } - if (numberOfSubSends <= 0) { - PrintToLog("TXLISTDB Error: Transaction %s parsed as a send all but could not locate sub sends in txlistdb.\n", txid.GetHex()); - return -1; - } - for (int subSend = 1; subSend <= numberOfSubSends; subSend++) { - UniValue subSendObj(UniValue::VOBJ); - uint32_t propertyId; - int64_t amount; - { - LOCK(cs_main); - p_txlistdb->getSendAllDetails(txid, subSend, propertyId, amount); - } - subSendObj.push_back(Pair("propertyid", (uint64_t)propertyId)); - subSendObj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); - subSendObj.push_back(Pair("amount", FormatMP(propertyId, amount))); - subSends.push_back(subSendObj); - } - return subSends.size(); -} - -/* Function to enumerate DEx purchases for a given txid and add to supplied JSON array - * Note: this function exists as it is feasible for a single transaction to carry multiple outputs - * and thus make multiple purchases from a single transaction - */ -int populateRPCDExPurchases(const CTransaction& wtx, UniValue& purchases, std::string filterAddress) -{ - int numberOfPurchases = 0; - { - LOCK(cs_main); - numberOfPurchases = p_txlistdb->getNumberOfSubRecords(wtx.GetHash()); - } - if (numberOfPurchases <= 0) { - PrintToLog("TXLISTDB Error: Transaction %s parsed as a DEx payment but could not locate purchases in txlistdb.\n", wtx.GetHash().GetHex()); - return -1; - } - for (int purchaseNumber = 1; purchaseNumber <= numberOfPurchases; purchaseNumber++) { - UniValue purchaseObj(UniValue::VOBJ); - std::string buyer, seller; - uint64_t vout, nValue, propertyId; - { - LOCK(cs_main); - p_txlistdb->getPurchaseDetails(wtx.GetHash(), purchaseNumber, &buyer, &seller, &vout, &propertyId, &nValue); - } - if (!filterAddress.empty() && buyer != filterAddress && seller != filterAddress) continue; // filter requested & doesn't match - bool bIsMine = false; - if (IsMyAddress(buyer) || IsMyAddress(seller)) bIsMine = true; - int64_t amountPaid = wtx.vout[vout].nValue; - purchaseObj.push_back(Pair("vout", vout)); - purchaseObj.push_back(Pair("amountpaid", FormatDivisibleMP(amountPaid))); - purchaseObj.push_back(Pair("ismine", bIsMine)); - purchaseObj.push_back(Pair("referenceaddress", seller)); - purchaseObj.push_back(Pair("propertyid", propertyId)); - purchaseObj.push_back(Pair("amountbought", FormatDivisibleMP(nValue))); - purchaseObj.push_back(Pair("valid", true)); //only valid purchases are stored, anything else is regular BTC tx - purchases.push_back(purchaseObj); - } - return purchases.size(); -} diff --git a/src/elysium/rpctxobject.h b/src/elysium/rpctxobject.h deleted file mode 100644 index ce51a5c38e..0000000000 --- a/src/elysium/rpctxobject.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef ELYSIUM_RPCTXOBJECT_H -#define ELYSIUM_RPCTXOBJECT_H - -#include - -#include - -class uint256; -class CMPTransaction; -class CTransaction; - -int populateRPCTransactionObject(const uint256& txid, UniValue& txobj, std::string filterAddress = "", bool extendedDetails = false, std::string extendedDetailsFilter = ""); -int populateRPCTransactionObject(const CTransaction& tx, const uint256& blockHash, UniValue& txobj, std::string filterAddress = "", bool extendedDetails = false, std::string extendedDetailsFilter = "", int blockHeight = 0); - -void populateRPCTypeInfo(CMPTransaction& mp_obj, UniValue& txobj, uint32_t txType, bool extendedDetails, std::string extendedDetailsFilter, int confirmations); - -void populateRPCTypeSimpleSend(CMPTransaction& elysiumObj, UniValue& txobj); -void populateRPCTypeSendToOwners(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails, std::string extendedDetailsFilter); -void populateRPCTypeSendAll(CMPTransaction& elysiumObj, UniValue& txobj, int confirmations); -void populateRPCTypeTradeOffer(CMPTransaction& elysiumObj, UniValue& txobj); -void populateRPCTypeMetaDExTrade(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails); -void populateRPCTypeMetaDExCancelPrice(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails); -void populateRPCTypeMetaDExCancelPair(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails); -void populateRPCTypeMetaDExCancelEcosystem(CMPTransaction& elysiumObj, UniValue& txobj, bool extendedDetails); -void populateRPCTypeAcceptOffer(CMPTransaction& elysiumObj, UniValue& txobj); -void populateRPCTypeCreatePropertyFixed(CMPTransaction& elysiumObj, UniValue& txobj, int confirmations); -void populateRPCTypeCreatePropertyVariable(CMPTransaction& elysiumObj, UniValue& txobj, int confirmations); -void populateRPCTypeCreatePropertyManual(CMPTransaction& elysiumObj, UniValue& txobj, int confirmations); -void populateRPCTypeCloseCrowdsale(CMPTransaction& elysiumObj, UniValue& txobj); -void populateRPCTypeGrant(CMPTransaction& elysiumObj, UniValue& txobj); -void populateRPCTypeRevoke(CMPTransaction& elysiumObj, UniValue& txobj); -void populateRPCTypeChangeIssuer(CMPTransaction& elysiumObj, UniValue& txobj); -void populateRPCTypeActivation(CMPTransaction& elysiumObj, UniValue& txobj); - -void populateRPCExtendedTypeSendToOwners(const uint256 txid, std::string extendedDetailsFilter, UniValue& txobj, uint16_t version); -void populateRPCExtendedTypeMetaDExTrade(const uint256& txid, uint32_t propertyIdForSale, int64_t amountForSale, UniValue& txobj); -void populateRPCExtendedTypeMetaDExCancel(const uint256& txid, UniValue& txobj); - -int populateRPCDExPurchases(const CTransaction& wtx, UniValue& purchases, std::string filterAddress); -int populateRPCSendAllSubSends(const uint256& txid, UniValue& subSends); - -bool showRefForTx(uint32_t txType); - -#endif // ELYSIUM_RPCTXOBJECT_H diff --git a/src/elysium/rpcvalues.cpp b/src/elysium/rpcvalues.cpp deleted file mode 100644 index 4c211e739c..0000000000 --- a/src/elysium/rpcvalues.cpp +++ /dev/null @@ -1,252 +0,0 @@ -#include "rpcvalues.h" - -#include "createtx.h" -#include "parse_string.h" -#include "sp.h" -#include "wallettxs.h" - -#include "../base58.h" -#include "../core_io.h" -#include "../primitives/transaction.h" -#include "../pubkey.h" -#include "../rpc/protocol.h" -#include "../rpc/server.h" -#include "../script/script.h" -#include "../uint256.h" - -#include - -#include -#include - -using elysium::StrToInt64; - -std::string ParseAddress(const UniValue& value) -{ - CBitcoinAddress address(value.get_str()); - if (!address.IsValid()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); - } - return address.ToString(); -} - -std::string ParseAddressOrEmpty(const UniValue& value) -{ - if (value.isNull() || value.get_str().empty()) { - return ""; - } - return ParseAddress(value); -} - -std::string ParseAddressOrWildcard(const UniValue& value) -{ - if (value.get_str() == "*") { - return "*"; - } - return ParseAddress(value); -} - -uint32_t ParsePropertyId(const UniValue& value) -{ - int64_t propertyId = value.get_int64(); - if (propertyId < 1 || 4294967295LL < propertyId) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property identifier is out of range"); - } - return static_cast(propertyId); -} - -int64_t ParseAmount(const UniValue& value, bool isDivisible) -{ - int64_t amount = elysium::StrToInt64(value.get_str(), isDivisible); - if (amount < 1) { - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); - } - return amount; -} - -int64_t ParseAmount(const UniValue& value, int propertyType) -{ - bool fDivisible = (propertyType == 2); // 1 = indivisible, 2 = divisible - return ParseAmount(value, fDivisible); -} - -uint8_t ParseDExPaymentWindow(const UniValue& value) -{ - int64_t blocks = value.get_int64(); - if (blocks < 1 || 255 < blocks) { - throw JSONRPCError(RPC_TYPE_ERROR, "Payment window must be within 1-255 blocks"); - } - return static_cast(blocks); -} - -int64_t ParseDExFee(const UniValue& value) -{ - int64_t fee = StrToInt64(value.get_str(), true); // BTC is divisible - if (fee < 0) { - throw JSONRPCError(RPC_TYPE_ERROR, "Mininmum accept fee must be positive"); - } - return fee; -} - -uint8_t ParseDExAction(const UniValue& value) -{ - int64_t action = value.get_int64(); - if (action <= 0 || 3 < action) { - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid action (1 = new, 2 = update, 3 = cancel only)"); - } - return static_cast(action); -} - -uint8_t ParseEcosystem(const UniValue& value) -{ - int64_t ecosystem = value.get_int64(); - if (ecosystem < 1 || 2 < ecosystem) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid ecosystem (1 = main, 2 = test only)"); - } - return static_cast(ecosystem); -} - -uint16_t ParsePropertyType(const UniValue& value) -{ - int64_t propertyType = value.get_int64(); - if (propertyType < 1 || 2 < propertyType) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property type (1 = indivisible, 2 = divisible only)"); - } - return static_cast(propertyType); -} - -uint32_t ParsePreviousPropertyId(const UniValue& value) -{ - int64_t previousId = value.get_int64(); - if (previousId != 0) { - throw JSONRPCError(RPC_TYPE_ERROR, "Property appends/replaces are not yet supported"); - } - return static_cast(previousId); -} - -std::string ParseText(const UniValue& value) -{ - std::string text = value.get_str(); - if (text.size() > 255) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Text must not be longer than 255 characters"); - } - return text; -} - -int64_t ParseDeadline(const UniValue& value) -{ - int64_t deadline = value.get_int64(); - if (deadline < 0) { - throw JSONRPCError(RPC_TYPE_ERROR, "Deadline must be positive"); - } - return deadline; -} - -uint8_t ParseEarlyBirdBonus(const UniValue& value) -{ - int64_t percentage = value.get_int64(); - if (percentage < 0 || 255 < percentage) { - throw JSONRPCError(RPC_TYPE_ERROR, "Early bird bonus must be in the range of 0-255 percent per week"); - } - return static_cast(percentage); -} - -uint8_t ParseIssuerBonus(const UniValue& value) -{ - int64_t percentage = value.get_int64(); - if (percentage < 0 || 255 < percentage) { - throw JSONRPCError(RPC_TYPE_ERROR, "Bonus for issuer must be in the range of 0-255 percent"); - } - return static_cast(percentage); -} - -uint8_t ParseMetaDExAction(const UniValue& value) -{ - int64_t action = value.get_int64(); - if (action <= 0 || 4 < action) { - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid action (1, 2, 3, 4 only)"); - } - return static_cast(action); -} - -CTransaction ParseTransaction(const UniValue& value) -{ - CMutableTransaction tx; - if (value.isNull() || value.get_str().empty()) { - return tx; - } - if (!DecodeHexTx(tx, value.get_str())) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction deserialization failed"); - } - return tx; -} - -CMutableTransaction ParseMutableTransaction(const UniValue& value) -{ - CTransaction tx = ParseTransaction(value); - return CMutableTransaction(tx); -} - -CPubKey ParsePubKeyOrAddress(const UniValue& value) -{ - CPubKey pubKey; - if (!elysium::AddressToPubKey(value.get_str(), pubKey)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redemption key or address"); - } - return pubKey; -} - -uint32_t ParseOutputIndex(const UniValue& value) -{ - int nOut = value.get_int(); - if (nOut < 0) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Vout index must be positive"); - } - return static_cast(nOut); -} - -/** Parses previous transaction outputs. */ -std::vector ParsePrevTxs(const UniValue& value) -{ - UniValue prevTxs = value.get_array(); - - std::vector prevTxsParsed; - prevTxsParsed.reserve(prevTxs.size()); - - for (size_t i = 0; i < prevTxs.size(); ++i) { - const UniValue& p = prevTxs[i]; - if (p.type() != UniValue::VOBJ) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid\",\"vout\",\"scriptPubKey\",\"value\":n.nnnnnnnn}"); - } - UniValue prevOut = p.get_obj(); - - uint256 txid = ParseHashO(prevOut, "txid"); - UniValue outputIndex = find_value(prevOut, "vout"); - UniValue outputValue = find_value(prevOut, "value"); - std::vector pkData(ParseHexO(prevOut, "scriptPubKey")); - - uint32_t nOut = ParseOutputIndex(outputIndex); - int64_t nValue = AmountFromValue(outputValue); - CScript scriptPubKey(pkData.begin(), pkData.end()); - - PrevTxsEntry entry(txid, nOut, nValue, scriptPubKey); - prevTxsParsed.push_back(entry); - } - - return prevTxsParsed; -} - -namespace elysium { - -SigmaDenomination ParseSigmaDenomination(const UniValue& value) -{ - auto v = value.get_int(); - - if (v < 0 || static_cast(v) >= MAX_DENOMINATIONS) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid denomination"); - } - - return v; -} - -} diff --git a/src/elysium/rpcvalues.h b/src/elysium/rpcvalues.h deleted file mode 100644 index bc7ed8b265..0000000000 --- a/src/elysium/rpcvalues.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef FIRO_ELYSIUM_RPCVALUES_H -#define FIRO_ELYSIUM_RPCVALUES_H - -class CPubKey; -class CTransaction; -struct CMutableTransaction; -struct PrevTxsEntry; - -#include "sigmaprimitives.h" - -#include - -#include -#include - -#include - -std::string ParseAddress(const UniValue& value); -std::string ParseAddressOrEmpty(const UniValue& value); -std::string ParseAddressOrWildcard(const UniValue& value); -uint32_t ParsePropertyId(const UniValue& value); -int64_t ParseAmount(const UniValue& value, bool isDivisible); -int64_t ParseAmount(const UniValue& value, int propertyType); -uint8_t ParseDExPaymentWindow(const UniValue& value); -int64_t ParseDExFee(const UniValue& value); -uint8_t ParseDExAction(const UniValue& value); -uint8_t ParseEcosystem(const UniValue& value); -uint16_t ParsePropertyType(const UniValue& value); -uint32_t ParsePreviousPropertyId(const UniValue& value); -std::string ParseText(const UniValue& value); -int64_t ParseDeadline(const UniValue& value); -uint8_t ParseEarlyBirdBonus(const UniValue& value); -uint8_t ParseIssuerBonus(const UniValue& value); -uint8_t ParseMetaDExAction(const UniValue& value); -CTransaction ParseTransaction(const UniValue& value); -CMutableTransaction ParseMutableTransaction(const UniValue& value); -CPubKey ParsePubKeyOrAddress(const UniValue& value); -uint32_t ParseOutputIndex(const UniValue& value); -/** Parses previous transaction outputs. */ -std::vector ParsePrevTxs(const UniValue& value); - -namespace elysium { - -SigmaDenomination ParseSigmaDenomination(const UniValue& value); - -} - -#endif // FIRO_ELYSIUM_RPCVALUES_H diff --git a/src/elysium/rules.cpp b/src/elysium/rules.cpp deleted file mode 100644 index da47f67629..0000000000 --- a/src/elysium/rules.cpp +++ /dev/null @@ -1,652 +0,0 @@ -#include "rules.h" - -#include "activation.h" -#include "consensushash.h" -#include "log.h" -#include "elysium.h" -#include "notifications.h" -#include "tx.h" -#include "utilsbitcoin.h" -#include "version.h" - -#include "../chainparams.h" -#include "../validation.h" -#include "../script/standard.h" -#include "../uint256.h" -#include "../ui_interface.h" - -#include -#include -#include - -#include - -namespace elysium -{ -/** - * Returns a mapping of transaction types, and the blocks at which they are enabled. - */ -std::vector CConsensusParams::GetRestrictions() const -{ - const TransactionRestriction vTxRestrictions[] = - { // transaction type version allow 0 activation block - // ---------------------------------- ------------- ------- ------------------ - { ELYSIUM_MESSAGE_TYPE_ALERT, 0xFFFF, true, ELYSIUM_ALERT_BLOCK }, - { ELYSIUM_MESSAGE_TYPE_ACTIVATION, 0xFFFF, true, ELYSIUM_ALERT_BLOCK }, - { ELYSIUM_MESSAGE_TYPE_DEACTIVATION, 0xFFFF, true, ELYSIUM_ALERT_BLOCK }, - - { ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V0, false, ELYSIUM_SEND_BLOCK }, - - { ELYSIUM_TYPE_TRADE_OFFER, MP_TX_PKT_V0, false, ELYSIUM_DEX_BLOCK }, - { ELYSIUM_TYPE_TRADE_OFFER, MP_TX_PKT_V1, false, ELYSIUM_DEX_BLOCK }, - { ELYSIUM_TYPE_ACCEPT_OFFER_BTC, MP_TX_PKT_V0, false, ELYSIUM_DEX_BLOCK }, - - { ELYSIUM_TYPE_CREATE_PROPERTY_FIXED, MP_TX_PKT_V0, false, ELYSIUM_SP_BLOCK }, - { ELYSIUM_TYPE_CREATE_PROPERTY_FIXED, MP_TX_PKT_V1, false, SIGMA_FEATURE_BLOCK }, - { ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE, MP_TX_PKT_V0, false, ELYSIUM_SP_BLOCK }, - { ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE, MP_TX_PKT_V1, false, ELYSIUM_SP_BLOCK }, - { ELYSIUM_TYPE_CLOSE_CROWDSALE, MP_TX_PKT_V0, false, ELYSIUM_SP_BLOCK }, - - { ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL, MP_TX_PKT_V0, false, ELYSIUM_MANUALSP_BLOCK }, - { ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL, MP_TX_PKT_V1, false, SIGMA_FEATURE_BLOCK }, - { ELYSIUM_TYPE_GRANT_PROPERTY_TOKENS, MP_TX_PKT_V0, false, ELYSIUM_MANUALSP_BLOCK }, - { ELYSIUM_TYPE_REVOKE_PROPERTY_TOKENS, MP_TX_PKT_V0, false, ELYSIUM_MANUALSP_BLOCK }, - { ELYSIUM_TYPE_CHANGE_ISSUER_ADDRESS, MP_TX_PKT_V0, false, ELYSIUM_MANUALSP_BLOCK }, - { ELYSIUM_TYPE_ENABLE_FREEZING, MP_TX_PKT_V0, false, ELYSIUM_MANUALSP_BLOCK }, - { ELYSIUM_TYPE_DISABLE_FREEZING, MP_TX_PKT_V0, false, ELYSIUM_MANUALSP_BLOCK }, - { ELYSIUM_TYPE_FREEZE_PROPERTY_TOKENS, MP_TX_PKT_V0, false, ELYSIUM_MANUALSP_BLOCK }, - { ELYSIUM_TYPE_UNFREEZE_PROPERTY_TOKENS, MP_TX_PKT_V0, false, ELYSIUM_MANUALSP_BLOCK }, - - { ELYSIUM_TYPE_SEND_TO_OWNERS, MP_TX_PKT_V0, false, ELYSIUM_STO_BLOCK }, - { ELYSIUM_TYPE_SEND_TO_OWNERS, MP_TX_PKT_V1, false, ELYSIUM_STOV1_BLOCK }, - - { ELYSIUM_TYPE_METADEX_TRADE, MP_TX_PKT_V0, false, ELYSIUM_METADEX_BLOCK }, - { ELYSIUM_TYPE_METADEX_CANCEL_PRICE, MP_TX_PKT_V0, false, ELYSIUM_METADEX_BLOCK }, - { ELYSIUM_TYPE_METADEX_CANCEL_PAIR, MP_TX_PKT_V0, false, ELYSIUM_METADEX_BLOCK }, - { ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM, MP_TX_PKT_V0, false, ELYSIUM_METADEX_BLOCK }, - - { ELYSIUM_TYPE_SEND_ALL, MP_TX_PKT_V0, false, ELYSIUM_SEND_ALL_BLOCK }, - - { ELYSIUM_TYPE_OFFER_ACCEPT_A_BET, MP_TX_PKT_V0, false, ELYSIUM_BET_BLOCK }, - - { ELYSIUM_TYPE_SIMPLE_SPEND, MP_TX_PKT_V0, false, SIGMA_FEATURE_BLOCK }, - { ELYSIUM_TYPE_SIMPLE_SPEND, MP_TX_PKT_V1, false, SIGMA_SPENDV1_FEATURE_BLOCK }, - { ELYSIUM_TYPE_CREATE_DENOMINATION, MP_TX_PKT_V0, false, SIGMA_FEATURE_BLOCK }, - { ELYSIUM_TYPE_SIMPLE_MINT, MP_TX_PKT_V0, false, SIGMA_FEATURE_BLOCK }, - }; - - const size_t nSize = sizeof(vTxRestrictions) / sizeof(vTxRestrictions[0]); - - return std::vector(vTxRestrictions, vTxRestrictions + nSize); -} - -/** - * Returns an empty vector of consensus checkpoints. - * - * This method should be overwriten by the child classes, if needed. - */ -std::vector CConsensusParams::GetCheckpoints() const -{ - return std::vector(); -} - -/** - * Constructor for mainnet consensus parameters. - */ -CMainConsensusParams::CMainConsensusParams() -{ - GENESIS_BLOCK = 108888; - - // Notice range for feature activations: - MIN_ACTIVATION_BLOCKS = 2048; // ~2 weeks - MAX_ACTIVATION_BLOCKS = 12288; // ~12 weeks - - // Waiting period for enabling freezing - ELYSIUM_FREEZE_WAIT_PERIOD = 4096; // ~4 weeks - - // Script related: - PUBKEYHASH_BLOCK = 0; - SCRIPTHASH_BLOCK = 0; - MULTISIG_BLOCK = 0; - NULLDATA_BLOCK = 0; - - // Transaction restrictions: - ELYSIUM_ALERT_BLOCK = 0; - ELYSIUM_SEND_BLOCK = 0; - ELYSIUM_DEX_BLOCK = 0; - ELYSIUM_SP_BLOCK = 0; - ELYSIUM_MANUALSP_BLOCK = 0; - ELYSIUM_STO_BLOCK = 0; - ELYSIUM_METADEX_BLOCK = 0; - ELYSIUM_SEND_ALL_BLOCK = 0; - ELYSIUM_BET_BLOCK = 999999; - ELYSIUM_STOV1_BLOCK = 999999; - - // Other feature activations: - GRANTEFFECTS_FEATURE_BLOCK = 0; - DEXMATH_FEATURE_BLOCK = 0; - SPCROWDCROSSOVER_FEATURE_BLOCK = 0; - TRADEALLPAIRS_FEATURE_BLOCK = 0; - FEES_FEATURE_BLOCK = 999999; - FREEZENOTICE_FEATURE_BLOCK = 999999; - - // Sigma releated - SIGMA_FEATURE_BLOCK = 212000; // 4 Nov 2019 - SIGMA_SPENDV1_FEATURE_BLOCK = 281532; // 1 July 2020 - - // Property creation fee - PROPERTY_CREATION_FEE_BLOCK = 212000; - PROPERTY_CREATION_FEE = 10 * COIN; - PROPERTY_CREATION_FEE_RECEIVER.SetString("a1HwTdCmQV3NspP2QqCGpehoFpi8NY4Zg3"); -} - -/** - * Constructor for testnet consensus parameters. - */ -CTestNetConsensusParams::CTestNetConsensusParams() -{ - GENESIS_BLOCK = 87000; - - // Notice range for feature activations: - MIN_ACTIVATION_BLOCKS = 0; - MAX_ACTIVATION_BLOCKS = 999999; - - // Waiting period for enabling freezing - ELYSIUM_FREEZE_WAIT_PERIOD = 0; - - // Script related: - PUBKEYHASH_BLOCK = 0; - SCRIPTHASH_BLOCK = 0; - MULTISIG_BLOCK = 0; - NULLDATA_BLOCK = 0; - - // Transaction restrictions: - ELYSIUM_ALERT_BLOCK = 0; - ELYSIUM_SEND_BLOCK = 0; - ELYSIUM_DEX_BLOCK = 0; - ELYSIUM_SP_BLOCK = 0; - ELYSIUM_MANUALSP_BLOCK = 0; - ELYSIUM_STO_BLOCK = 0; - ELYSIUM_METADEX_BLOCK = 0; - ELYSIUM_SEND_ALL_BLOCK = 0; - ELYSIUM_BET_BLOCK = 999999; - ELYSIUM_STOV1_BLOCK = 999999; - - // Other feature activations: - GRANTEFFECTS_FEATURE_BLOCK = 0; - DEXMATH_FEATURE_BLOCK = 0; - SPCROWDCROSSOVER_FEATURE_BLOCK = 0; - TRADEALLPAIRS_FEATURE_BLOCK = 0; - FEES_FEATURE_BLOCK = 999999; - FREEZENOTICE_FEATURE_BLOCK = 999999; - - // sigma related - SIGMA_FEATURE_BLOCK = 100000; - SIGMA_SPENDV1_FEATURE_BLOCK = 140000; - - // Property creation fee - PROPERTY_CREATION_FEE_BLOCK = 100000; - PROPERTY_CREATION_FEE = 10 * COIN; - PROPERTY_CREATION_FEE_RECEIVER.SetString("TG2ruj59E5b1u9G3F7HQVs6pCcVDBxrQve"); -} - -/** - * Constructor for regtest consensus parameters. - */ -CRegTestConsensusParams::CRegTestConsensusParams() -{ - GENESIS_BLOCK = 101; - - // Notice range for feature activations: - MIN_ACTIVATION_BLOCKS = 5; - MAX_ACTIVATION_BLOCKS = 10; - - // Waiting period for enabling freezing - ELYSIUM_FREEZE_WAIT_PERIOD = 10; - - // Script related: - PUBKEYHASH_BLOCK = 0; - SCRIPTHASH_BLOCK = 0; - MULTISIG_BLOCK = 0; - NULLDATA_BLOCK = 0; - - // Transaction restrictions: - ELYSIUM_ALERT_BLOCK = 0; - ELYSIUM_SEND_BLOCK = 0; - ELYSIUM_DEX_BLOCK = 0; - ELYSIUM_SP_BLOCK = 0; - ELYSIUM_MANUALSP_BLOCK = 0; - ELYSIUM_STO_BLOCK = 0; - ELYSIUM_METADEX_BLOCK = 0; - ELYSIUM_SEND_ALL_BLOCK = 0; - ELYSIUM_BET_BLOCK = 999999; - ELYSIUM_STOV1_BLOCK = 999999; - - // Other feature activations: - GRANTEFFECTS_FEATURE_BLOCK = 0; - DEXMATH_FEATURE_BLOCK = 0; - SPCROWDCROSSOVER_FEATURE_BLOCK = 0; - TRADEALLPAIRS_FEATURE_BLOCK = 0; - FEES_FEATURE_BLOCK = 999999; - FREEZENOTICE_FEATURE_BLOCK = 999999; - - // sigma related - SIGMA_FEATURE_BLOCK = 100; - SIGMA_SPENDV1_FEATURE_BLOCK = 150; - - // Property creation fee - PROPERTY_CREATION_FEE_BLOCK = 250; - PROPERTY_CREATION_FEE = 10 * COIN; - PROPERTY_CREATION_FEE_RECEIVER.SetString("TG2ruj59E5b1u9G3F7HQVs6pCcVDBxrQve"); -} - -//! Consensus parameters for mainnet -static CMainConsensusParams mainConsensusParams; -//! Consensus parameters for testnet -static CTestNetConsensusParams testNetConsensusParams; -//! Consensus parameters for regtest mode -static CRegTestConsensusParams regTestConsensusParams; - -/** - * Returns consensus parameters for the given network. - */ -CConsensusParams& ConsensusParams(const std::string& network) -{ - if (network == "main") { - return mainConsensusParams; - } - if (network == "test") { - return testNetConsensusParams; - } - if (network == "regtest") { - return regTestConsensusParams; - } - // Fallback: - return mainConsensusParams; -} - -/** - * Returns currently active consensus parameter. - */ -const CConsensusParams& ConsensusParams() -{ - const std::string& network = Params().NetworkIDString(); - - return ConsensusParams(network); -} - -/** - * Returns currently active mutable consensus parameter. - */ -CConsensusParams& MutableConsensusParams() -{ - const std::string& network = Params().NetworkIDString(); - - return ConsensusParams(network); -} - -/** - * Resets consensus paramters. - */ -void ResetConsensusParams() -{ - mainConsensusParams = CMainConsensusParams(); - testNetConsensusParams = CTestNetConsensusParams(); - regTestConsensusParams = CRegTestConsensusParams(); -} - -/** - * Checks, if the script type is allowed as input. - */ -bool IsAllowedInputType(int whichType, int nBlock) -{ - const CConsensusParams& params = ConsensusParams(); - - switch (whichType) - { - case TX_PUBKEYHASH: - return (params.PUBKEYHASH_BLOCK <= nBlock); - - case TX_SCRIPTHASH: - return (params.SCRIPTHASH_BLOCK <= nBlock); - } - - return false; -} - -/** - * Checks, if the script type qualifies as output. - */ -bool IsAllowedOutputType(int whichType, int nBlock) -{ - const CConsensusParams& params = ConsensusParams(); - - switch (whichType) - { - case TX_PUBKEYHASH: - return (params.PUBKEYHASH_BLOCK <= nBlock); - - case TX_SCRIPTHASH: - return (params.SCRIPTHASH_BLOCK <= nBlock); - - case TX_MULTISIG: - return (params.MULTISIG_BLOCK <= nBlock); - - case TX_NULL_DATA: - return (params.NULLDATA_BLOCK <= nBlock); - } - - return false; -} - -/** - * Activates a feature at a specific block height, authorization has already been validated. - * - * Note: Feature activations are consensus breaking. It is not permitted to activate a feature within - * the next 2048 blocks (roughly 2 weeks), nor is it permitted to activate a feature further out - * than 12288 blocks (roughly 12 weeks) to ensure sufficient notice. - * This does not apply for activation during initialization (where loadingActivations is set true). - */ -bool ActivateFeature(uint16_t featureId, int activationBlock, uint32_t minClientVersion, int transactionBlock) -{ - PrintToLog("Feature activation requested (ID %d to go active as of block: %d)\n", featureId, activationBlock); - - const CConsensusParams& params = ConsensusParams(); - - // check activation block is allowed - if ((activationBlock < (transactionBlock + params.MIN_ACTIVATION_BLOCKS)) || - (activationBlock > (transactionBlock + params.MAX_ACTIVATION_BLOCKS))) { - PrintToLog("Feature activation of ID %d refused due to notice checks\n", featureId); - return false; - } - - // check whether the feature is already active - if (IsFeatureActivated(featureId, transactionBlock)) { - PrintToLog("Feature activation of ID %d refused as the feature is already live\n", featureId); - return false; - } - - // check feature is recognized and activation is successful - std::string featureName = GetFeatureName(featureId); - bool supported = ELYSIUM_VERSION >= minClientVersion; - switch (featureId) { - case FEATURE_CLASS_C: - MutableConsensusParams().NULLDATA_BLOCK = activationBlock; - break; - case FEATURE_METADEX: - MutableConsensusParams().ELYSIUM_METADEX_BLOCK = activationBlock; - break; - case FEATURE_BETTING: - MutableConsensusParams().ELYSIUM_BET_BLOCK = activationBlock; - break; - case FEATURE_GRANTEFFECTS: - MutableConsensusParams().GRANTEFFECTS_FEATURE_BLOCK = activationBlock; - break; - case FEATURE_DEXMATH: - MutableConsensusParams().DEXMATH_FEATURE_BLOCK = activationBlock; - break; - case FEATURE_SENDALL: - MutableConsensusParams().ELYSIUM_SEND_ALL_BLOCK = activationBlock; - break; - case FEATURE_SPCROWDCROSSOVER: - MutableConsensusParams().SPCROWDCROSSOVER_FEATURE_BLOCK = activationBlock; - break; - case FEATURE_TRADEALLPAIRS: - MutableConsensusParams().TRADEALLPAIRS_FEATURE_BLOCK = activationBlock; - break; - case FEATURE_FEES: - MutableConsensusParams().FEES_FEATURE_BLOCK = activationBlock; - break; - case FEATURE_STOV1: - MutableConsensusParams().ELYSIUM_STOV1_BLOCK = activationBlock; - break; - case FEATURE_FREEZENOTICE: - MutableConsensusParams().FREEZENOTICE_FEATURE_BLOCK = activationBlock; - break; - case FEATURE_SIGMA: - MutableConsensusParams().SIGMA_FEATURE_BLOCK = activationBlock; - break; - case FEATURE_SIGMA_SPENDV1: - MutableConsensusParams().SIGMA_SPENDV1_FEATURE_BLOCK = activationBlock; - break; - default: - supported = false; - break; - } - - PrintToLog("Feature activation of ID %d processed. %s will be enabled at block %d.\n", featureId, featureName, activationBlock); - AddPendingActivation(featureId, activationBlock, minClientVersion, featureName); - - if (!supported) { - PrintToLog("WARNING!!! AS OF BLOCK %d THIS CLIENT WILL BE OUT OF CONSENSUS AND WILL AUTOMATICALLY SHUTDOWN.\n", activationBlock); - std::string alertText = strprintf("Your client must be updated and will shutdown at block %d (unsupported feature %d ('%s') activated)\n", - activationBlock, featureId, featureName); - AddAlert("elysium", ALERT_BLOCK_EXPIRY, activationBlock, alertText); - AlertNotify(alertText); - } - - return true; -} - -/** - * Deactivates a feature immediately, authorization has already been validated. - * - * Note: There is no notice period for feature deactivation as: - * # It is reserved for emergency use in the event an exploit is found - * # No client upgrade is required - * # No action is required by users - */ -bool DeactivateFeature(uint16_t featureId, int transactionBlock) -{ - PrintToLog("Immediate feature deactivation requested (ID %d)\n", featureId); - - if (!IsFeatureActivated(featureId, transactionBlock)) { - PrintToLog("Feature deactivation of ID %d refused as the feature is not yet live\n", featureId); - return false; - } - - std::string featureName = GetFeatureName(featureId); - switch (featureId) { - case FEATURE_CLASS_C: - MutableConsensusParams().NULLDATA_BLOCK = 999999; - break; - case FEATURE_METADEX: - MutableConsensusParams().ELYSIUM_METADEX_BLOCK = 999999; - break; - case FEATURE_BETTING: - MutableConsensusParams().ELYSIUM_BET_BLOCK = 999999; - break; - case FEATURE_GRANTEFFECTS: - MutableConsensusParams().GRANTEFFECTS_FEATURE_BLOCK = 999999; - break; - case FEATURE_DEXMATH: - MutableConsensusParams().DEXMATH_FEATURE_BLOCK = 999999; - break; - case FEATURE_SENDALL: - MutableConsensusParams().ELYSIUM_SEND_ALL_BLOCK = 999999; - break; - case FEATURE_SPCROWDCROSSOVER: - MutableConsensusParams().SPCROWDCROSSOVER_FEATURE_BLOCK = 999999; - break; - case FEATURE_TRADEALLPAIRS: - MutableConsensusParams().TRADEALLPAIRS_FEATURE_BLOCK = 999999; - break; - case FEATURE_FEES: - MutableConsensusParams().FEES_FEATURE_BLOCK = 999999; - break; - case FEATURE_STOV1: - MutableConsensusParams().ELYSIUM_STOV1_BLOCK = 999999; - break; - case FEATURE_FREEZENOTICE: - MutableConsensusParams().FREEZENOTICE_FEATURE_BLOCK = 999999; - break; - case FEATURE_SIGMA: - MutableConsensusParams().SIGMA_FEATURE_BLOCK = 999999; - break; - case FEATURE_SIGMA_SPENDV1: - MutableConsensusParams().SIGMA_SPENDV1_FEATURE_BLOCK = 999999; - break; - default: - return false; - break; - } - - PrintToLog("Feature deactivation of ID %d processed. %s has been disabled.\n", featureId, featureName); - - std::string alertText = strprintf("An emergency deactivation of feature ID %d (%s) has occurred.", featureId, featureName); - AddAlert("elysium", ALERT_BLOCK_EXPIRY, transactionBlock + 1024, alertText); - AlertNotify(alertText); - - return true; -} - -/** - * Returns the display name of a feature ID - */ -std::string GetFeatureName(uint16_t featureId) -{ - switch (featureId) { - case FEATURE_CLASS_C: return "Class C transaction encoding"; - case FEATURE_METADEX: return "Distributed Meta Token Exchange"; - case FEATURE_BETTING: return "Bet transactions"; - case FEATURE_GRANTEFFECTS: return "Remove grant side effects"; - case FEATURE_DEXMATH: return "DEx integer math update"; - case FEATURE_SENDALL: return "Send All transactions"; - case FEATURE_SPCROWDCROSSOVER: return "Disable crowdsale ecosystem crossovers"; - case FEATURE_TRADEALLPAIRS: return "Allow trading all pairs on the Distributed Exchange"; - case FEATURE_FEES: return "Fee system (inc 0.05% fee from trades of non-Omni pairs)"; - case FEATURE_STOV1: return "Cross-property Send To Owners"; - case FEATURE_FREEZENOTICE: return "Activate the waiting period for enabling freezing"; - case FEATURE_SIGMA: return "Activate Sigma transactions"; - case FEATURE_SIGMA_SPENDV1: return "Activate Sigma spend V1 transactions"; - - default: return "Unknown feature"; - } -} - -/** - * Checks, whether a feature is activated at the given block. - */ -bool IsFeatureActivated(uint16_t featureId, int transactionBlock) -{ - const CConsensusParams& params = ConsensusParams(); - int activationBlock = std::numeric_limits::max(); - - switch (featureId) { - case FEATURE_CLASS_C: - activationBlock = params.NULLDATA_BLOCK; - break; - case FEATURE_METADEX: - activationBlock = params.ELYSIUM_METADEX_BLOCK; - break; - case FEATURE_BETTING: - activationBlock = params.ELYSIUM_BET_BLOCK; - break; - case FEATURE_GRANTEFFECTS: - activationBlock = params.GRANTEFFECTS_FEATURE_BLOCK; - break; - case FEATURE_DEXMATH: - activationBlock = params.DEXMATH_FEATURE_BLOCK; - break; - case FEATURE_SENDALL: - activationBlock = params.ELYSIUM_SEND_ALL_BLOCK; - break; - case FEATURE_SPCROWDCROSSOVER: - activationBlock = params.SPCROWDCROSSOVER_FEATURE_BLOCK; - break; - case FEATURE_TRADEALLPAIRS: - activationBlock = params.TRADEALLPAIRS_FEATURE_BLOCK; - break; - case FEATURE_FEES: - activationBlock = params.FEES_FEATURE_BLOCK; - break; - case FEATURE_STOV1: - activationBlock = params.ELYSIUM_STOV1_BLOCK; - break; - case FEATURE_FREEZENOTICE: - activationBlock = params.FREEZENOTICE_FEATURE_BLOCK; - break; - case FEATURE_SIGMA: - activationBlock = params.SIGMA_FEATURE_BLOCK; - break; - case FEATURE_SIGMA_SPENDV1: - activationBlock = params.SIGMA_SPENDV1_FEATURE_BLOCK; - break; - default: - return false; - } - - return (transactionBlock >= activationBlock); -} - -/** - * Checks, if the transaction type and version is supported and enabled. - * - * In the test ecosystem, transactions, which are known to the client are allowed - * without height restriction. - * - * Certain transactions use a property identifier of 0 (= BTC) as wildcard, which - * must explicitly be allowed. - */ -bool IsTransactionTypeAllowed(int txBlock, uint32_t txProperty, uint16_t txType, uint16_t version) -{ - const std::vector& vTxRestrictions = ConsensusParams().GetRestrictions(); - - for (std::vector::const_iterator it = vTxRestrictions.begin(); it != vTxRestrictions.end(); ++it) - { - const TransactionRestriction& entry = *it; - if (entry.txType != txType || entry.txVersion != version) { - continue; - } - // a property identifier of 0 (= FIRO) may be used as wildcard - if (ELYSIUM_PROPERTY_XZC == txProperty && !entry.allowWildcard) { - continue; - } - // transactions are not restricted in the test ecosystem - if (isTestEcosystemProperty(txProperty)) { - return true; - } - if (txBlock >= entry.activationBlock) { - return true; - } - } - - return false; -} - -/** - * Compares a supplied block, block hash and consensus hash against a hardcoded list of checkpoints. - */ -bool VerifyCheckpoint(int block, const uint256& blockHash) -{ - // optimization; we only checkpoint every 10,000 blocks - skip any further work if block not a multiple of 10K - if (block % 10000 != 0) return true; - - const std::vector& vCheckpoints = ConsensusParams().GetCheckpoints(); - - for (std::vector::const_iterator it = vCheckpoints.begin(); it != vCheckpoints.end(); ++it) { - const ConsensusCheckpoint& checkpoint = *it; - if (block != checkpoint.blockHeight) { - continue; - } - - if (blockHash != checkpoint.blockHash) { - PrintToLog("%s(): block hash mismatch - expected %s, received %s\n", __func__, checkpoint.blockHash.GetHex(), blockHash.GetHex()); - return false; - } - - // only verify if there is a checkpoint to verify against - uint256 consensusHash = GetConsensusHash(); - if (consensusHash != checkpoint.consensusHash) { - PrintToLog("%s(): consensus hash mismatch - expected %s, received %s\n", __func__, checkpoint.consensusHash.GetHex(), consensusHash.GetHex()); - return false; - } else { - break; - } - } - - // either checkpoint matched or we don't have a checkpoint for this block - return true; -} - -} // namespace elysium diff --git a/src/elysium/rules.h b/src/elysium/rules.h deleted file mode 100644 index 55e6df8ebe..0000000000 --- a/src/elysium/rules.h +++ /dev/null @@ -1,340 +0,0 @@ -#ifndef FIRO_ELYSIUM_RULES_H -#define FIRO_ELYSIUM_RULES_H - -#include "../amount.h" -#include "../base58.h" -#include "../uint256.h" - -#include -#include - -#include - -namespace elysium { - -/** - * Feature identifier to enable Class C transaction parsing and processing. - **/ -constexpr uint16_t FEATURE_CLASS_C = 1; - -/** - * Feature identifier to enable the distributed token exchange. - **/ -constexpr uint16_t FEATURE_METADEX = 2; - -/** - * Feature identifier to enable betting transactions. - **/ -constexpr uint16_t FEATURE_BETTING = 3; - -/** - * Feature identifier to disable crowdsale participations when "granting tokens". - **/ -constexpr uint16_t FEATURE_GRANTEFFECTS = 4; - -/** - * Feature identifier to disable DEx "over-offers" and to switch to plain integer math. - **/ -constexpr uint16_t FEATURE_DEXMATH = 5; - -/** - * Feature identifier to enable Send All transactions. - **/ -constexpr uint16_t FEATURE_SENDALL = 6; - -/** - * Feature identifier disable ecosystem crossovers in crowdsale logic. - **/ -constexpr uint16_t FEATURE_SPCROWDCROSSOVER = 7; - -/** - * Feature identifier to enable non-Omni pairs on the distributed exchange. - **/ -constexpr uint16_t FEATURE_TRADEALLPAIRS = 8; - -/** - * Feature identifier to enable the fee cache and strip 0.05% fees from non-Omni pairs. - **/ -constexpr uint16_t FEATURE_FEES = 9; - -/** - * Feature identifier to enable cross property (v1) Send To Owners. - **/ -constexpr uint16_t FEATURE_STOV1 = 10; - -/** - * Feature identifier to activate the waiting period for enabling managed property address freezing. - **/ -constexpr uint16_t FEATURE_FREEZENOTICE = 14; - -/** - * Feature identifier to activate sigma on elysium. - **/ -constexpr uint16_t FEATURE_SIGMA = 15; - -/** - * Feature indentifier to activate sigma spend v1 on elysium. - **/ -constexpr uint16_t FEATURE_SIGMA_SPENDV1 = 16; - -//! When (propertyTotalTokens / ELYSIUM_FEE_THRESHOLD) is reached fee distribution will occur -const int64_t ELYSIUM_FEE_THRESHOLD = 100000; // 0.001% - -/** A structure to represent transaction restrictions. - */ -struct TransactionRestriction -{ - //! Transaction type - uint16_t txType; - //! Transaction version - uint16_t txVersion; - //! Whether the property identifier can be 0 (= BTC) - bool allowWildcard; - //! Block after which the feature or transaction is enabled - int activationBlock; -}; - -/** A structure to represent a verification checkpoint. - */ -struct ConsensusCheckpoint -{ - int blockHeight; - uint256 blockHash; - uint256 consensusHash; -}; - -// TODO: rename allcaps variable names -// TODO: remove remaining global heights -// TODO: add Elysium addresses to params - -/** - * Base class for consensus parameters. - **/ -class CConsensusParams -{ -public: - /** - * First block of the Elysium feature. - **/ - int GENESIS_BLOCK; - - /** - * Minimum number of blocks to use for notice rules on activation. - **/ - int MIN_ACTIVATION_BLOCKS; - - /** - * Maximum number of blocks to use for notice rules on activation. - **/ - int MAX_ACTIVATION_BLOCKS; - - /** - * Waiting period after enabling freezing before addresses may be frozen. - **/ - int ELYSIUM_FREEZE_WAIT_PERIOD; - - /** - * Block to enable pay-to-pubkey-hash support. - **/ - int PUBKEYHASH_BLOCK; - - /** - * Block to enable pay-to-script-hash support. - **/ - int SCRIPTHASH_BLOCK; - - /** - * Block to enable bare-multisig based encoding. - **/ - int MULTISIG_BLOCK; - - /** - * Block to enable OP_RETURN based encoding. - **/ - int NULLDATA_BLOCK; - - /** - * Block to enable alerts and notifications. - **/ - int ELYSIUM_ALERT_BLOCK; - - /** - * Block to enable simple send transactions. - **/ - int ELYSIUM_SEND_BLOCK; - - /** - * Block to enable DEx transactions. - **/ - int ELYSIUM_DEX_BLOCK; - - /** - * Block to enable smart property transactions. - **/ - int ELYSIUM_SP_BLOCK; - - /** - * Block to enable managed properties. - **/ - int ELYSIUM_MANUALSP_BLOCK; - - /** - * Block to enable send-to-owners transactions. - **/ - int ELYSIUM_STO_BLOCK; - - /** - * Block to enable MetaDEx transactions. - **/ - int ELYSIUM_METADEX_BLOCK; - - /** - * Block to enable "send all" transactions. - **/ - int ELYSIUM_SEND_ALL_BLOCK; - - /** - * Block to enable betting transactions. - **/ - int ELYSIUM_BET_BLOCK; - - /** - * Block to enable cross property STO (v1). - **/ - int ELYSIUM_STOV1_BLOCK; - - /** - * Block to deactivate crowdsale participations when "granting tokens". - **/ - int GRANTEFFECTS_FEATURE_BLOCK; - - /** - * Block to disable DEx "over-offers" and to switch to plain integer math. - **/ - int DEXMATH_FEATURE_BLOCK; - - /** - * Block to disable ecosystem crossovers in crowdsale logic. - **/ - int SPCROWDCROSSOVER_FEATURE_BLOCK; - - /** - * Block to enable trading of non-Omni pairs. - **/ - int TRADEALLPAIRS_FEATURE_BLOCK; - - /** - * Block to enable the fee system & 0.05% fee for trading non-Omni pairs. - **/ - int FEES_FEATURE_BLOCK; - - /** - * Block to activate the waiting period for enabling managed property address freezing. - **/ - int FREEZENOTICE_FEATURE_BLOCK; - - /** - * Block to activate Sigma related features. - **/ - int SIGMA_FEATURE_BLOCK; - - /** - * Block to activate Sigma spend version 1 - **/ - int SIGMA_SPENDV1_FEATURE_BLOCK; - - /** - * Block to activate property creation fee. - **/ - int PROPERTY_CREATION_FEE_BLOCK; - - /** - * Amount of FIRO to pay when create a new property on main ecosystem. - **/ - CAmount PROPERTY_CREATION_FEE; - - /** - * The address to receive property creation fee. - **/ - CBitcoinAddress PROPERTY_CREATION_FEE_RECEIVER; - - /** - * Returns a mapping of transaction types, and the blocks at which they are enabled. - **/ - virtual std::vector GetRestrictions() const; - - /** - * Returns an empty vector of consensus checkpoints. - **/ - virtual std::vector GetCheckpoints() const; - - virtual ~CConsensusParams() {} - -protected: - CConsensusParams() {} -}; - -/** Consensus parameters for mainnet. - */ -class CMainConsensusParams: public CConsensusParams -{ -public: - /** Constructor for mainnet consensus parameters. */ - CMainConsensusParams(); - /** Destructor. */ - virtual ~CMainConsensusParams() {} -}; - -/** Consensus parameters for testnet. - */ -class CTestNetConsensusParams: public CConsensusParams -{ -public: - /** Constructor for testnet consensus parameters. */ - CTestNetConsensusParams(); - /** Destructor. */ - virtual ~CTestNetConsensusParams() {} -}; - -/** Consensus parameters for regtest mode. - */ -class CRegTestConsensusParams: public CConsensusParams -{ -public: - /** Constructor for regtest consensus parameters. */ - CRegTestConsensusParams(); - /** Destructor. */ - virtual ~CRegTestConsensusParams() {} -}; - -/** Returns consensus parameters for the given network. */ -CConsensusParams& ConsensusParams(const std::string& network); -/** Returns currently active consensus parameter. */ -const CConsensusParams& ConsensusParams(); -/** Returns currently active mutable consensus parameter. */ -CConsensusParams& MutableConsensusParams(); -/** Resets consensus paramters. */ -void ResetConsensusParams(); - - -/** Gets the display name for a feature ID */ -std::string GetFeatureName(uint16_t featureId); -/** Activates a feature at a specific block height. */ -bool ActivateFeature(uint16_t featureId, int activationBlock, uint32_t minClientVersion, int transactionBlock); -/** Deactivates a feature immediately, authorization has already been validated. */ -bool DeactivateFeature(uint16_t featureId, int transactionBlock); -/** Checks, whether a feature is activated at the given block. */ -bool IsFeatureActivated(uint16_t featureId, int transactionBlock); -/** Checks, if the script type is allowed as input. */ -bool IsAllowedInputType(int whichType, int nBlock); -/** Checks, if the script type qualifies as output. */ -bool IsAllowedOutputType(int whichType, int nBlock); -/** Checks, if the transaction type and version is supported and enabled. */ -bool IsTransactionTypeAllowed(int txBlock, uint32_t txProperty, uint16_t txType, uint16_t version); - -/** Compares a supplied block, block hash and consensus hash against a hardcoded list of checkpoints. */ -bool VerifyCheckpoint(int block, const uint256& blockHash); - -} // namespace elysium - -#endif // FIRO_ELYSIUM_RULES_H diff --git a/src/elysium/script.cpp b/src/elysium/script.cpp deleted file mode 100644 index fc87b066dd..0000000000 --- a/src/elysium/script.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "elysium/script.h" - -#include "amount.h" -#include "script/script.h" -#include "script/standard.h" -#include "serialize.h" -#include "utilstrencodings.h" - -#include - -#include -#include -#include - -/** The minimum transaction relay fee. */ -extern CFeeRate minRelayTxFee; - -/** - * Determines the minimum output amount to be spent by an output, based on the - * scriptPubKey size in relation to the minimum relay fee. - * - * @param scriptPubKey[in] The scriptPubKey - * @return The dust threshold value - */ -int64_t GetDustThreshold(const CScript& scriptPubKey) -{ - CTxOut txOut(0, scriptPubKey); - - return txOut.GetDustThreshold(minRelayTxFee); -} - -/** - * Identifies standard output types based on a scriptPubKey. - * - * Note: whichTypeRet is set to TX_NONSTANDARD, if no standard script was found. - * - * @param scriptPubKey[in] The script - * @param whichTypeRet[out] The output type - * @return True if a standard script was found - */ -bool GetOutputType(const CScript& scriptPubKey, txnouttype& whichTypeRet) -{ - std::vector > vSolutions; - - if (SafeSolver(scriptPubKey, whichTypeRet, vSolutions)) { - return true; - } - whichTypeRet = TX_NONSTANDARD; - - return false; -} - -/** - * Returns public keys or hashes from scriptPubKey, for standard transaction types. - * - * Note: in contrast to the script/standard/Solver, this Solver is not affected by - * user settings, and in particular any OP_RETURN size is considered as standard. - * - * @param scriptPubKey[in] The script - * @param typeRet[out] The output type - * @param vSolutionsRet[out] The extracted public keys or hashes - * @return True if a standard script was found - */ -bool SafeSolver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet) -{ - // Templates - static std::multimap mTemplates; - if (mTemplates.empty()) - { - // Standard tx, sender provides pubkey, receiver adds signature - mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); - - // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey - mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); - - // Modification of the previous one but with super transparent address - mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_EXCHANGEADDR << OP_DUP << OP_HASH160 << OP_EQUALVERIFY << OP_CHECKSIG)); - - // Sender provides N pubkeys, receivers provides M signatures - mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); - - // Empty, provably prunable, data-carrying output - mTemplates.insert(std::make_pair(TX_NULL_DATA, CScript() << OP_RETURN)); - } - - vSolutionsRet.clear(); - - // Shortcut for pay-to-script-hash, which are more constrained than the other types: - // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL - if (scriptPubKey.IsPayToScriptHash()) - { - typeRet = TX_SCRIPTHASH; - std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); - vSolutionsRet.push_back(hashBytes); - return true; - } - - // Provably prunable, data-carrying output - // - // So long as script passes the IsUnspendable() test and all but the first - // byte passes the IsPushOnly() test we don't care what exactly is in the - // script. - if (scriptPubKey.size() >= 2 && scriptPubKey[0] == OP_RETURN) - { - CScript script(scriptPubKey.begin()+1, scriptPubKey.end()); - if (script.IsPushOnly()) { - typeRet = TX_NULL_DATA; - return true; - } - } - - // Scan templates - const CScript& script1 = scriptPubKey; - BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates) - { - const CScript& script2 = tplate.second; - vSolutionsRet.clear(); - - opcodetype opcode1, opcode2; - std::vector vch1, vch2; - - // Compare - CScript::const_iterator pc1 = script1.begin(); - CScript::const_iterator pc2 = script2.begin(); - while (true) - { - if (pc1 == script1.end() && pc2 == script2.end()) - { - // Found a match - typeRet = tplate.first; - if (typeRet == TX_MULTISIG) - { - // Additional checks for TX_MULTISIG: - unsigned char m = vSolutionsRet.front()[0]; - unsigned char n = vSolutionsRet.back()[0]; - if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n) - return false; - } - return true; - } - if (!script1.GetOp(pc1, opcode1, vch1)) - break; - if (!script2.GetOp(pc2, opcode2, vch2)) - break; - - // Template matching opcodes: - if (opcode2 == OP_PUBKEYS) - { - while (vch1.size() >= 33 && vch1.size() <= 65) - { - vSolutionsRet.push_back(vch1); - if (!script1.GetOp(pc1, opcode1, vch1)) - break; - } - if (!script2.GetOp(pc2, opcode2, vch2)) - break; - // Normal situation is to fall through - // to other if/else statements - } - - if (opcode2 == OP_PUBKEY) - { - if (vch1.size() < 33 || vch1.size() > 65) - break; - vSolutionsRet.push_back(vch1); - } - else if (opcode2 == OP_PUBKEYHASH) - { - if (vch1.size() != sizeof(uint160)) - break; - vSolutionsRet.push_back(vch1); - } - else if (opcode2 == OP_SMALLINTEGER) - { // Single-byte small integer pushed onto vSolutions - if (opcode1 == OP_0 || - (opcode1 >= OP_1 && opcode1 <= OP_16)) - { - char n = (char)CScript::DecodeOP_N(opcode1); - vSolutionsRet.push_back(std::vector(1, n)); - } - else - break; - } - else if (opcode1 != opcode2 || vch1 != vch2) - { - // Others must match exactly - break; - } - } - } - - vSolutionsRet.clear(); - typeRet = TX_NONSTANDARD; - return false; -} diff --git a/src/elysium/script.h b/src/elysium/script.h deleted file mode 100644 index febe22606a..0000000000 --- a/src/elysium/script.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef FIRO_ELYSIUM_SCRIPT_H -#define FIRO_ELYSIUM_SCRIPT_H - -#include "../script/script.h" -#include "../script/standard.h" - -#include - -#include - -/** Determines the minimum output amount to be spent by an output. */ -int64_t GetDustThreshold(const CScript& scriptPubKey); - -/** Identifies standard output types based on a scriptPubKey. */ -bool GetOutputType(const CScript& scriptPubKey, txnouttype& whichTypeRet); - -/** Returns public keys or hashes from scriptPubKey, for standard transaction types. */ -bool SafeSolver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet); - -namespace elysium { - -/** - * Extracts the pushed data from a script. - **/ -template -Output GetPushedValues(const CScript& script, Output output) -{ - auto pc = script.begin(); - - while (pc < script.end()) { - opcodetype op; - std::vector data; - - if (!script.GetOp(pc, op, data)) { - return output; - } - - if (op >= 0x00 && op <= OP_PUSHDATA4) { - *output++ = data; - } - } - - return output; -} - -} // namespace elysium - -#endif // FIRO_ELYSIUM_SCRIPT_H diff --git a/src/elysium/sigma.cpp b/src/elysium/sigma.cpp deleted file mode 100644 index 0f2214342e..0000000000 --- a/src/elysium/sigma.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "sigma.h" - -#include "sigmadb.h" -#include "sigmaprimitives.h" - -#include "../validation.h" -#include "../sync.h" - -#include -#include - -namespace elysium { - -bool VerifySigmaSpend( - PropertyId property, - SigmaDenomination denomination, - SigmaMintGroup group, - size_t groupSize, - const SigmaProof& proof, - const secp_primitives::Scalar& serial, - bool fPadding) -{ - std::vector anonimitySet; // Don't preallocate the vector due to it will allow attacker to crash all client. - - { - LOCK(cs_main); - sigmaDb->GetAnonimityGroup(property, denomination, group, groupSize, std::back_inserter(anonimitySet)); - } - - // If the size of anonimity set is not the expected once then no need to verify the proof. - if (anonimitySet.size() != groupSize) { - return false; - } - - return proof.Verify(serial, anonimitySet.begin(), anonimitySet.end(), fPadding); -} - -} // namespace elysium diff --git a/src/elysium/sigma.h b/src/elysium/sigma.h deleted file mode 100644 index f934d1fbaf..0000000000 --- a/src/elysium/sigma.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef FIRO_ELYSIUM_SIGMA_H -#define FIRO_ELYSIUM_SIGMA_H - -#include "property.h" -#include "sigmaprimitives.h" - -#include - -namespace elysium { - -bool VerifySigmaSpend( - PropertyId property, - SigmaDenomination denomination, - SigmaMintGroup group, - size_t groupSize, - const SigmaProof& proof, - const secp_primitives::Scalar& serial, - bool fPadding); - -} // namespace elysium - -#endif // FIRO_ELYSIUM_SIGMA_H diff --git a/src/elysium/sigmadb.cpp b/src/elysium/sigmadb.cpp deleted file mode 100644 index 588b620081..0000000000 --- a/src/elysium/sigmadb.cpp +++ /dev/null @@ -1,710 +0,0 @@ -#include "elysium.h" -#include "errors.h" -#include "log.h" -#include "sigmadb.h" -#include "sp.h" -#include "tally.h" -#include "tx.h" - -#include -#include "../clientversion.h" -#include "../tinyformat.h" -#include "../streams.h" - -#include - -#include -#include - -#include -#include - -namespace elysium { - -enum class KeyType : uint8_t -{ - Mint = 0, - Sequence = 1, - GroupSize = 2, - SpendSerial = 3 -}; - -template -struct SizeOf; - -template -struct SizeOf -{ - static constexpr size_t Value = (sizeof(T)); -}; - -template -struct SizeOf -{ - static constexpr size_t Value = (sizeof(T) + SizeOf::Value); -}; - -template -It SerializeKey(It it) -{ - return it; -} - -template -It SerializeKey(It it, std::array t, R ...r) -{ - it = std::copy(t.begin(), t.end(), it); - return SerializeKey(it, r...); -} - -template< - typename It, typename T, typename ...R, - typename std::enable_if::value>::type* = nullptr -> It SerializeKey(It it, T t, R ...r) -{ - if (sizeof(t) > 1) { - elysium::swapByteOrder(t); - } - it = std::copy_n(reinterpret_cast(&t), sizeof(t), it); - return SerializeKey(it, r...); -} - -template::Value> -std::array CreateKey(KeyType type, T ...args) -{ - std::array key; - auto it = key.begin(); - it = std::copy_n(reinterpret_cast(&type), sizeof(type), it); - - SerializeKey(it, args...); - - return key; -} - -// array size represent size of key -// <1 byte of type><4 bytes of property Id><1 byte of denomination><4 bytes of group id><2 bytes of idx> -#define MINT_KEY_SIZE sizeof(KeyType) + sizeof(uint8_t) + sizeof(uint16_t) + 2 * sizeof(uint32_t) -std::array CreateMintKey( - uint32_t propertyId, - uint8_t denomination, - uint32_t groupId, - uint16_t idx) -{ - return CreateKey(KeyType::Mint, propertyId, denomination, groupId, idx); -} - -// array size represent size of key -// <1 byte of type><8 bytes of sequence> -#define SEQUENCE_KEY_SIZE sizeof(KeyType) + sizeof(uint64_t) -std::array CreateSequenceKey( - uint64_t sequence) -{ - return CreateKey(KeyType::Sequence, sequence); -} - -// array size represent size of key -// <1 byte of type> -#define GROUPSIZE_KEY_SIZE sizeof(KeyType) -std::array CreateGroupSizeKey() -{ - return CreateKey(KeyType::GroupSize); -} - -typedef std::array SpendSerial; - -// array size represent size of key -// <1 byte of type><4 bytes of property Id><1 byte of denomination><32 bytes of serials> -#define SPEND_KEY_SIZE sizeof(KeyType) + sizeof(uint32_t) + sizeof(uint8_t) + std::tuple_size::value -std::array CreateSpendSerialKey( - uint32_t propertyId, - uint8_t denomination, - SpendSerial const &serial) -{ - return CreateKey(KeyType::SpendSerial, propertyId, denomination, serial); -} - -inline bool IsMintKey(leveldb::Slice const &key) -{ - return key.size() == MINT_KEY_SIZE && key[0] == static_cast(KeyType::Mint); -} - -inline bool IsMintEntry(leveldb::Iterator *it) -{ - return IsMintKey(it->key()); -} - -inline bool IsSequenceKey(leveldb::Slice const &key) -{ - return key.size() == SEQUENCE_KEY_SIZE && key[0] == static_cast(KeyType::Sequence); -} - -inline bool IsSequenceEntry(leveldb::Iterator *it) -{ - return IsSequenceKey(it->key()); -} - -inline bool IsSpendSerialKey(leveldb::Slice const &key) -{ - return key.size() == SPEND_KEY_SIZE && key[0] == static_cast(KeyType::SpendSerial); -} - -inline bool IsSpendSerialEntry(leveldb::Iterator *it) -{ - return IsSpendSerialKey(it->key()); -} - -template -leveldb::Slice GetSlice(const std::array& v) -{ - return leveldb::Slice(reinterpret_cast(v.data()), v.size()); -} - -template -leveldb::Slice GetSlice(const std::vector& v) -{ - return leveldb::Slice(reinterpret_cast(v.data()), v.size() * sizeof(T)); -} - -SigmaPublicKey ParseMint(const std::string& val) -{ - if (val.size() != secp_primitives::GroupElement::serialize_size) { - throw std::runtime_error("ParseMint() : invalid key size"); - } - - SigmaPublicKey key; - key.commitment.deserialize(reinterpret_cast(val.data())); - - return key; -} - -bool ParseMintKey( - const leveldb::Slice& key, uint32_t& propertyId, uint8_t& denomination, uint32_t& groupId, uint16_t& idx) -{ - if (key.size() > 0 && key.data()[0] == static_cast(KeyType::Mint)) { - if (key.size() != MINT_KEY_SIZE) { - throw std::runtime_error("invalid key size"); - } - - auto it = key.data() + sizeof(KeyType); - std::memcpy(&propertyId, it, sizeof(propertyId)); - std::memcpy(&denomination, it += sizeof(propertyId), sizeof(denomination)); - std::memcpy(&groupId, it += sizeof(denomination), sizeof(groupId)); - std::memcpy(&idx, it += sizeof(groupId), sizeof(idx)); - - elysium::swapByteOrder(propertyId); - elysium::swapByteOrder(groupId); - elysium::swapByteOrder(idx); - - return true; - } - return false; -} - -bool ParseSpendSerialKey( - const leveldb::Slice& key, uint32_t& propertyId, uint8_t& denomination, SpendSerial& serial) -{ - if (key.size() > 0 && key.data()[0] == static_cast(KeyType::SpendSerial)) { - if (key.size() != SPEND_KEY_SIZE) { - throw std::runtime_error("invalid key size"); - } - - auto it = key.data() + sizeof(KeyType); - std::memcpy(&propertyId, it, sizeof(propertyId)); - std::memcpy(&denomination, it += sizeof(propertyId), sizeof(denomination)); - std::memcpy(serial.data(), it += sizeof(denomination), std::tuple_size::value); - - elysium::swapByteOrder(propertyId); - - return true; - } - return false; -} - -SpendSerial SerializeSpendSerial(secp_primitives::Scalar const &serial) -{ - SpendSerial s; - if (serial.memoryRequired() != std::tuple_size::value) { - throw std::invalid_argument("serial size is invalid"); - } - - serial.serialize(s.data()); - return s; -} - -void SafeSeekToPreviousKey(leveldb::Iterator *it, const leveldb::Slice& key) -{ - it->Seek(key); - if (it->Valid()) { - it->Prev(); - } else { - it->SeekToLast(); - } -} - -SigmaDatabase *sigmaDb; - -constexpr uint16_t SigmaDatabase::MAX_GROUP_SIZE; - -// Database structure -// Index height and commitment -// 0= -// Sequence of mint sorted following blockchain -// 1=key -SigmaDatabase::SigmaDatabase(const boost::filesystem::path& path, bool wipe, uint16_t groupSize) -{ - auto status = Open(path, wipe); - if (!status.ok()) { - throw std::runtime_error("Failed to create " + path.string() + ": " + status.ToString()); - } - - this->groupSize = InitGroupSize(groupSize); -} - -SigmaDatabase::~SigmaDatabase() -{ -} - -std::pair SigmaDatabase::RecordMint( - PropertyId propertyId, - SigmaDenomination denomination, - const SigmaPublicKey& pubKey, - int height) -{ - auto lastGroup = GetLastGroupId(propertyId, denomination); - auto mints = GetMintCount(propertyId, denomination, lastGroup); - - if (mints > groupSize) { - throw std::runtime_error("mints count is exceed group limit"); - } - auto nextIdx = mints; - - if (mints == groupSize) { - lastGroup++; - nextIdx = 0; - } - - // Add mint entry. - auto keyData = CreateMintKey(propertyId, denomination, lastGroup, nextIdx); - auto key = GetSlice(keyData); - - std::vector buffer(pubKey.commitment.memoryRequired()); - pubKey.commitment.serialize(buffer.data()); - - AddEntry(key, GetSlice(buffer), height); - - // Raise event. - MintAdded(propertyId, denomination, lastGroup, nextIdx, pubKey, height); - - return std::make_pair(lastGroup, nextIdx); -} - -void SigmaDatabase::RecordSpendSerial( - uint32_t propertyId, - uint8_t denomination, - secp_primitives::Scalar const &serial, - int height, - uint256 const &spendTx) -{ - auto serialData = SerializeSpendSerial(serial); - auto keyData = CreateSpendSerialKey(propertyId, denomination, serialData); - - AddEntry(GetSlice(keyData), leveldb::Slice(std::string(spendTx.begin(), spendTx.end())), height); - - SpendAdded(propertyId, denomination, serial, spendTx); -} - -// operation code of histories -enum class OpCode : uint8_t -{ - StoreMint = 0, - StoreSpendSerial = 1 -}; - -class History -{ -public: - History() - { - } - - History(int32_t block, OpCode op, std::vector const &data) - : block(block), op(op), data(data.begin(), data.end()) - { - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) - { - auto op = static_cast(this->op); - - READWRITE(block); - READWRITE(op); - READWRITE(data); - - this->op = static_cast(op); - } - - int32_t block; - OpCode op; - std::vector data; -}; - -void SigmaDatabase::DeleteAll(int startBlock) -{ - auto nextSequence = GetNextSequence(); - if (nextSequence == 0) { - // No mint to delete - return; - } - - // Seek to most recent history. - auto lastSequence = nextSequence - 1; - auto sequenceKey = CreateSequenceKey(lastSequence); - - auto it = NewIterator(); - it->Seek(GetSlice(sequenceKey)); - - leveldb::WriteBatch batch; - std::vector> defers; // functions to be called after delete whole keys - for (; it->Valid() && IsSequenceEntry(it.get()); it->Prev()) { - - CDataStream deserialized( - it->value().data(), - it->value().data() + it->value().size(), - SER_DISK, CLIENT_VERSION - ); - - // Check if it need to delete then push it to batch - History entry; - deserialized >> entry; - - if (entry.block < startBlock) { - // We iterate in the latest to oldest that mean we can stop as soon as we found it block number is lower - // than theshold. - break; - } - - // intentionally using if instead of switch to separate scope - if (entry.op == OpCode::StoreMint) { - auto key = GetSlice(entry.data); - - // retrieve meta data of mint - uint32_t propertyId; - uint8_t denomination; - uint32_t groupId; - uint16_t count; - if (!ParseMintKey(key, propertyId, denomination, groupId, count)) { - throw std::runtime_error("fail to parse mint key"); - } - - // get commitment - std::string data; - auto status = pdb->Get(readoptions, key, &data); - if (!status.ok()) { - throw std::runtime_error("fail to get mint"); - } - CDataStream pubkeyDeserialized(data.data(), data.data() + data.size(), SER_DISK, CLIENT_VERSION); - SigmaPublicKey pub; - pubkeyDeserialized >> pub; - - // function to trigger event - defers.push_back([this, propertyId, denomination, pub]() { - MintRemoved(propertyId, denomination, pub); - }); - - batch.Delete(GetSlice(entry.data)); - } else if (entry.op == OpCode::StoreSpendSerial) { - auto key = GetSlice(entry.data); - - // retrieve meta data of spend - uint32_t propertyId; - uint8_t denomination; - SpendSerial serialData; - ParseSpendSerialKey(key, propertyId, denomination, serialData); - - secp_primitives::Scalar serial; - serial.deserialize(serialData.data()); - - // function to trigger event - defers.push_back([this, propertyId, denomination, serial]() { - SpendRemoved(propertyId, denomination, serial); - }); - - batch.Delete(key); - } else { - throw std::runtime_error("opcode is invalid"); - } - - batch.Delete(it->key()); - } - - auto status = pdb->Write(syncoptions, &batch); - if (!status.ok()) { - throw std::runtime_error("Fail to update database"); - } - - for (auto &defer : defers) { - defer(); - } -} - -void SigmaDatabase::RecordGroupSize(uint16_t groupSize) -{ - auto key = CreateGroupSizeKey(); - - auto status = pdb->Put(writeoptions, GetSlice(key), - leveldb::Slice(reinterpret_cast(&groupSize), sizeof(groupSize))); - - if (!status.ok()) { - throw std::runtime_error("store sigma mint group size fail"); - } -} - -uint16_t SigmaDatabase::GetGroupSize() -{ - auto key = CreateGroupSizeKey(); - - std::string result; - auto status = pdb->Get(readoptions, GetSlice(key), &result); - - if (status.ok()) { - uint16_t groupSize(0); - - if (result.size() == sizeof(groupSize)) { - std::copy_n(result.data(), result.size(), reinterpret_cast(&groupSize)); - return groupSize; - } - - throw std::runtime_error("size of group size value is invalid"); - } - - if (!status.IsNotFound()) { - throw std::runtime_error("fail to read group size from database"); - } - return 0; -} - -uint16_t SigmaDatabase::InitGroupSize(uint16_t groupSize) -{ - if (groupSize > MAX_GROUP_SIZE) { - throw std::invalid_argument("group size exceed limit"); - } - - uint16_t currentGroupSize = GetGroupSize(); - - if (!groupSize) { - if (currentGroupSize) { - // if groupSize == 0 and have groupSize in db - // mean user need to use current groupSize - return currentGroupSize; - } else { - // groupSize in db isn't set - groupSize = MAX_GROUP_SIZE; - } - } else if (currentGroupSize) { - if (groupSize != currentGroupSize) { - // have groupSize in db but isn't equal to input - throw std::invalid_argument("group size input isn't equal to group size in database"); - } - - return currentGroupSize; - } - - RecordGroupSize(groupSize); - return groupSize; -} - -size_t SigmaDatabase::GetAnonimityGroup( - uint32_t propertyId, uint8_t denomination, uint32_t groupId, size_t count, - std::function insertF) -{ - auto firstKey = CreateMintKey(propertyId, denomination, groupId, 0); - - auto it = NewIterator(); - it->Seek(GetSlice(firstKey)); - - uint32_t mintPropId, mintGroupId; - uint16_t mintIdx; - uint8_t mintDenom; - - size_t i = 0; - for (; i < count && it->Valid(); i++, it->Next()) { - if (!ParseMintKey(it->key(), mintPropId, mintDenom, mintGroupId, mintIdx) || - mintPropId != propertyId || - mintDenom != denomination || - mintGroupId != groupId) { - break; - } - - if (mintIdx != i) { - throw std::runtime_error("GetAnonimityGroup() : coin index is out of order"); - } - - auto pub = ParseMint(it->value().ToString()); - - if (!pub.IsMember()) { - throw std::runtime_error("GetAnonimityGroup() : coin is invalid"); - } - insertF(pub); - } - - return i; -} - -uint32_t SigmaDatabase::GetLastGroupId( - uint32_t propertyId, - uint8_t denomination) -{ - auto key = CreateMintKey(propertyId, denomination, UINT32_MAX, UINT16_MAX); - uint32_t groupId = 0; - - auto it = NewIterator(); - SafeSeekToPreviousKey(it.get(), GetSlice(key)); - - if (it->Valid()) { - auto key = it->key(); - - uint32_t mintPropId, mintGroupId; - uint16_t mintIdx; - uint8_t mintDenom; - if (ParseMintKey(key, mintPropId, mintDenom, mintGroupId, mintIdx) - && propertyId == mintPropId - && denomination == mintDenom) { - groupId = mintGroupId; - } - } - - return groupId; -} - -size_t SigmaDatabase::GetMintCount( - uint32_t propertyId, uint8_t denomination, uint32_t groupId) -{ - auto key = CreateMintKey(propertyId, denomination, groupId, UINT16_MAX); - size_t count = 0; - - auto it = NewIterator(); - SafeSeekToPreviousKey(it.get(), GetSlice(key)); - - if (it->Valid()) { - auto key = it->key(); - - uint32_t mintPropId, mintGroupId; - uint16_t mintIdx; - uint8_t mintDenom; - if (ParseMintKey(key, mintPropId, mintDenom, mintGroupId, mintIdx) - && propertyId == mintPropId - && denomination == mintDenom - && groupId == mintGroupId) { - count = mintIdx + 1; - } - } - - return count; -} - -uint64_t SigmaDatabase::GetNextSequence() -{ - auto key = CreateSequenceKey(UINT64_MAX); - auto it = NewIterator(); - - uint64_t nextSequence = 0; - SafeSeekToPreviousKey(it.get(), GetSlice(key)); - - if (it->Valid() && it->key().size() > 0 && it->key().data()[0] == static_cast(KeyType::Sequence)) { - if (it->key().size() != SEQUENCE_KEY_SIZE) { - throw std::runtime_error("key size is invalid"); - } - auto lastKey = it->key(); - std::memcpy(&nextSequence, lastKey.data() + sizeof(KeyType), sizeof(nextSequence)); - elysium::swapByteOrder(nextSequence); - nextSequence++; - } - - return nextSequence; -} - -elysium::SigmaPublicKey SigmaDatabase::GetMint( - uint32_t propertyId, uint8_t denomination, uint32_t groupId, uint16_t index) -{ - auto key = CreateMintKey(propertyId, denomination, groupId, index); - - std::string val; - auto status = pdb->Get( - readoptions, - GetSlice(key), - &val - ); - - if (status.ok()) { - return ParseMint(val); - } - - throw std::runtime_error("not found sigma mint"); -} - -bool SigmaDatabase::HasSpendSerial( - uint32_t propertyId, uint8_t denomination, secp_primitives::Scalar const &serial, uint256 &spendTx) -{ - auto serialData = SerializeSpendSerial(serial); - auto keyData = CreateSpendSerialKey(propertyId, denomination, serialData); - std::string data; - auto status = pdb->Get(readoptions, GetSlice(keyData), &data); - - if (status.ok()) { - spendTx = uint256(std::vector(data.begin(), data.end())); - return true; - } - - if (status.IsNotFound()) { - return false; - } - - throw std::runtime_error("Error on serial checking"); -} - -void SigmaDatabase::AddEntry(const leveldb::Slice& key, const leveldb::Slice& value, int block) -{ - leveldb::WriteBatch batch; - - // Add entry writting to batch first. - batch.Put(key, value); - - // Prepare history object. - History history; - - if (IsMintKey(key)) { - history.op = OpCode::StoreMint; - } else if (IsSpendSerialKey(key)) { - history.op = OpCode::StoreSpendSerial; - } else { - throw std::invalid_argument("The specified entry is not supported"); - } - - history.block = block; - history.data.insert(history.data.end(), key.data(), key.data() + key.size()); - - // Add history writing to batch. - auto next = GetNextSequence(); - auto sequenceKey = CreateSequenceKey(next); - - CDataStream serialized(SER_DISK, CLIENT_VERSION); - serialized << history; - - batch.Put(GetSlice(sequenceKey), GetSlice(serialized.vch)); - - // Execute batch. - auto status = pdb->Write(syncoptions, &batch); - if (!status.ok()) { - throw std::runtime_error("Failed to write database: " + status.ToString()); - } -} - -std::unique_ptr SigmaDatabase::NewIterator() const -{ - return std::unique_ptr(CDBBase::NewIterator()); -} - -} // namespace elysium diff --git a/src/elysium/sigmadb.h b/src/elysium/sigmadb.h deleted file mode 100644 index 17f88719c3..0000000000 --- a/src/elysium/sigmadb.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef FIRO_ELYSIUM_SIGMADB_H -#define FIRO_ELYSIUM_SIGMADB_H - -#include "convert.h" -#include "persistence.h" -#include "property.h" -#include "sigmaprimitives.h" - -#include "../uint256.h" - -#include - -#include -#include - -#include - -#include -#include - -#include - -template -struct is_iterator -{ - static constexpr bool value = false; -}; - -template -struct is_iterator::iterator_category, void>::value>::type> -{ - static constexpr bool value = true; -}; - -namespace elysium { - -class SigmaDatabase : public CDBBase -{ -public: - /** - * Limit of sigma anonimity group, which is 2 ^ 14. - */ - static constexpr uint16_t MAX_GROUP_SIZE = 16384; - -public: - SigmaDatabase(const boost::filesystem::path& path, bool wipe, uint16_t groupSize = 0); - ~SigmaDatabase() override; - -public: - std::pair RecordMint( - PropertyId propertyId, - SigmaDenomination denomination, - const SigmaPublicKey& pubKey, - int height); - - void RecordSpendSerial( - uint32_t propertyId, - uint8_t denomination, - secp_primitives::Scalar const &serial, - int height, - uint256 const &spendTx); - - template< - class OutputIt, - typename std::enable_if::value, void>::type* = nullptr - > OutputIt GetAnonimityGroup(uint32_t propertyId, uint8_t denomination, uint32_t groupId, size_t count, OutputIt firstIt) - { - GetAnonimityGroup(propertyId, denomination, groupId, count, [&firstIt](elysium::SigmaPublicKey& pub) mutable { - *firstIt++ = std::move(pub); - }); - - return firstIt; - } - size_t GetAnonimityGroup(uint32_t propertyId, uint8_t denomination, uint32_t groupId, size_t count, - std::function); - - template - OutputIt GetAnonimityGroup(uint32_t propertyId, uint8_t denomination, uint32_t groupId, OutputIt firstIt) - { - auto mintCount = GetMintCount(propertyId, denomination, groupId); - if (mintCount) { - firstIt = GetAnonimityGroup(propertyId, denomination, groupId, mintCount, firstIt); - } - return firstIt; - } - - void DeleteAll(int startBlock); - - uint32_t GetLastGroupId(uint32_t propertyId, uint8_t denomination); - size_t GetMintCount(uint32_t propertyId, uint8_t denomination, uint32_t groupId); - uint64_t GetNextSequence(); - SigmaPublicKey GetMint(uint32_t propertyId, uint8_t denomination, uint32_t groupId, uint16_t index); - bool HasSpendSerial( - uint32_t propertyId, uint8_t denomination, secp_primitives::Scalar const &serial, uint256 &spendTx); - - uint16_t groupSize; - -public: - boost::signals2::signal MintAdded; - boost::signals2::signal MintRemoved; - boost::signals2::signal SpendAdded; - boost::signals2::signal SpendRemoved; - -protected: - void AddEntry(const leveldb::Slice& key, const leveldb::Slice& value, int block); - -private: - void RecordGroupSize(uint16_t groupSize); - - std::unique_ptr NewIterator() const; - -protected: - uint16_t InitGroupSize(uint16_t groupSize); - uint16_t GetGroupSize(); -}; - -extern SigmaDatabase *sigmaDb; - -} // namespace elysium - -#endif // FIRO_ELYSIUM_SIGMADB_H diff --git a/src/elysium/sigmaprimitives.cpp b/src/elysium/sigmaprimitives.cpp deleted file mode 100644 index 7d8cad33cc..0000000000 --- a/src/elysium/sigmaprimitives.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include "sigmaprimitives.h" - -#include "../hash.h" -#include "../sigma/sigma_primitives.h" - -#include - -#include -#include - -namespace elysium { - -uint160 GetSerialId(const secp_primitives::Scalar &serial) -{ - CDataStream ss(SER_GETHASH, 0); - ss << serial; - return Hash160(ss.begin(), ss.end()); -} - -const SigmaParams DefaultSigmaParams(secp_primitives::GroupElement().set_base_g(), 7, 4); - -// SigmaParams Implementation. - -SigmaParams::SigmaParams(const secp_primitives::GroupElement& g, unsigned m, unsigned n) : - g(g), - m(m), - n(n) -{ - if (!g.isMember() || g.isInfinity() || m == 0 || n == 0) { - throw std::invalid_argument("Invalid Sigma parameters"); - } - - std::array hash; - - g.sha256(hash.data()); - h.reserve(m * n); - - for (unsigned i = 0; i < m * n; i++) { - h.emplace_back(); - h[i].generate(hash.data()); - h[i].sha256(hash.data()); - } -} - -// SigmaPrivateKey Implementation. - -SigmaPrivateKey::SigmaPrivateKey() -{ -} - -SigmaPrivateKey::SigmaPrivateKey( - secp_primitives::Scalar const &serial, - secp_primitives::Scalar const &randomness) - : serial(serial), randomness(randomness) -{ -} - -bool SigmaPrivateKey::operator==(const SigmaPrivateKey& other) const -{ - return serial == other.serial && randomness == other.randomness; -} - -bool SigmaPrivateKey::operator!=(const SigmaPrivateKey& other) const -{ - return !(*this == other); -} - -bool SigmaPrivateKey::IsMember() const -{ - return serial.isMember() && randomness.isMember(); -} - -bool SigmaPrivateKey::IsValid() const -{ - return IsMember() && !serial.isZero() && !randomness.isZero(); -} - -void SigmaPrivateKey::Generate() -{ - do { - serial.randomize(); - randomness.randomize(); - } while (!IsValid()); -} - -// SigmaPublicKey Implementation. - -SigmaPublicKey::SigmaPublicKey() -{ -} - -SigmaPublicKey::SigmaPublicKey(const SigmaPrivateKey& key, const SigmaParams& params) -{ - Generate(key, params); -} - -bool SigmaPublicKey::operator==(const SigmaPublicKey& other) const -{ - return commitment == other.commitment; -} - -bool SigmaPublicKey::operator!=(const SigmaPublicKey& other) const -{ - return !(*this == other); -} - -bool SigmaPublicKey::IsMember() const -{ - return commitment.isMember(); -} - -bool SigmaPublicKey::IsValid() const -{ - return IsMember() && !commitment.isInfinity(); -} - -void SigmaPublicKey::Generate(const SigmaPrivateKey& key, const SigmaParams& params) -{ - if (!key.IsMember()) { - throw std::invalid_argument("The private key is not valid"); - } - - commitment = sigma::SigmaPrimitives::commit( - params.g, - key.serial, - params.h[0], - key.randomness - ); -} - -// SigmaProof Implementation. - -SigmaProof::SigmaProof(const SigmaParams& params) : - params(params), - proof(params.n, params.m) -{ -} - -bool SigmaProof::operator==(const SigmaProof& other) const -{ - return proof == other.proof; -} - -bool SigmaProof::operator!=(const SigmaProof& other) const -{ - return !(*this == other); -} - -} // namespace elysium diff --git a/src/elysium/sigmaprimitives.h b/src/elysium/sigmaprimitives.h deleted file mode 100644 index 0ad8dc6480..0000000000 --- a/src/elysium/sigmaprimitives.h +++ /dev/null @@ -1,266 +0,0 @@ -#ifndef FIRO_ELYSIUM_SIGMAPRIMITIVES_H -#define FIRO_ELYSIUM_SIGMAPRIMITIVES_H - -#include "../clientversion.h" -#include "../streams.h" -#include "../uint256.h" -#include "../utilstrencodings.h" - -#include "../sigma/sigmaplus_proof.h" -#include "../sigma/sigmaplus_prover.h" -#include "../sigma/sigmaplus_verifier.h" - -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace elysium { - -uint160 GetSerialId(const secp_primitives::Scalar &serial); - -class SigmaParams -{ -public: - secp_primitives::GroupElement g; - unsigned m, n; - std::vector h; - -public: - SigmaParams(const secp_primitives::GroupElement& g, unsigned m, unsigned n); -}; - -class SigmaPrivateKey -{ -public: - secp_primitives::Scalar serial; - secp_primitives::Scalar randomness; - -public: - SigmaPrivateKey(); - SigmaPrivateKey( - secp_primitives::Scalar const &serial, - secp_primitives::Scalar const &randomness); - -public: - bool operator==(const SigmaPrivateKey& other) const; - bool operator!=(const SigmaPrivateKey& other) const; - -public: - bool IsMember() const; - bool IsValid() const; - -public: - void Generate(); - -public: - ADD_SERIALIZE_METHODS; - - template - void SerializationOp(Stream& s, Operation ser_action) - { - READWRITE(serial); - READWRITE(randomness); - } -}; - -class SigmaPublicKey -{ -public: - secp_primitives::GroupElement commitment; - -public: - SigmaPublicKey(); - SigmaPublicKey(const SigmaPrivateKey& key, const SigmaParams& params); - -public: - bool operator==(const SigmaPublicKey& other) const; - bool operator!=(const SigmaPublicKey& other) const; - -public: - bool IsMember() const; - bool IsValid() const; - -public: - void Generate(const SigmaPrivateKey& key, const SigmaParams& params); - -public: - ADD_SERIALIZE_METHODS; - - template - void SerializationOp(Stream& s, Operation ser_action) - { - READWRITE(commitment); - } -}; - -class SigmaProof -{ -public: - const SigmaParams& params; - sigma::SigmaPlusProof proof; - -public: - explicit SigmaProof(const SigmaParams& params); - - template - SigmaProof(const SigmaParams& params, const SigmaPrivateKey& key, PublicKey first, PublicKey last, bool fPadding) : - SigmaProof(params) - { - Generate(key, first, last, fPadding); - } - -public: - bool operator==(const SigmaProof& other) const; - bool operator!=(const SigmaProof& other) const; - -public: - template - bool Verify(Serial serial, PublicKey first, PublicKey last, bool fPadding) const - { - // Create commitment set. - auto gs = (params.g * serial).inverse(); - std::vector commits; - - commits.reserve(std::distance(first, last)); - - for (auto it = first; it != last; it++) { - commits.emplace_back(it->commitment + gs); - } - - // Verify proof. - sigma::SigmaPlusVerifier verifier( - params.g, - params.h, - params.n, - params.m - ); - - return verifier.verify(commits, proof, fPadding); - } - -public: - template - void Generate(const SigmaPrivateKey& priv, PublicKey first, PublicKey last, bool fPadding) - { - if (!priv.IsMember()) { - throw std::invalid_argument("Private key is not valid"); - } - - // Create commitment set. - auto gs = (params.g * priv.serial).inverse(); - SigmaPublicKey pub(priv, params); - std::vector commits; - boost::optional index; - - commits.reserve(std::distance(first, last)); - - for (auto it = first; it != last; it++) { - auto& commit = it->commitment; - - if (commit == pub.commitment) { - index = std::distance(first, it); - } - - commits.emplace_back(commit + gs); - } - - if (!index) { - throw std::invalid_argument("No commitment for private key in the set"); - } - - // Generate proof. - sigma::SigmaPlusProver prover( - params.g, - params.h, - params.n, - params.m - ); - - prover.proof(commits, *index, priv.randomness, fPadding, proof); - } - -public: - ADD_SERIALIZE_METHODS; - - template - void SerializationOp(Stream& s, Operation ser_action) - { - READWRITE(proof); - } -}; - -typedef uint8_t SigmaDenomination; -typedef uint32_t SigmaMintGroup; -typedef uint16_t SigmaMintIndex; - -extern const SigmaParams DefaultSigmaParams; - -} // namespace elysium - -namespace std { - -using namespace elysium; - -// std::hash specialization. - -template<> -struct hash -{ - size_t operator()(const SigmaPrivateKey& k) const - { - size_t h = 0; - - h ^= hash()(k.serial); - h ^= hash()(k.randomness); - - return h; - } -}; - -template<> -struct hash -{ - size_t operator()(const SigmaPublicKey& k) const - { - return k.commitment.hash(); - } -}; - -// basic_ostream supports. - -template -basic_ostream& operator<<(basic_ostream& os, const SigmaPrivateKey& k) -{ - return os << "{serial: " << k.serial.GetHex() << ", randomness: " << k.randomness.GetHex() << '}'; -} - -template -basic_ostream& operator<<(basic_ostream& os, const SigmaPublicKey& k) -{ - return os << "{commitment: " << k.commitment.tostring() << '}'; -} - -template -basic_ostream& operator<<(basic_ostream& os, const SigmaProof& p) -{ - CDataStream buffer(SER_DISK, CLIENT_VERSION); - - buffer << p.proof; - - return os << HexStr(buffer.vch); -} - -} // namespace std - -#endif // FIRO_ELYSIUM_SIGMAPRIMITIVES_H diff --git a/src/elysium/sigmawallet.cpp b/src/elysium/sigmawallet.cpp deleted file mode 100644 index 82cbab20d7..0000000000 --- a/src/elysium/sigmawallet.cpp +++ /dev/null @@ -1,511 +0,0 @@ -// Copyright (c) 2019 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "sigmawallet.h" - -#include "walletmodels.h" - -#include "../uint256.h" - -#include "../crypto/hmac_sha256.h" -#include "../crypto/hmac_sha512.h" - -#include "../wallet/wallet.h" -#include "../wallet/walletdb.h" -#include "../wallet/walletexcept.h" - -#include - -#include -#include -#include -#include - -namespace elysium { - -SigmaWallet::MintPoolEntry::MintPoolEntry() -{ -} - -SigmaWallet::MintPoolEntry::MintPoolEntry(SigmaPublicKey const &key, CKeyID const &seedId, uint32_t index) - : key(key), seedId(seedId), index(index) -{ -} - -bool SigmaWallet::MintPoolEntry::operator==(MintPoolEntry const &another) const -{ - return key == another.key && - seedId == another.seedId && - index == another.index; -} - -bool SigmaWallet::MintPoolEntry::operator!=(MintPoolEntry const &another) const -{ - return !(*this == another); -} - -SigmaWallet::SigmaWallet(Database *database) - : database(database), walletFile(pwalletMain->strWalletFile) -{ -} - -void SigmaWallet::ReloadMasterKey() -{ - LOCK(pwalletMain->cs_wallet); - - if (pwalletMain->IsLocked()) { - throw std::runtime_error("Unable to reload master key because wallet is locked"); - } - - masterId = pwalletMain->GetHDChain().masterKeyID; - - if (masterId.IsNull()) { - throw std::runtime_error("Master id is null"); - } - - // Load mint pool from DB - LoadMintPool(); - - // Clean up any mint entries that aren't corresponded to current masterId - RemoveInvalidMintPoolEntries(); - - // Refill mint pool - FillMintPool(); -} - -uint32_t SigmaWallet::GenerateNewSeed(CKeyID &seedId, uint512 &seed) -{ - LOCK(pwalletMain->cs_wallet); - seedId = pwalletMain->GenerateNewKey(BIP44ChangeIndex()).GetID(); - return GenerateSeed(seedId, seed); -} - -uint32_t SigmaWallet::GenerateSeed(CKeyID const &seedId, uint512 &seed) -{ - LOCK(pwalletMain->cs_wallet); - CKey key; - if (!pwalletMain->GetKey(seedId, key)) { - throw std::runtime_error( - "Unable to retrieve generated key for mint seed. Is the wallet locked?"); - } - - // HMAC-SHA512(key, count) - // `count` is LE unsigned 32 bits integer - std::array result; - uint32_t change; - auto seedIndex = GetSeedIndex(seedId, change); - - if (change != BIP44ChangeIndex()) { - throw std::invalid_argument("BIP44 Change of seed id is invalid"); - } - - CHMAC_SHA512(key.begin(), key.size()). - Write(reinterpret_cast(&seedIndex), sizeof(seedIndex)). - Finalize(result.data()); - - seed = uint512(result); - - return seedIndex; -} - -namespace { - -uint32_t GetBIP44AddressIndex(std::string const &path, uint32_t &change) -{ - uint32_t index; - if (sscanf(path.data(), "m/44'/%*u'/%*u'/%u/%u", &change, &index) != 2) { - throw std::runtime_error("Fail to match BIP44 path"); - } - - return index; -} - -} - -uint32_t SigmaWallet::GetSeedIndex(CKeyID const &seedId, uint32_t &change) -{ - LOCK(pwalletMain->cs_wallet); - auto it = pwalletMain->mapKeyMetadata.find(seedId); - if (it == pwalletMain->mapKeyMetadata.end()) { - throw std::runtime_error("key not found"); - } - - // parse last index - try { - return GetBIP44AddressIndex(it->second.hdKeypath, change); - } catch (std::runtime_error const &e) { - LogPrintf("%s : fail to get child from, %s\n", __func__, e.what()); - throw; - } -} - -// Mint Updating -void SigmaWallet::WriteMint(SigmaMintId const &id, SigmaMint const &mint) -{ - if (!database->WriteMint(id, mint)) { - throw std::runtime_error("fail to write hdmint"); - } - - if (!database->WriteMintId(mint.serialId, id)) { - throw std::runtime_error("fail to record id"); - } - - RemoveFromMintPool(id.pubKey); - FillMintPool(); -} - -SigmaPrivateKey SigmaWallet::GeneratePrivateKey(CKeyID const &seedId) -{ - uint512 seed; - - GenerateSeed(seedId, seed); - return GeneratePrivateKey(seed); -} - -SigmaMintId SigmaWallet::GenerateMint(PropertyId property, SigmaDenomination denom, boost::optional seedId) -{ - LOCK(pwalletMain->cs_wallet); - - // If not specify seed to use that mean caller want to generate a new mint. - if (!seedId) { - if (pwalletMain->IsLocked()) { - throw WalletLocked(); - } - - if (mintPool.empty()) { - - // Try to recover mint pools - ReloadMasterKey(); - - if (mintPool.empty()) { - throw std::runtime_error("Mint pool is empty"); - } - } - - seedId = mintPool.begin()->seedId; - } - - // Generate private & public key. - auto priv = GeneratePrivateKey(seedId.get()); - SigmaPublicKey pub(priv, DefaultSigmaParams); - - // Create a new mint. - auto serialId = GetSerialId(priv.serial); - SigmaMint mint(property, denom, seedId.get(), serialId); - SigmaMintId id(mint.property, mint.denomination, pub); - - WriteMint(id, mint); - - return id; -} - -SigmaMint SigmaWallet::UpdateMint(SigmaMintId const &id, std::function const &modifier) -{ - auto m = GetMint(id); - modifier(m); - - if (!database->WriteMint(id, m)) { - throw std::runtime_error("fail to update mint"); - } - - return m; -} - -void SigmaWallet::ClearMintsChainState() -{ - CWalletDB db(walletFile); - std::vector> mints; - - db.TxnBegin(); - - ListMints(std::back_inserter(mints), &db); - - for (auto &m : mints) { - m.second.chainState = SigmaMintChainState(); - m.second.spendTx = uint256(); - - if (!database->WriteMint(m.first, m.second, &db)) { - throw std::runtime_error("Failed to write " + walletFile); - } - } - - db.TxnCommit(); -} - -bool SigmaWallet::TryRecoverMint( - SigmaMintId const &id, - SigmaMintChainState const &chainState, - uint256 const &spendTx) -{ - LOCK(pwalletMain->cs_wallet); - - MintPoolEntry entry; - if (!GetMintPoolEntry(id.pubKey, entry)) { - return false; - } - - // Regenerate the mint - auto const &seedId = entry.seedId; - - uint512 seed; - GenerateSeed(seedId, seed); - - auto privKey = GeneratePrivateKey(seed); - - auto serialId = GetSerialId(privKey.serial); - - // Create mint object - SigmaMint mint( - id.property, - id.denomination, - seedId, - serialId); - mint.chainState = chainState; - mint.spendTx = spendTx; - - WriteMint(id, mint); - - return true; -} - -bool SigmaWallet::TryRecoverMint( - SigmaMintId const &id, - SigmaMintChainState const &chainState) -{ - return TryRecoverMint(id, chainState, uint256()); -} - -void SigmaWallet::UpdateMintCreatedTx(const SigmaMintId& id, const uint256& tx) -{ - UpdateMint(id, [&](SigmaMint& m) { - m.createdTx = tx; - }); -} - -void SigmaWallet::UpdateMintChainstate(SigmaMintId const &id, SigmaMintChainState const &state) -{ - UpdateMint(id, [&](SigmaMint &m) { - m.chainState = state; - }); -} - -void SigmaWallet::UpdateMintSpendTx(SigmaMintId const &id, uint256 const &tx) -{ - UpdateMint(id, [&](SigmaMint &m) { - m.spendTx = tx; - }); -} - -// Mint querying -bool SigmaWallet::HasMint(SigmaMintId const &id) const -{ - return database->HasMint(id); -} - -bool SigmaWallet::HasMint(secp_primitives::Scalar const &serial) const -{ - auto id = GetSerialId(serial); - return database->HasMintId(id); -} - -SigmaMint SigmaWallet::GetMint(SigmaMintId const &id) const -{ - SigmaMint m; - if (!database->ReadMint(id, m)) { - throw std::runtime_error("fail to read hdmint"); - } - - return m; -} - -SigmaMint SigmaWallet::GetMint(secp_primitives::Scalar const &serial) const -{ - return GetMint(GetMintId(serial)); -} - -SigmaMintId SigmaWallet::GetMintId(secp_primitives::Scalar const &serial) const -{ - SigmaMintId id; - auto serialHash = GetSerialId(serial); - if (!database->ReadMintId(serialHash, id)) { - throw std::runtime_error("fail to read id"); - } - - return id; -} - -// MintPool state -void SigmaWallet::RemoveInvalidMintPoolEntries() // Remove MintPool entry that isn't belong to current masterId. -{ - LOCK(pwalletMain->cs_wallet); - - bool updated = false; - for (auto it = mintPool.begin(); it != mintPool.end(); it++) { - - auto metaIt = pwalletMain->mapKeyMetadata.find(it->seedId); - if (metaIt == pwalletMain->mapKeyMetadata.end() || - metaIt->second.hdMasterKeyID != masterId) { - - updated = true; - mintPool.erase(it); - } - } - - if (updated) { - SaveMintPool(); - } -} - -void SigmaWallet::DeleteUnconfirmedMint(SigmaMintId const &id) -{ - SigmaMint mint; - if (!database->ReadMint(id, mint)) { - throw std::runtime_error("no mint data in wallet"); - } - - if (mint.IsOnChain()) { - throw std::invalid_argument("try to delete onchain mint"); - } - - SigmaPublicKey pubKey(GeneratePrivateKey(mint.seedId), DefaultSigmaParams); - - uint32_t change; - auto index = GetSeedIndex(mint.seedId, change); - - if (change != BIP44ChangeIndex()) { - throw std::invalid_argument("Try to delete invalid seed id mint"); - } - - mintPool.insert(MintPoolEntry(pubKey, mint.seedId, index)); - SaveMintPool(); - - if (!database->EraseMint(id)) { - throw std::runtime_error("fail to erase mint from wallet"); - } -} - -bool SigmaWallet::IsMintInPool(SigmaPublicKey const &pubKey) -{ - LOCK(pwalletMain->cs_wallet); - return mintPool.get<1>().count(pubKey); -} - -bool SigmaWallet::GetMintPoolEntry(SigmaPublicKey const &pubKey, MintPoolEntry &entry) -{ - LOCK(pwalletMain->cs_wallet); - - auto &publicKeyIndex = mintPool.get<1>(); - auto it = publicKeyIndex.find(pubKey); - - if (it == publicKeyIndex.end()) { - return false; - } - - entry = *it; - return true; -} - -// Generate coins to mint pool until amount of coins in mint pool touch the expected amount. -size_t SigmaWallet::FillMintPool() -{ - LOCK(pwalletMain->cs_wallet); - - size_t generatedCoins = 0; - while (mintPool.size() < MINTPOOL_CAPACITY) { - - CKeyID seedId; - uint512 seed; - - auto index = GenerateNewSeed(seedId, seed); - auto privKey = GeneratePrivateKey(seed); - - SigmaPublicKey pubKey(privKey, DefaultSigmaParams); - mintPool.insert(MintPoolEntry(pubKey, seedId, index)); - - generatedCoins++; - } - - if (generatedCoins) { - SaveMintPool(); - } - - return generatedCoins; -} - -void SigmaWallet::LoadMintPool() -{ - LOCK(pwalletMain->cs_wallet); - - mintPool.clear(); - - std::vector mintPoolData; - if (database->ReadMintPool(mintPoolData)) { - for (auto &entry : mintPoolData) { - mintPool.insert(std::move(entry)); - } - } - - LogPrintf("%s : load mint pool size %d\n", __func__, mintPool.size()); -} - -void SigmaWallet::SaveMintPool() -{ - LOCK(pwalletMain->cs_wallet); - - std::vector mintPoolData; - for (auto const &entry : mintPool) { - mintPoolData.push_back(entry); - } - - if (!database->WriteMintPool(mintPoolData)) { - throw std::runtime_error("fail to save mint pool to DB"); - } -} - -bool SigmaWallet::RemoveFromMintPool(SigmaPublicKey const &publicKey) -{ - LOCK(pwalletMain->cs_wallet); - - auto &publicKeyIndex = mintPool.get<1>(); - auto it = publicKeyIndex.find(publicKey); - - if (it != publicKeyIndex.end()) { - - publicKeyIndex.erase(it); - SaveMintPool(); - return true; - } - - // publicKey is not in the pool - return false; -} - -SigmaWallet::Database::Connection::Connection(CWalletDB *db) -{ - if (db) { - this->db.db = db; - local = false; - } else { - new (this->db.local) CWalletDB(pwalletMain->strWalletFile); - local = true; - } -} - -SigmaWallet::Database::Connection::~Connection() -{ - if (local) { - reinterpret_cast(db.local)->~CWalletDB(); - } -} - -CWalletDB* SigmaWallet::Database::Connection::operator->() noexcept -{ - return local ? reinterpret_cast(db.local) : db.db; -} - -SigmaWallet::Database::Database() -{ -} - -} // namespace elysium diff --git a/src/elysium/sigmawallet.h b/src/elysium/sigmawallet.h deleted file mode 100644 index 877cb881a2..0000000000 --- a/src/elysium/sigmawallet.h +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2019 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef FIRO_ELYSIUM_SIGMAWALLET_H -#define FIRO_ELYSIUM_SIGMAWALLET_H - -#include "property.h" -#include "sigmaprimitives.h" -#include "walletmodels.h" - -#include -#include -#include -#include -#include - -#include "../crypto/hmac_sha256.h" -#include "../crypto/hmac_sha512.h" -#include "../uint256.h" -#include "../wallet/wallet.h" -#include "../wallet/walletdb.h" -#include "../wallet/walletexcept.h" - -#include -#include - -namespace elysium { - -class SigmaWallet -{ -public: - struct MintPoolEntry { - SigmaPublicKey key; - CKeyID seedId; - uint32_t index; - - MintPoolEntry(); - MintPoolEntry(SigmaPublicKey const &key, CKeyID const &seedId, uint32_t index); - - bool operator==(MintPoolEntry const &another) const; - bool operator!=(MintPoolEntry const &another) const; - - ADD_SERIALIZE_METHODS; - - template - void SerializationOp(Stream& s, Operation ser_action) - { - READWRITE(key); - READWRITE(seedId); - READWRITE(index); - } - }; - - typedef boost::multi_index_container< - MintPoolEntry, - boost::multi_index::indexed_by< - // Sequence - boost::multi_index::ordered_unique< - boost::multi_index::member - >, - // Public Key index - boost::multi_index::hashed_unique< - boost::multi_index::member, - std::hash - > - > - > MintPool; - -protected: - class Database { - public: - Database(); - - public: - virtual bool WriteMint(SigmaMintId const &id, SigmaMint const &mint, CWalletDB *db = nullptr) = 0; - virtual bool ReadMint(SigmaMintId const &id, SigmaMint &mint, CWalletDB *db = nullptr) const = 0; - virtual bool EraseMint(SigmaMintId const &id, CWalletDB *db = nullptr) = 0; - virtual bool HasMint(SigmaMintId const &id, CWalletDB *db = nullptr) const = 0; - - virtual bool WriteMintId(uint160 const &hash, SigmaMintId const &mintId, CWalletDB *db = nullptr) = 0; - virtual bool ReadMintId(uint160 const &hash, SigmaMintId &mintId, CWalletDB *db = nullptr) const = 0; - virtual bool EraseMintId(uint160 const &hash, CWalletDB *db = nullptr) = 0; - virtual bool HasMintId(uint160 const &hash, CWalletDB *db = nullptr) const = 0; - - virtual bool WriteMintPool(std::vector const &mints, CWalletDB *db = nullptr) = 0; - virtual bool ReadMintPool(std::vector &mints, CWalletDB *db = nullptr) = 0; - - virtual void ListMints(std::function const&, CWalletDB *db = nullptr) = 0; - - protected: - // Helper - class Connection - { - public: - Connection(CWalletDB *db); - ~Connection(); - - public: - CWalletDB* operator->() noexcept; - - private: - bool local; - union { - CWalletDB *db; - unsigned char local[sizeof(CWalletDB)]; - } db; - }; - }; - -public: - std::unique_ptr database; - std::string walletFile; - MintPool mintPool; - uint160 masterId; - - static constexpr unsigned MINTPOOL_CAPACITY = 20; - -public: - SigmaWallet(Database *database); - -public: - void ReloadMasterKey(); - - // Generator -protected: - uint32_t GenerateNewSeed(CKeyID &seedId, uint512 &seed); - uint32_t GenerateSeed(CKeyID const &seedId, uint512 &seed); - uint32_t GetSeedIndex(CKeyID const &seedId, uint32_t &change); - -protected: - virtual uint32_t BIP44ChangeIndex() const = 0; - virtual SigmaPrivateKey GeneratePrivateKey(uint512 const &seed) = 0; - - // Mint updating -public: - SigmaPrivateKey GeneratePrivateKey(CKeyID const &seedId); - SigmaMintId GenerateMint(PropertyId property, SigmaDenomination denom, boost::optional seedId = boost::none); - - void ClearMintsChainState(); - - bool TryRecoverMint(SigmaMintId const &id, SigmaMintChainState const &chainState); - bool TryRecoverMint( - SigmaMintId const &id, SigmaMintChainState const &chainState, uint256 const &spendTx); - -private: - SigmaMint UpdateMint(SigmaMintId const &id, std::function const &modifier); - - void WriteMint(SigmaMintId const &id, SigmaMint const &mint); - -public: - void UpdateMintCreatedTx(const SigmaMintId& id, const uint256& tx); - void UpdateMintChainstate(SigmaMintId const &id, SigmaMintChainState const &state); - void UpdateMintSpendTx(SigmaMintId const &id, uint256 const &tx); - - // Mint querying -public: - - bool HasMint(SigmaMintId const &id) const; - bool HasMint(secp_primitives::Scalar const &serial) const; - - SigmaMint GetMint(SigmaMintId const &id) const; - SigmaMint GetMint(secp_primitives::Scalar const &serial) const; - SigmaMintId GetMintId(secp_primitives::Scalar const &serial) const; - - template - Output ListMints(Output output, CWalletDB *db = nullptr) - { - database->ListMints([&](const SigmaMintId& id, const SigmaMint &m) { - *output++ = std::make_pair(id, m); - }, db); - - return output; - } - - // MintPool state -public: - void DeleteUnconfirmedMint(SigmaMintId const &id); - bool IsMintInPool(SigmaPublicKey const &pubKey); - - bool GetMintPoolEntry(SigmaPublicKey const &pubKey, MintPoolEntry &entry); - -protected: - void RemoveInvalidMintPoolEntries(); // Remove MintPool entries that aren't belong to current masterId. - size_t FillMintPool(); - - void LoadMintPool(); - void SaveMintPool(); - - bool RemoveFromMintPool(SigmaPublicKey const &publicKey); -}; - -} // namespace elysium - -#endif // FIRO_ELYSIUM_SIGMAWALLET_H diff --git a/src/elysium/sigmawalletv0.cpp b/src/elysium/sigmawalletv0.cpp deleted file mode 100644 index 44f26aab80..0000000000 --- a/src/elysium/sigmawalletv0.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "sigmawalletv0.h" - -#include "../wallet/wallet.h" - -namespace elysium { - -SigmaWalletV0::SigmaWalletV0() : SigmaWallet(new Database()) -{ -} - -uint32_t SigmaWalletV0::BIP44ChangeIndex() const -{ - return BIP44_ELYSIUM_MINT_INDEX_V0; -} - -SigmaPrivateKey SigmaWalletV0::GeneratePrivateKey(uint512 const &seed) -{ - SigmaPrivateKey priv; - - // first 32 bytes as seed - uint256 serialSeed; - std::copy(seed.begin(), seed.begin() + 32, serialSeed.begin()); - priv.serial.memberFromSeed(serialSeed.begin()); - - // last 32 bytes as seed - uint256 randomnessSeed; - std::copy(seed.begin() + 32, seed.end(), randomnessSeed.begin()); - priv.randomness.memberFromSeed(randomnessSeed.begin()); - - return priv; -} - -SigmaWalletV0::Database::Database() -{ -} - -bool SigmaWalletV0::Database::WriteMint(SigmaMintId const &id, SigmaMint const &mint, CWalletDB *db) -{ - auto local = Connection(db); - return local->WriteElysiumMintV0(id, mint); -} - -bool SigmaWalletV0::Database::ReadMint(SigmaMintId const &id, SigmaMint &mint, CWalletDB *db) const -{ - auto local = Connection(db); - return local->ReadElysiumMintV0(id, mint); -} - -bool SigmaWalletV0::Database::EraseMint(SigmaMintId const &id, CWalletDB *db) -{ - auto local = Connection(db); - return local->EraseElysiumMintV0(id); -} - -bool SigmaWalletV0::Database::HasMint(SigmaMintId const &id, CWalletDB *db) const -{ - auto local = Connection(db); - return local->HasElysiumMintV0(id); -} - -bool SigmaWalletV0::Database::WriteMintId(uint160 const &hash, SigmaMintId const &mintId, CWalletDB *db) -{ - auto local = Connection(db); - return local->WriteElysiumMintIdV0(hash, mintId); -} - -bool SigmaWalletV0::Database::ReadMintId(uint160 const &hash, SigmaMintId &mintId, CWalletDB *db) const -{ - auto local = Connection(db); - return local->ReadElysiumMintIdV0(hash, mintId); -} - -bool SigmaWalletV0::Database::EraseMintId(uint160 const &hash, CWalletDB *db) -{ - auto local = Connection(db); - return local->EraseElysiumMintIdV0(hash); -} - -bool SigmaWalletV0::Database::HasMintId(uint160 const &hash, CWalletDB *db) const -{ - auto local = Connection(db); - return local->HasElysiumMintIdV0(hash); -} - -bool SigmaWalletV0::Database::WriteMintPool(std::vector const &mints, CWalletDB *db) -{ - auto local = Connection(db); - return local->WriteElysiumMintPoolV0(mints); -} - -bool SigmaWalletV0::Database::ReadMintPool(std::vector &mints, CWalletDB *db) -{ - auto local = Connection(db); - return local->ReadElysiumMintPoolV0(mints); -} - -void SigmaWalletV0::Database::ListMints(std::function const &inserter, CWalletDB *db) -{ - auto local = Connection(db); - local->ListElysiumMintsV0(inserter); -} - -} \ No newline at end of file diff --git a/src/elysium/sigmawalletv0.h b/src/elysium/sigmawalletv0.h deleted file mode 100644 index f7fdb523f4..0000000000 --- a/src/elysium/sigmawalletv0.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef FIRO_ELYSIUM_SIGMAWALLETV0_H -#define FIRO_ELYSIUM_SIGMAWALLETV0_H - -#include "sigmawallet.h" - -namespace elysium { - -class SigmaWalletV0 : public SigmaWallet -{ -public: - SigmaWalletV0(); - -protected: - uint32_t BIP44ChangeIndex() const; - SigmaPrivateKey GeneratePrivateKey(uint512 const &seed); - - class Database : public SigmaWallet::Database { - public: - Database(); - - public: - bool WriteMint(SigmaMintId const &id, SigmaMint const &mint, CWalletDB *db = nullptr); - bool ReadMint(SigmaMintId const &id, SigmaMint &mint, CWalletDB *db = nullptr) const; - bool EraseMint(SigmaMintId const &id, CWalletDB *db = nullptr); - bool HasMint(SigmaMintId const &id, CWalletDB *db = nullptr) const; - - bool WriteMintId(uint160 const &hash, SigmaMintId const &mintId, CWalletDB *db = nullptr); - bool ReadMintId(uint160 const &hash, SigmaMintId &mintId, CWalletDB *db = nullptr) const; - bool EraseMintId(uint160 const &hash, CWalletDB *db = nullptr); - bool HasMintId(uint160 const &hash, CWalletDB *db = nullptr) const; - - bool WriteMintPool(std::vector const &mints, CWalletDB *db = nullptr); - bool ReadMintPool(std::vector &mints, CWalletDB *db = nullptr); - - void ListMints(std::function const&, CWalletDB *db = nullptr); - }; - -public: - using SigmaWallet::GeneratePrivateKey; -}; - -} - -#endif // FIRO_ELYSIUM_SIGMAWALLETV0_H \ No newline at end of file diff --git a/src/elysium/sigmawalletv1.cpp b/src/elysium/sigmawalletv1.cpp deleted file mode 100644 index 81c56f27d6..0000000000 --- a/src/elysium/sigmawalletv1.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "sigmawalletv1.h" - -#include "../wallet/wallet.h" - -namespace elysium { - -SigmaWalletV1::SigmaWalletV1() - : SigmaWallet(new SigmaWalletV1::Database()), - context(ECDSAContext::CreateSignContext()) -{ -} - -bool SigmaWalletV1::GetPublicKey(ECDSAPrivateKey const &priv, secp256k1_pubkey &out) -{ - return 1 == secp256k1_ec_pubkey_create( - context.Get(), - &out, - priv.data()); -} - -secp_primitives::Scalar SigmaWalletV1::GenerateSerial(secp256k1_pubkey const &pubkey) -{ - std::array compressedPub; - - size_t outSize = compressedPub.size(); - secp256k1_ec_pubkey_serialize( - context.Get(), - compressedPub.data(), - &outSize, - &pubkey, - SECP256K1_EC_COMPRESSED); - - if (outSize != 33) { - throw std::runtime_error("Compressed public key size is invalid."); - } - - std::array hash; - CSHA256().Write(compressedPub.data(), compressedPub.size()).Finalize(hash.data()); - - secp_primitives::Scalar serial; - serial.memberFromSeed(hash.data()); - - return serial; -} - -uint32_t SigmaWalletV1::BIP44ChangeIndex() const -{ - return BIP44_ELYSIUM_MINT_INDEX_V1; -} - -SigmaPrivateKey SigmaWalletV1::GeneratePrivateKey(uint512 const &seed) -{ - ECDSAPrivateKey signatureKey; - return GeneratePrivateKey(seed, signatureKey); -} - -SigmaPrivateKey SigmaWalletV1::GeneratePrivateKey( - uint512 const &seed, ECDSAPrivateKey &signatureKey) -{ - // last 32 bytes as seed of randomness - std::array randomnessSeed; - std::copy(seed.begin() + 32, seed.end(), randomnessSeed.begin()); - secp_primitives::Scalar randomness; - randomness.memberFromSeed(randomnessSeed.data()); - - // first 32 bytes as seed of ecdsa key and serial - std::copy(seed.begin(), seed.begin() + 32, signatureKey.begin()); - - SigmaPrivateKey key; - - // hash until get valid private key - do { - secp256k1_pubkey pubkey; - do { - CSHA256().Write(signatureKey.data(), signatureKey.size()).Finalize(signatureKey.data()); - } while (!GetPublicKey(signatureKey, pubkey)); - - auto serial = GenerateSerial(pubkey); - - key = SigmaPrivateKey(serial, randomness); - } while (!key.IsValid()); - - return key; -} - -CKey SigmaWalletV1::GetSignatureKey(SigmaMintId const &id) -{ - auto mint = GetMint(id); - uint512 seed; - ECDSAPrivateKey signatureKey; - - GenerateSeed(mint.seedId, seed); - GeneratePrivateKey(seed, signatureKey); - - CKey key; - key.Set(signatureKey.begin(), signatureKey.end(), true); - - return key; -} - - -// DB -SigmaWalletV1::Database::Database() -{ -} - -bool SigmaWalletV1::Database::WriteMint(SigmaMintId const &id, SigmaMint const &mint, CWalletDB *db) -{ - auto local = Connection(db); - return local->WriteElysiumMintV1(id, mint); -} - -bool SigmaWalletV1::Database::ReadMint(SigmaMintId const &id, SigmaMint &mint, CWalletDB *db) const -{ - auto local = Connection(db); - return local->ReadElysiumMintV1(id, mint); -} - -bool SigmaWalletV1::Database::EraseMint(SigmaMintId const &id, CWalletDB *db) -{ - auto local = Connection(db); - return local->EraseElysiumMintV1(id); -} - -bool SigmaWalletV1::Database::HasMint(SigmaMintId const &id, CWalletDB *db) const -{ - auto local = Connection(db); - return local->HasElysiumMintV1(id); -} - -bool SigmaWalletV1::Database::WriteMintId(uint160 const &hash, SigmaMintId const &mintId, CWalletDB *db) -{ - auto local = Connection(db); - return local->WriteElysiumMintIdV1(hash, mintId); -} - -bool SigmaWalletV1::Database::ReadMintId(uint160 const &hash, SigmaMintId &mintId, CWalletDB *db) const -{ - auto local = Connection(db); - return local->ReadElysiumMintIdV1(hash, mintId); -} - -bool SigmaWalletV1::Database::EraseMintId(uint160 const &hash, CWalletDB *db) -{ - auto local = Connection(db); - return local->EraseElysiumMintIdV1(hash); -} - -bool SigmaWalletV1::Database::HasMintId(uint160 const &hash, CWalletDB *db) const -{ - auto local = Connection(db); - return local->HasElysiumMintIdV1(hash); -} - -bool SigmaWalletV1::Database::WriteMintPool(std::vector const &mints, CWalletDB *db) -{ - auto local = Connection(db); - return local->WriteElysiumMintPoolV1(mints); -} - -bool SigmaWalletV1::Database::ReadMintPool(std::vector &mints, CWalletDB *db) -{ - auto local = Connection(db); - return local->ReadElysiumMintPoolV1(mints); -} - -void SigmaWalletV1::Database::ListMints( - std::function const &inserter, CWalletDB *db) -{ - auto local = Connection(db); - local->ListElysiumMintsV1(inserter); -} - -} \ No newline at end of file diff --git a/src/elysium/sigmawalletv1.h b/src/elysium/sigmawalletv1.h deleted file mode 100644 index e9ddae59e3..0000000000 --- a/src/elysium/sigmawalletv1.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef FIRO_ELYSIUM_SIGMAWALLETV1_H -#define FIRO_ELYSIUM_SIGMAWALLETV1_H - -#include "ecdsa_context.h" -#include "sigmawallet.h" - -namespace elysium { - - -class SigmaWalletV1 : public SigmaWallet -{ -protected: - typedef std::array ECDSAPrivateKey; - -public: - SigmaWalletV1(); - -protected: - bool GetPublicKey(ECDSAPrivateKey const &priv, secp256k1_pubkey &out); - secp_primitives::Scalar GenerateSerial(secp256k1_pubkey const &pubkey); - -protected: - uint32_t BIP44ChangeIndex() const; - SigmaPrivateKey GeneratePrivateKey(uint512 const &seed); - SigmaPrivateKey GeneratePrivateKey(uint512 const &seed, ECDSAPrivateKey &signatureKey); - - class Database : public SigmaWallet::Database - { - public: - Database(); - - public: - bool WriteMint(SigmaMintId const &id, SigmaMint const &mint, CWalletDB *db = nullptr); - bool ReadMint(SigmaMintId const &id, SigmaMint &mint, CWalletDB *db = nullptr) const; - bool EraseMint(SigmaMintId const &id, CWalletDB *db = nullptr); - bool HasMint(SigmaMintId const &id, CWalletDB *db = nullptr) const; - - bool WriteMintId(uint160 const &hash, SigmaMintId const &mintId, CWalletDB *db = nullptr); - bool ReadMintId(uint160 const &hash, SigmaMintId &mintId, CWalletDB *db = nullptr) const; - bool EraseMintId(uint160 const &hash, CWalletDB *db = nullptr); - bool HasMintId(uint160 const &hash, CWalletDB *db = nullptr) const; - - bool WriteMintPool(std::vector const &mints, CWalletDB *db = nullptr); - bool ReadMintPool(std::vector &mints, CWalletDB *db = nullptr); - - void ListMints(std::function const&, CWalletDB *db = nullptr); - }; - -public: - using SigmaWallet::GeneratePrivateKey; - -public: - CKey GetSignatureKey(SigmaMintId const &id); - -private: - ECDSAContext context; -}; - -} - -#endif // FIRO_ELYSIUM_SIGMAWALLETV1_H \ No newline at end of file diff --git a/src/elysium/signaturebuilder.cpp b/src/elysium/signaturebuilder.cpp deleted file mode 100644 index d9c5ecb168..0000000000 --- a/src/elysium/signaturebuilder.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "sigmaprimitives.h" -#include "signaturebuilder.h" - -#include "../base58.h" - -namespace elysium { - -SigmaV1SignatureBuilder::SigmaV1SignatureBuilder( - CBitcoinAddress const &receiver, - int64_t referenceAmount, - SigmaProof const &proof) -{ - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - - // serialize payload - uint160 keyId; - AddressType type; - if (!receiver.GetIndexKey(keyId, type)) { - throw std::invalid_argument("Fail to get address key id."); - } - - hasher.write(reinterpret_cast(keyId.begin()), keyId.size()); - - // `LE` reference amount - hasher.write(reinterpret_cast(&referenceAmount), sizeof(referenceAmount)); - - // serial and proof - CDataStream serialized(SER_NETWORK, PROTOCOL_VERSION); - serialized << proof; - std::vector serializedData; - serializedData.insert(serializedData.end(), serialized.begin(), serialized.end()); - - hasher.write(serializedData.data(), serializedData.size()); - - hash = hasher.GetHash(); -} - -ECDSASignature SigmaV1SignatureBuilder::Sign(CKey &key) const -{ - std::vector sig; - if (!key.Sign(hash, sig)) { - throw std::runtime_error("Fail to sign payload"); - } - - return ECDSASignature::ParseDER(ECDSAContext::CreateSignContext(), sig.data(), sig.size()); -} - -bool SigmaV1SignatureBuilder::Verify(CPubKey const &pubKey, ECDSASignature const &signature) const -{ - return pubKey.Verify(hash, signature.GetDER(ECDSAContext::CreateVerifyContext())); -} - -} \ No newline at end of file diff --git a/src/elysium/signaturebuilder.h b/src/elysium/signaturebuilder.h deleted file mode 100644 index 884c3155d2..0000000000 --- a/src/elysium/signaturebuilder.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 The Firo Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef FIRO_ELYSIUM_SIGNATUREBUILDER_H -#define FIRO_ELYSIUM_SIGNATUREBUILDER_H - -#include "ecdsa_signature.h" - -#include "../base58.h" -#include "../key.h" - -namespace elysium { - -class SignatureBuilder -{ -public: - virtual ECDSASignature Sign(CKey &key) const = 0; - virtual bool Verify(CPubKey const &pubKey, ECDSASignature const &signature) const = 0; -}; - -class SigmaV1SignatureBuilder : SignatureBuilder -{ -public: - SigmaV1SignatureBuilder( - CBitcoinAddress const &receiver, - int64_t referenceAmount, - SigmaProof const &proof); - -public: - ECDSASignature Sign(CKey &key) const; - bool Verify(CPubKey const &pubKey, ECDSASignature const &signature) const; - -protected: - uint256 hash; -}; - -} - -#endif // FIRO_ELYSIUM_SIGNATUREBUILDER_H \ No newline at end of file diff --git a/src/elysium/sp.cpp b/src/elysium/sp.cpp deleted file mode 100644 index 18bcc40b9a..0000000000 --- a/src/elysium/sp.cpp +++ /dev/null @@ -1,1022 +0,0 @@ -#include "sp.h" - -#include "log.h" -#include "elysium.h" -#include "packetencoder.h" -#include "uint256_extensions.h" -#include "utilsbitcoin.h" - -#include "../arith_uint256.h" -#include "../base58.h" -#include "../clientversion.h" -#include "../validation.h" -#include "../serialize.h" -#include "../streams.h" -#include "../tinyformat.h" -#include "../uint256.h" -#include "../utiltime.h" - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -using namespace elysium; - -CMPSPInfo::Entry::Entry() - : prop_type(0), prev_prop_id(0), num_tokens(0), property_desired(0), - deadline(0), early_bird(0), percentage(0), - close_early(false), max_tokens(false), missedTokens(0), timeclosed(0), - fixed(false), manual(false), sigmaStatus(SigmaStatus::SoftDisabled) {} - -bool CMPSPInfo::Entry::isDivisible() const -{ - switch (prop_type) { - case ELYSIUM_PROPERTY_TYPE_DIVISIBLE: - case ELYSIUM_PROPERTY_TYPE_DIVISIBLE_REPLACING: - case ELYSIUM_PROPERTY_TYPE_DIVISIBLE_APPENDING: - return true; - } - return false; -} - -void CMPSPInfo::Entry::print() const -{ - PrintToLog("%s:%s(Fixed=%s,Divisible=%s):%d:%s/%s, %s %s\n", - issuer, - name, - fixed ? "Yes" : "No", - isDivisible() ? "Yes" : "No", - num_tokens, - category, subcategory, url, data); -} - -CMPSPInfo::CMPSPInfo(const boost::filesystem::path& path, bool fWipe) -{ - leveldb::Status status = Open(path, fWipe); - PrintToLog("Loading smart property database: %s\n", status.ToString()); - - // special cases for constant SPs ELYSIUM and TELYSIUM - implied_elysium.issuer = GetSystemAddress().ToString(); - implied_elysium.prop_type = ELYSIUM_PROPERTY_TYPE_DIVISIBLE; - implied_elysium.num_tokens = 700000; - implied_elysium.category = "N/A"; - implied_elysium.subcategory = "N/A"; - implied_elysium.name = "Exodus"; - implied_elysium.url = "https://www.firo.org"; - implied_elysium.data = "Exodus serve as the binding between Firo, smart properties and contracts created on the Exodus Layer."; - implied_telysium.issuer = GetSystemAddress().ToString(); - implied_telysium.prop_type = ELYSIUM_PROPERTY_TYPE_DIVISIBLE; - implied_telysium.num_tokens = 700000; - implied_telysium.category = "N/A"; - implied_telysium.subcategory = "N/A"; - implied_telysium.name = "Test Exodus"; - implied_telysium.url = "https://www.firo.org"; - implied_telysium.data = "Test Exodus serve as the binding between Firo, smart properties and contracts created on the Exodus Layer."; - - init(); -} - -CMPSPInfo::~CMPSPInfo() -{ - if (elysium_debug_persistence) PrintToLog("CMPSPInfo closed\n"); -} - -void CMPSPInfo::Clear() -{ - // wipe database via parent class - CDBBase::Clear(); - // reset "next property identifiers" - init(); -} - -void CMPSPInfo::init(uint32_t nextSPID, uint32_t nextTestSPID) -{ - next_spid = nextSPID; - next_test_spid = nextTestSPID; -} - -uint32_t CMPSPInfo::peekNextSPID(uint8_t ecosystem) const -{ - uint32_t nextId = 0; - - switch (ecosystem) { - case ELYSIUM_PROPERTY_ELYSIUM: // Main ecosystem, ELYSIUM: 1, TELYSIUM: 2, First available SP = 3 - nextId = next_spid; - break; - case ELYSIUM_PROPERTY_TELYSIUM: // Test ecosystem, same as above with high bit set - nextId = next_test_spid; - break; - default: // Non-standard ecosystem, ID's start at 0 - nextId = 0; - } - - return nextId; -} - -bool CMPSPInfo::updateSP(uint32_t propertyId, const Entry& info) -{ - // cannot update implied SP - if (ELYSIUM_PROPERTY_ELYSIUM == propertyId || ELYSIUM_PROPERTY_TELYSIUM == propertyId) { - return false; - } - - // DB key for property entry - CDataStream ssSpKey(SER_DISK, CLIENT_VERSION); - ssSpKey << std::make_pair('s', propertyId); - leveldb::Slice slSpKey(&ssSpKey[0], ssSpKey.size()); - - // DB value for property entry - CDataStream ssSpValue(SER_DISK, CLIENT_VERSION); - ssSpValue << info; - leveldb::Slice slSpValue(&ssSpValue[0], ssSpValue.size()); - - // DB key for historical property entry - CDataStream ssSpPrevKey(SER_DISK, CLIENT_VERSION); - ssSpPrevKey << 'b'; - ssSpPrevKey << info.update_block; - ssSpPrevKey << propertyId; - leveldb::Slice slSpPrevKey(&ssSpPrevKey[0], ssSpPrevKey.size()); - - leveldb::WriteBatch batch; - std::string strSpPrevValue; - - // if a value exists move it to the old key - if (!pdb->Get(readoptions, slSpKey, &strSpPrevValue).IsNotFound()) { - batch.Put(slSpPrevKey, strSpPrevValue); - } - batch.Put(slSpKey, slSpValue); - leveldb::Status status = pdb->Write(syncoptions, &batch); - - if (!status.ok()) { - PrintToLog("%s(): ERROR for SP %d: %s\n", __func__, propertyId, status.ToString()); - return false; - } - - PrintToLog("%s(): updated entry for SP %d successfully\n", __func__, propertyId); - return true; -} - -uint32_t CMPSPInfo::putSP(uint8_t ecosystem, const Entry& info) -{ - uint32_t propertyId = 0; - switch (ecosystem) { - case ELYSIUM_PROPERTY_ELYSIUM: // Main ecosystem, ELYSIUM: 1, TELYSIUM: 2, First available SP = 3 - propertyId = next_spid++; - break; - case ELYSIUM_PROPERTY_TELYSIUM: // Test ecosystem, same as above with high bit set - propertyId = next_test_spid++; - break; - default: // Non-standard ecosystem, ID's start at 0 - propertyId = 0; - } - - // DB key for property entry - CDataStream ssSpKey(SER_DISK, CLIENT_VERSION); - ssSpKey << std::make_pair('s', propertyId); - leveldb::Slice slSpKey(&ssSpKey[0], ssSpKey.size()); - - // DB value for property entry - CDataStream ssSpValue(SER_DISK, CLIENT_VERSION); - ssSpValue << info; - leveldb::Slice slSpValue(&ssSpValue[0], ssSpValue.size()); - - // DB key for identifier lookup entry - CDataStream ssTxIndexKey(SER_DISK, CLIENT_VERSION); - ssTxIndexKey << std::make_pair('t', info.txid); - leveldb::Slice slTxIndexKey(&ssTxIndexKey[0], ssTxIndexKey.size()); - - // DB value for identifier - CDataStream ssTxValue(SER_DISK, CLIENT_VERSION); - ssTxValue << propertyId; - leveldb::Slice slTxValue(&ssTxValue[0], ssTxValue.size()); - - // sanity checking - std::string existingEntry; - if (!pdb->Get(readoptions, slSpKey, &existingEntry).IsNotFound() && slSpValue.compare(existingEntry) != 0) { - std::string strError = strprintf("writing SP %d to DB, when a different SP already exists for that identifier", propertyId); - PrintToLog("%s() ERROR: %s\n", __func__, strError); - } else if (!pdb->Get(readoptions, slTxIndexKey, &existingEntry).IsNotFound() && slTxValue.compare(existingEntry) != 0) { - std::string strError = strprintf("writing index txid %s : SP %d is overwriting a different value", info.txid.ToString(), propertyId); - PrintToLog("%s() ERROR: %s\n", __func__, strError); - } - - // atomically write both the the SP and the index to the database - leveldb::WriteBatch batch; - batch.Put(slSpKey, slSpValue); - batch.Put(slTxIndexKey, slTxValue); - - leveldb::Status status = pdb->Write(syncoptions, &batch); - - if (!status.ok()) { - PrintToLog("%s(): ERROR for SP %d: %s\n", __func__, propertyId, status.ToString()); - } - - return propertyId; -} - -bool CMPSPInfo::getSP(uint32_t propertyId, Entry& info) const -{ - // special cases for constant SPs ELYSIUM and TELYSIUM - if (ELYSIUM_PROPERTY_ELYSIUM == propertyId) { - info = implied_elysium; - return true; - } else if (ELYSIUM_PROPERTY_TELYSIUM == propertyId) { - info = implied_telysium; - return true; - } - - // DB key for property entry - CDataStream ssSpKey(SER_DISK, CLIENT_VERSION); - ssSpKey << std::make_pair('s', propertyId); - leveldb::Slice slSpKey(&ssSpKey[0], ssSpKey.size()); - - // DB value for property entry - std::string strSpValue; - leveldb::Status status = pdb->Get(readoptions, slSpKey, &strSpValue); - if (!status.ok()) { - if (!status.IsNotFound()) { - PrintToLog("%s(): ERROR for SP %d: %s\n", __func__, propertyId, status.ToString()); - } - return false; - } - - try { - CDataStream ssSpValue(strSpValue.data(), strSpValue.data() + strSpValue.size(), SER_DISK, CLIENT_VERSION); - ssSpValue >> info; - } catch (const std::exception& e) { - PrintToLog("%s(): ERROR for SP %d: %s\n", __func__, propertyId, e.what()); - return false; - } - - return true; -} - -bool CMPSPInfo::hasSP(uint32_t propertyId) const -{ - // Special cases for constant SPs MSC and TMSC - if (ELYSIUM_PROPERTY_ELYSIUM == propertyId || ELYSIUM_PROPERTY_TELYSIUM == propertyId) { - return true; - } - - // DB key for property entry - CDataStream ssSpKey(SER_DISK, CLIENT_VERSION); - ssSpKey << std::make_pair('s', propertyId); - leveldb::Slice slSpKey(&ssSpKey[0], ssSpKey.size()); - - // DB value for property entry - std::string strSpValue; - leveldb::Status status = pdb->Get(readoptions, slSpKey, &strSpValue); - - return status.ok(); -} - -uint32_t CMPSPInfo::findSPByTX(const uint256& txid) const -{ - uint32_t propertyId = 0; - - // DB key for identifier lookup entry - CDataStream ssTxIndexKey(SER_DISK, CLIENT_VERSION); - ssTxIndexKey << std::make_pair('t', txid); - leveldb::Slice slTxIndexKey(&ssTxIndexKey[0], ssTxIndexKey.size()); - - // DB value for identifier - std::string strTxIndexValue; - if (!pdb->Get(readoptions, slTxIndexKey, &strTxIndexValue).ok()) { - std::string strError = strprintf("failed to find property created with %s", txid.GetHex()); - PrintToLog("%s(): ERROR: %s", __func__, strError); - return 0; - } - - try { - CDataStream ssValue(strTxIndexValue.data(), strTxIndexValue.data() + strTxIndexValue.size(), SER_DISK, CLIENT_VERSION); - ssValue >> propertyId; - } catch (const std::exception& e) { - PrintToLog("%s(): ERROR: %s\n", __func__, e.what()); - return 0; - } - - return propertyId; -} - -int64_t CMPSPInfo::popBlock(const uint256& block_hash) -{ - int64_t remainingSPs = 0; - leveldb::WriteBatch commitBatch; - leveldb::Iterator* iter = NewIterator(); - - CDataStream ssSpKeyPrefix(SER_DISK, CLIENT_VERSION); - ssSpKeyPrefix << 's'; - leveldb::Slice slSpKeyPrefix(&ssSpKeyPrefix[0], ssSpKeyPrefix.size()); - - for (iter->Seek(slSpKeyPrefix); iter->Valid() && iter->key().starts_with(slSpKeyPrefix); iter->Next()) { - // deserialize the persisted value - leveldb::Slice slSpValue = iter->value(); - Entry info; - try { - CDataStream ssValue(slSpValue.data(), slSpValue.data() + slSpValue.size(), SER_DISK, CLIENT_VERSION); - ssValue >> info; - } catch (const std::exception& e) { - PrintToLog("%s(): ERROR: %s\n", __func__, e.what()); - return -1; - } - // pop the block - if (info.update_block == block_hash) { - leveldb::Slice slSpKey = iter->key(); - - // need to roll this SP back - if (info.update_block == info.creation_block) { - // this is the block that created this SP, so delete the SP and the tx index entry - CDataStream ssTxIndexKey(SER_DISK, CLIENT_VERSION); - ssTxIndexKey << std::make_pair('t', info.txid); - leveldb::Slice slTxIndexKey(&ssTxIndexKey[0], ssTxIndexKey.size()); - commitBatch.Delete(slSpKey); - commitBatch.Delete(slTxIndexKey); - } else { - uint32_t propertyId = 0; - try { - CDataStream ssValue(1+slSpKey.data(), 1+slSpKey.data()+slSpKey.size(), SER_DISK, CLIENT_VERSION); - ssValue >> propertyId; - } catch (const std::exception& e) { - PrintToLog("%s(): ERROR: %s\n", __func__, e.what()); - return -2; - } - - CDataStream ssSpPrevKey(SER_DISK, CLIENT_VERSION); - ssSpPrevKey << 'b'; - ssSpPrevKey << info.update_block; - ssSpPrevKey << propertyId; - leveldb::Slice slSpPrevKey(&ssSpPrevKey[0], ssSpPrevKey.size()); - - std::string strSpPrevValue; - if (!pdb->Get(readoptions, slSpPrevKey, &strSpPrevValue).IsNotFound()) { - // copy the prev state to the current state and delete the old state - commitBatch.Put(slSpKey, strSpPrevValue); - commitBatch.Delete(slSpPrevKey); - ++remainingSPs; - } else { - // failed to find a previous SP entry, trigger reparse - PrintToLog("%s(): ERROR: failed to retrieve previous SP entry\n", __func__); - return -3; - } - } - } else { - ++remainingSPs; - } - } - - // clean up the iterator - delete iter; - - leveldb::Status status = pdb->Write(syncoptions, &commitBatch); - - if (!status.ok()) { - PrintToLog("%s(): ERROR: %s\n", __func__, status.ToString()); - return -4; - } - - return remainingSPs; -} - -void CMPSPInfo::setWatermark(const uint256& watermark) -{ - leveldb::WriteBatch batch; - - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey << 'B'; - leveldb::Slice slKey(&ssKey[0], ssKey.size()); - - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - ssValue << watermark; - leveldb::Slice slValue(&ssValue[0], ssValue.size()); - - batch.Delete(slKey); - batch.Put(slKey, slValue); - - leveldb::Status status = pdb->Write(syncoptions, &batch); - if (!status.ok()) { - PrintToLog("%s(): ERROR: failed to write watermark: %s\n", __func__, status.ToString()); - } -} - -bool CMPSPInfo::getWatermark(uint256& watermark) const -{ - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey << 'B'; - leveldb::Slice slKey(&ssKey[0], ssKey.size()); - - std::string strValue; - leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); - if (!status.ok()) { - if (!status.IsNotFound()) { - PrintToLog("%s(): ERROR: failed to retrieve watermark: %s\n", __func__, status.ToString()); - } - return false; - } - - try { - CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); - ssValue >> watermark; - } catch (const std::exception& e) { - PrintToLog("%s(): ERROR: failed to deserialize watermark: %s\n", __func__, e.what()); - return false; - } - - return true; -} - -bool CMPSPInfo::getPrevVersion(uint32_t propertyId, Entry &info) const -{ - CDataStream prevKeyData(SER_DISK, CLIENT_VERSION); - prevKeyData << 'b'; - prevKeyData << info.update_block; - prevKeyData << propertyId; - leveldb::Slice prevKey(&prevKeyData[0], prevKeyData.size()); - - std::string prevValueData; - auto status = pdb->Get(readoptions, prevKey, &prevValueData); - if (!status.ok()) { - if (status.IsNotFound()) { - return false; - } - LogPrintf("%s() : fail to get previous version of property %d\n", __func__, propertyId); - throw std::runtime_error("fail to get previous version of sp"); - } - - CDataStream prevValue( - prevValueData.data(), - prevValueData.data() + prevValueData.size(), - SER_DISK, CLIENT_VERSION - ); - prevValue >> info; - - return true; -} - -int CMPSPInfo::getDenominationRemainingConfirmation( - uint32_t propertyId, uint8_t denomination, int target) -{ - LOCK(cs_main); - Entry info; - if (!getSP(propertyId, info)) { - throw std::invalid_argument("property notfound"); - } - - // no denomination in lastest version then imply it's unconfirmed. - if (denomination >= info.denominations.size()) { - return target; - } - - int targetBlock = - std::max(chainActive.Height() - target + 1, 0); - CBlockIndex *lastBlockHasDenomination = nullptr; - - while ( - denomination < info.denominations.size() && - (lastBlockHasDenomination = - GetBlockIndex(info.update_block))->nHeight > targetBlock) { - if (!getPrevVersion(propertyId, info)) { - break; - } - } - - return lastBlockHasDenomination->nHeight <= targetBlock ? 0 : - lastBlockHasDenomination->nHeight - targetBlock; -} - -void CMPSPInfo::printAll() const -{ - // print off the hard coded MSC and TMSC entries - for (uint32_t idx = ELYSIUM_PROPERTY_ELYSIUM; idx <= ELYSIUM_PROPERTY_TELYSIUM; idx++) { - Entry info; - PrintToLog("%10d => ", idx); - if (getSP(idx, info)) { - info.print(); - } else { - PrintToLog("\n"); - } - } - - leveldb::Iterator* iter = NewIterator(); - - CDataStream ssSpKeyPrefix(SER_DISK, CLIENT_VERSION); - ssSpKeyPrefix << 's'; - leveldb::Slice slSpKeyPrefix(&ssSpKeyPrefix[0], ssSpKeyPrefix.size()); - - for (iter->Seek(slSpKeyPrefix); iter->Valid() && iter->key().starts_with(slSpKeyPrefix); iter->Next()) { - leveldb::Slice slSpKey = iter->key(); - uint32_t propertyId = 0; - try { - CDataStream ssValue(1+slSpKey.data(), 1+slSpKey.data()+slSpKey.size(), SER_DISK, CLIENT_VERSION); - ssValue >> propertyId; - } catch (const std::exception& e) { - PrintToLog("\n"); - PrintToLog("%s(): ERROR: %s\n", __func__, e.what()); - continue; - } - PrintToLog("%10s => ", propertyId); - - // deserialize the persisted data - leveldb::Slice slSpValue = iter->value(); - Entry info; - try { - CDataStream ssSpValue(slSpValue.data(), slSpValue.data() + slSpValue.size(), SER_DISK, CLIENT_VERSION); - ssSpValue >> info; - } catch (const std::exception& e) { - PrintToLog("\n"); - PrintToLog("%s(): ERROR: %s\n", __func__, e.what()); - continue; - } - info.print(); - } - - // clean up the iterator - delete iter; -} - -CMPCrowd::CMPCrowd() - : propertyId(0), nValue(0), property_desired(0), deadline(0), - early_bird(0), percentage(0), u_created(0), i_created(0) -{ -} - -CMPCrowd::CMPCrowd(uint32_t pid, int64_t nv, uint32_t cd, int64_t dl, uint8_t eb, uint8_t per, int64_t uct, int64_t ict) - : propertyId(pid), nValue(nv), property_desired(cd), deadline(dl), - early_bird(eb), percentage(per), u_created(uct), i_created(ict) -{ -} - -void CMPCrowd::insertDatabase(const uint256& txHash, const std::vector& txData) -{ - txFundraiserData.insert(std::make_pair(txHash, txData)); -} - -std::string CMPCrowd::toString(const std::string& address) const -{ - return strprintf("%34s : id=%u=%X; prop=%u, value= %li, deadline: %s (%lX)", address, propertyId, propertyId, - property_desired, nValue, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", deadline), deadline); -} - -void CMPCrowd::print(const std::string& address, FILE* fp) const -{ - fprintf(fp, "%s\n", toString(address).c_str()); -} - -void CMPCrowd::saveCrowdSale(std::ofstream& file, SHA256_CTX* shaCtx, const std::string& addr) const -{ - // compose the outputline - // addr,propertyId,nValue,property_desired,deadline,early_bird,percentage,created,mined - std::string lineOut = strprintf("%s,%d,%d,%d,%d,%d,%d,%d,%d", - addr, - propertyId, - nValue, - property_desired, - deadline, - early_bird, - percentage, - u_created, - i_created); - - // append N pairs of address=nValue;blockTime for the database - std::map >::const_iterator iter; - for (iter = txFundraiserData.begin(); iter != txFundraiserData.end(); ++iter) { - lineOut.append(strprintf(",%s=", (*iter).first.GetHex())); - std::vector const &vals = (*iter).second; - - std::vector::const_iterator valIter; - for (valIter = vals.begin(); valIter != vals.end(); ++valIter) { - if (valIter != vals.begin()) { - lineOut.append(";"); - } - - lineOut.append(strprintf("%d", *valIter)); - } - } - - // add the line to the hash - SHA256_Update(shaCtx, lineOut.c_str(), lineOut.length()); - - // write the line - file << lineOut << std::endl; -} - -CMPCrowd* elysium::getCrowd(const std::string& address) -{ - CrowdMap::iterator my_it = my_crowds.find(address); - - if (my_it != my_crowds.end()) return &(my_it->second); - - return (CMPCrowd *)NULL; -} - -bool elysium::IsPropertyIdValid(uint32_t propertyId) -{ - if (propertyId == 0) return false; - - uint32_t nextId = 0; - - if (propertyId < TEST_ECO_PROPERTY_1) { - nextId = _my_sps->peekNextSPID(1); - } else { - nextId = _my_sps->peekNextSPID(2); - } - - if (propertyId < nextId) { - return true; - } - - return false; -} - -bool elysium::IsSigmaStatusValid(SigmaStatus status) -{ - return status == SigmaStatus::SoftDisabled || - status == SigmaStatus::SoftEnabled || - status == SigmaStatus::HardDisabled || - status == SigmaStatus::HardEnabled; -} - -bool elysium::IsSigmaEnabled(PropertyId property) -{ - CMPSPInfo::Entry info; - - LOCK(cs_main); - - if (!_my_sps->getSP(property, info)) { - throw std::invalid_argument("property identifier is not valid"); - } - - return IsEnabledFlag(info.sigmaStatus); -} - -bool elysium::IsDenominationValid(PropertyId property, SigmaDenomination denomination) -{ - CMPSPInfo::Entry info; - - LOCK(cs_main); - - if (!_my_sps->getSP(property, info)) { - throw std::invalid_argument("property identifier is not valid"); - } - - return denomination < info.denominations.size(); -} - -int64_t elysium::GetDenominationValue(PropertyId property, SigmaDenomination denomination) -{ - CMPSPInfo::Entry info; - - LOCK(cs_main); - - if (!_my_sps->getSP(property, info)) { - throw std::invalid_argument("property identifier is not valid"); - } - - if (denomination >= info.denominations.size()) { - throw std::invalid_argument("denomination identifier is not valid"); - } - - return info.denominations[denomination]; -} - -std::string std::to_string(SigmaStatus status) -{ - switch (status) { - case SigmaStatus::SoftDisabled: - return "SoftDisabled"; - case SigmaStatus::SoftEnabled: - return "SoftEnabled"; - case SigmaStatus::HardDisabled: - return "HardDisabled"; - case SigmaStatus::HardEnabled: - return "HardEnabled"; - default: - throw std::invalid_argument("sigma status is invalid"); - } -} - -bool elysium::isPropertyDivisible(uint32_t propertyId) -{ - // TODO: is a lock here needed - CMPSPInfo::Entry sp; - - if (_my_sps->getSP(propertyId, sp)) return sp.isDivisible(); - - return true; -} - -std::string elysium::getPropertyName(uint32_t propertyId) -{ - CMPSPInfo::Entry sp; - if (_my_sps->getSP(propertyId, sp)) return sp.name; - return "Property Name Not Found"; -} - -bool elysium::isCrowdsaleActive(uint32_t propertyId) -{ - for (CrowdMap::const_iterator it = my_crowds.begin(); it != my_crowds.end(); ++it) { - const CMPCrowd& crowd = it->second; - uint32_t foundPropertyId = crowd.getPropertyId(); - if (foundPropertyId == propertyId) return true; - } - return false; -} - -/** - * Calculates missing bonus tokens, which are credited to the crowdsale issuer. - * - * Due to rounding effects, a crowdsale issuer may not receive the full - * bonus immediatly. The missing amount is calculated based on the total - * tokens created and already credited. - * - * @param sp The crowdsale property - * @param crowdsale The crowdsale - * @return The number of missed tokens - */ -int64_t elysium::GetMissedIssuerBonus(const CMPSPInfo::Entry& sp, const CMPCrowd& crowdsale) -{ - // consistency check - assert(getTotalTokens(crowdsale.getPropertyId()) - == (crowdsale.getIssuerCreated() + crowdsale.getUserCreated())); - - arith_uint256 amountMissing = 0; - arith_uint256 bonusPercentForIssuer = ConvertTo256(sp.percentage); - arith_uint256 amountAlreadyCreditedToIssuer = ConvertTo256(crowdsale.getIssuerCreated()); - arith_uint256 amountCreditedToUsers = ConvertTo256(crowdsale.getUserCreated()); - arith_uint256 amountTotal = amountCreditedToUsers + amountAlreadyCreditedToIssuer; - - // calculate theoretical bonus for issuer based on the amount of - // tokens credited to users - arith_uint256 exactBonus = amountCreditedToUsers * bonusPercentForIssuer; - exactBonus /= ConvertTo256(100); // 100 % - - // there shall be no negative missing amount - if (exactBonus < amountAlreadyCreditedToIssuer) { - return 0; - } - - // subtract the amount already credited to the issuer - if (exactBonus > amountAlreadyCreditedToIssuer) { - amountMissing = exactBonus - amountAlreadyCreditedToIssuer; - } - - // calculate theoretical total amount of all tokens - arith_uint256 newTotal = amountTotal + amountMissing; - - // reduce to max. possible amount - if (newTotal > uint256_const::max_int64) { - amountMissing = uint256_const::max_int64 - amountTotal; - } - - return ConvertTo64(amountMissing); -} - -// calculateFundraiser does token calculations per transaction -// calcluateFractional does calculations for missed tokens -void elysium::calculateFundraiser(bool inflateAmount, int64_t amtTransfer, uint8_t bonusPerc, - int64_t fundraiserSecs, int64_t currentSecs, int64_t numProps, uint8_t issuerPerc, int64_t totalTokens, - std::pair& tokens, bool& close_crowdsale) -{ - // Weeks in seconds - arith_uint256 weeks_sec_ = ConvertTo256(604800); - - // Precision for all non-firo values (bonus percentages, for example) - arith_uint256 precision_ = ConvertTo256(1000000000000LL); - - // Precision for all percentages (10/100 = 10%) - arith_uint256 percentage_precision = ConvertTo256(100); - - // Calculate the bonus seconds - arith_uint256 bonusSeconds_ = 0; - if (currentSecs < fundraiserSecs) { - bonusSeconds_ = ConvertTo256(fundraiserSecs) - ConvertTo256(currentSecs); - } - - // Calculate the whole number of weeks to apply bonus - arith_uint256 weeks_ = (bonusSeconds_ / weeks_sec_) * precision_; - weeks_ += (Modulo256(bonusSeconds_, weeks_sec_) * precision_) / weeks_sec_; - - // Calculate the earlybird percentage to be applied - arith_uint256 ebPercentage_ = weeks_ * ConvertTo256(bonusPerc); - - // Calcluate the bonus percentage to apply up to percentage_precision number of digits - arith_uint256 bonusPercentage_ = (precision_ * percentage_precision); - bonusPercentage_ += ebPercentage_; - bonusPercentage_ /= percentage_precision; - - // Calculate the bonus percentage for the issuer - arith_uint256 issuerPercentage_ = ConvertTo256(issuerPerc); - issuerPercentage_ *= precision_; - issuerPercentage_ /= percentage_precision; - - // Precision for firo amounts (satoshi) - arith_uint256 satoshi_precision_ = ConvertTo256(100000000L); - - // Total tokens including remainders - arith_uint256 createdTokens = ConvertTo256(amtTransfer); - if (inflateAmount) { - createdTokens *= ConvertTo256(100000000L); - } - createdTokens *= ConvertTo256(numProps); - createdTokens *= bonusPercentage_; - - arith_uint256 issuerTokens = createdTokens / satoshi_precision_; - issuerTokens /= precision_; - issuerTokens *= (issuerPercentage_ / 100); - issuerTokens *= precision_; - - arith_uint256 createdTokens_int = createdTokens / precision_; - createdTokens_int /= satoshi_precision_; - - arith_uint256 issuerTokens_int = issuerTokens / precision_; - issuerTokens_int /= satoshi_precision_; - issuerTokens_int /= 100; - - arith_uint256 newTotalCreated = ConvertTo256(totalTokens) + createdTokens_int + issuerTokens_int; - - if (newTotalCreated > uint256_const::max_int64) { - arith_uint256 maxCreatable = uint256_const::max_int64 - ConvertTo256(totalTokens); - arith_uint256 created = createdTokens_int + issuerTokens_int; - - // Calcluate the ratio of tokens for what we can create and apply it - arith_uint256 ratio = created * precision_; - ratio *= satoshi_precision_; - ratio /= maxCreatable; - - // The tokens for the issuer - issuerTokens_int = issuerTokens_int * precision_; - issuerTokens_int *= satoshi_precision_; - issuerTokens_int /= ratio; - - assert(issuerTokens_int <= maxCreatable); - - // The tokens for the user - createdTokens_int = maxCreatable - issuerTokens_int; - - // Close the crowdsale after assigning all tokens - close_crowdsale = true; - } - - // The tokens to credit - tokens = std::make_pair(ConvertTo64(createdTokens_int), ConvertTo64(issuerTokens_int)); -} - -// go hunting for whether a simple send is a crowdsale purchase -// TODO !!!! horribly inefficient !!!! find a more efficient way to do this -bool elysium::isCrowdsalePurchase(const uint256& txid, const std::string& address, int64_t* propertyId, int64_t* userTokens, int64_t* issuerTokens) -{ - // 1. loop crowdsales (active/non-active) looking for issuer address - // 2. loop those crowdsales for that address and check their participant txs in database - - // check for an active crowdsale to this address - CMPCrowd* pcrowdsale = getCrowd(address); - if (pcrowdsale) { - std::map >::const_iterator it; - const std::map >& database = pcrowdsale->getDatabase(); - for (it = database.begin(); it != database.end(); it++) { - const uint256& tmpTxid = it->first; - if (tmpTxid == txid) { - *propertyId = pcrowdsale->getPropertyId(); - *userTokens = it->second.at(2); - *issuerTokens = it->second.at(3); - return true; - } - } - } - - // if we still haven't found txid, check non active crowdsales to this address - for (uint8_t ecosystem = 1; ecosystem <= 2; ecosystem++) { - uint32_t startPropertyId = (ecosystem == 1) ? 1 : TEST_ECO_PROPERTY_1; - for (uint32_t loopPropertyId = startPropertyId; loopPropertyId < _my_sps->peekNextSPID(ecosystem); loopPropertyId++) { - CMPSPInfo::Entry sp; - if (!_my_sps->getSP(loopPropertyId, sp)) continue; - if (sp.issuer != address) continue; - for (std::map >::const_iterator it = sp.historicalData.begin(); it != sp.historicalData.end(); it++) { - if (it->first == txid) { - *propertyId = loopPropertyId; - *userTokens = it->second.at(2); - *issuerTokens = it->second.at(3); - return true; - } - } - } - } - - // didn't find anything, not a crowdsale purchase - return false; -} - -void elysium::eraseMaxedCrowdsale(const std::string& address, int64_t blockTime, int block) -{ - CrowdMap::iterator it = my_crowds.find(address); - - if (it != my_crowds.end()) { - const CMPCrowd& crowdsale = it->second; - - PrintToLog("%s(): ERASING MAXED OUT CROWDSALE from address=%s, at block %d (timestamp: %d), SP: %d (%s)\n", - __func__, address, block, blockTime, crowdsale.getPropertyId(), strMPProperty(crowdsale.getPropertyId())); - - if (elysium_debug_sp) { - PrintToLog("%s(): %s\n", __func__, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", blockTime)); - PrintToLog("%s(): %s\n", __func__, crowdsale.toString(address)); - } - - // get sp from data struct - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(crowdsale.getPropertyId(), sp)); - - // get txdata - sp.historicalData = crowdsale.getDatabase(); - sp.close_early = true; - sp.max_tokens = true; - sp.timeclosed = blockTime; - - // update SP with this data - sp.update_block = chainActive[block]->GetBlockHash(); - assert(_my_sps->updateSP(crowdsale.getPropertyId(), sp)); - - // no calculate fractional calls here, no more tokens (at MAX) - my_crowds.erase(it); - } -} - -unsigned int elysium::eraseExpiredCrowdsale(const CBlockIndex* pBlockIndex) -{ - if (pBlockIndex == NULL) return 0; - - const int64_t blockTime = pBlockIndex->GetBlockTime(); - const int blockHeight = pBlockIndex->nHeight; - unsigned int how_many_erased = 0; - CrowdMap::iterator my_it = my_crowds.begin(); - - while (my_crowds.end() != my_it) { - const std::string& address = my_it->first; - const CMPCrowd& crowdsale = my_it->second; - - if (blockTime > crowdsale.getDeadline()) { - PrintToLog("%s(): ERASING EXPIRED CROWDSALE from address=%s, at block %d (timestamp: %d), SP: %d (%s)\n", - __func__, address, blockHeight, blockTime, crowdsale.getPropertyId(), strMPProperty(crowdsale.getPropertyId())); - - if (elysium_debug_sp) { - PrintToLog("%s(): %s\n", __func__, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", blockTime)); - PrintToLog("%s(): %s\n", __func__, crowdsale.toString(address)); - } - - // get sp from data struct - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(crowdsale.getPropertyId(), sp)); - - // find missing tokens - int64_t missedTokens = GetMissedIssuerBonus(sp, crowdsale); - - // get txdata - sp.historicalData = crowdsale.getDatabase(); - sp.missedTokens = missedTokens; - - // update SP with this data - sp.update_block = pBlockIndex->GetBlockHash(); - assert(_my_sps->updateSP(crowdsale.getPropertyId(), sp)); - - // update values - if (missedTokens > 0) { - assert(update_tally_map(sp.issuer, crowdsale.getPropertyId(), missedTokens, BALANCE)); - } - - my_crowds.erase(my_it++); - - ++how_many_erased; - - } else my_it++; - } - - return how_many_erased; -} - -std::string elysium::strPropertyType(uint16_t propertyType) -{ - switch (propertyType) { - case ELYSIUM_PROPERTY_TYPE_DIVISIBLE: return "divisible"; - case ELYSIUM_PROPERTY_TYPE_INDIVISIBLE: return "indivisible"; - } - - return "unknown"; -} - -std::string elysium::strEcosystem(uint8_t ecosystem) -{ - switch (ecosystem) { - case ELYSIUM_PROPERTY_ELYSIUM: return "main"; - case ELYSIUM_PROPERTY_TELYSIUM: return "test"; - } - - return "unknown"; -} diff --git a/src/elysium/sp.h b/src/elysium/sp.h deleted file mode 100644 index dcf487f74c..0000000000 --- a/src/elysium/sp.h +++ /dev/null @@ -1,318 +0,0 @@ -#ifndef FIRO_ELYSIUM_SP_H -#define FIRO_ELYSIUM_SP_H - -#include "log.h" -#include "persistence.h" -#include "property.h" -#include "sigmaprimitives.h" - -#include "../validation.h" -#include "../serialize.h" - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace elysium { - -constexpr size_t MAX_DENOMINATIONS = std::numeric_limits::max(); - -} // namespace elysium - -/** LevelDB based storage for currencies, smart properties and tokens. - * - * DB Schema: - * - * Key: - * char 'B' - * Value: - * uint256 hashBlock - * - * Key: - * char 's' - * uint32_t propertyId - * Value: - * CMPSPInfo::Entry info - * - * Key: - * char 't' - * uint256 hashTxid - * Value: - * uint32_t propertyId - * - * Key: - * char 'b' - * uint256 hashBlock - * uint32_t propertyId - * Value: - * CMPSPInfo::Entry info - */ -class CMPSPInfo : public CDBBase -{ -public: - struct Entry { - // common SP data - std::string issuer; - uint16_t prop_type; - uint32_t prev_prop_id; - std::string category; - std::string subcategory; - std::string name; - std::string url; - std::string data; - int64_t num_tokens; - - // crowdsale generated SP - uint32_t property_desired; - int64_t deadline; - uint8_t early_bird; - uint8_t percentage; - - // closedearly states, if the SP was a crowdsale and closed due to MAXTOKENS or CLOSE command - bool close_early; - bool max_tokens; - int64_t missedTokens; - int64_t timeclosed; - uint256 txid_close; - - // other information - uint256 txid; - uint256 creation_block; - uint256 update_block; - bool fixed; - bool manual; - elysium::SigmaStatus sigmaStatus; - std::vector denominations; - - // For crowdsale properties: - // txid -> amount invested, crowdsale deadline, user issued tokens, issuer issued tokens - // For managed properties: - // txid -> granted amount, revoked amount - std::map > historicalData; - - Entry(); - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - auto sigmaStatus = static_cast(this->sigmaStatus); - - READWRITE(issuer); - READWRITE(prop_type); - READWRITE(prev_prop_id); - READWRITE(category); - READWRITE(subcategory); - READWRITE(name); - READWRITE(url); - READWRITE(data); - READWRITE(num_tokens); - READWRITE(property_desired); - READWRITE(deadline); - READWRITE(early_bird); - READWRITE(percentage); - READWRITE(close_early); - READWRITE(max_tokens); - READWRITE(missedTokens); - READWRITE(timeclosed); - READWRITE(txid_close); - READWRITE(txid); - READWRITE(creation_block); - READWRITE(update_block); - READWRITE(fixed); - READWRITE(manual); - READWRITE(historicalData); - - if (ser_action.ForRead()) { - // If it is EOF when trying to read additional field that mean it is data before we introduced it. - try { - READWRITE(sigmaStatus); - } catch (std::ios_base::failure&) { - // Assume it is EOF due to no other better way to check. - sigmaStatus = static_cast(elysium::SigmaStatus::SoftDisabled); - } - - try { - READWRITE(denominations); - } catch (std::ios_base::failure&) { - denominations.clear(); - } - } else { - READWRITE(sigmaStatus); - READWRITE(denominations); - } - - this->sigmaStatus = static_cast(sigmaStatus); - } - - bool isDivisible() const; - void print() const; - }; - -private: - // implied version of ELYSIUM and TELYSIUM so they don't hit the leveldb - Entry implied_elysium; - Entry implied_telysium; - - uint32_t next_spid; - uint32_t next_test_spid; - -public: - CMPSPInfo(const boost::filesystem::path& path, bool fWipe); - virtual ~CMPSPInfo(); - - /** Extends clearing of CDBBase. */ - void Clear(); - - void init(uint32_t nextSPID = 0x3UL, uint32_t nextTestSPID = TEST_ECO_PROPERTY_1); - - uint32_t peekNextSPID(uint8_t ecosystem) const; - bool updateSP(uint32_t propertyId, const Entry& info); - uint32_t putSP(uint8_t ecosystem, const Entry& info); - bool getSP(uint32_t propertyId, Entry& info) const; - bool hasSP(uint32_t propertyId) const; - uint32_t findSPByTX(const uint256& txid) const; - - int64_t popBlock(const uint256& block_hash); - - void setWatermark(const uint256& watermark); - bool getWatermark(uint256& watermark) const; - - bool getPrevVersion(uint32_t propertyId, Entry &info) const; - - int getDenominationRemainingConfirmation(uint32_t propertyId, uint8_t denomination, int target); - - void printAll() const; -}; - -/** A live crowdsale. - */ -class CMPCrowd -{ -private: - uint32_t propertyId; - int64_t nValue; - - uint32_t property_desired; - int64_t deadline; - uint8_t early_bird; - uint8_t percentage; - - int64_t u_created; - int64_t i_created; - - uint256 txid; // NOTE: not persisted as it doesnt seem used - - // Schema: - // txid -> amount invested, crowdsale deadline, user issued tokens, issuer issued tokens - std::map > txFundraiserData; - -public: - CMPCrowd(); - CMPCrowd(uint32_t pid, int64_t nv, uint32_t cd, int64_t dl, uint8_t eb, uint8_t per, int64_t uct, int64_t ict); - - uint32_t getPropertyId() const { return propertyId; } - - int64_t getDeadline() const { return deadline; } - uint32_t getCurrDes() const { return property_desired; } - - void incTokensUserCreated(int64_t amount) { u_created += amount; } - void incTokensIssuerCreated(int64_t amount) { i_created += amount; } - - int64_t getUserCreated() const { return u_created; } - int64_t getIssuerCreated() const { return i_created; } - - void insertDatabase(const uint256& txHash, const std::vector& txData); - std::map > getDatabase() const { return txFundraiserData; } - - std::string toString(const std::string& address) const; - void print(const std::string& address, FILE* fp = stdout) const; - void saveCrowdSale(std::ofstream& file, SHA256_CTX* shaCtx, const std::string& addr) const; -}; - -namespace elysium { - -typedef std::map CrowdMap; - -extern CMPSPInfo* _my_sps; -extern CrowdMap my_crowds; - -std::string strPropertyType(uint16_t propertyType); -std::string strEcosystem(uint8_t ecosystem); - -std::string getPropertyName(uint32_t propertyId); -bool isPropertyDivisible(uint32_t propertyId); -bool IsPropertyIdValid(uint32_t propertyId); -bool IsSigmaStatusValid(SigmaStatus status); -bool IsSigmaEnabled(PropertyId property); -bool IsDenominationValid(PropertyId property, SigmaDenomination denomination); -int64_t GetDenominationValue(PropertyId property, SigmaDenomination denomination); - -CMPCrowd* getCrowd(const std::string& address); - -bool isCrowdsaleActive(uint32_t propertyId); -bool isCrowdsalePurchase(const uint256& txid, const std::string& address, int64_t* propertyId, int64_t* userTokens, int64_t* issuerTokens); - -/** Calculates missing bonus tokens, which are credited to the crowdsale issuer. */ -int64_t GetMissedIssuerBonus(const CMPSPInfo::Entry& sp, const CMPCrowd& crowdsale); - -/** Calculates amounts credited for a crowdsale purchase. */ -void calculateFundraiser(bool inflateAmount, int64_t amtTransfer, uint8_t bonusPerc, - int64_t fundraiserSecs, int64_t currentSecs, int64_t numProps, uint8_t issuerPerc, int64_t totalTokens, - std::pair& tokens, bool& close_crowdsale); - -void eraseMaxedCrowdsale(const std::string& address, int64_t blockTime, int block); - -unsigned int eraseExpiredCrowdsale(const CBlockIndex* pBlockIndex); - -template -int64_t SumDenominationsValue(PropertyId property, Denomination begin, Denomination end) -{ - CMPSPInfo::Entry sp; - - LOCK(cs_main); - - if (!_my_sps->getSP(property, sp)) { - throw std::invalid_argument("the property not found"); - } - - int64_t amount = 0; - - for (auto it = begin; it != end; it++) { - if (*it >= sp.denominations.size()) { - throw std::invalid_argument("the denomination not found"); - } - - if (sp.denominations[*it] > static_cast(MAX_INT_8_BYTES) - amount) { - throw std::overflow_error("summation of mints is overflow"); - } - - amount += sp.denominations[*it]; - } - - return amount; -} - -} // namespace elysium - -namespace std { - -using namespace elysium; - -string to_string(SigmaStatus status); - -} // namespace std - -#endif // FIRO_ELYSIUM_SP_H diff --git a/src/elysium/sto.cpp b/src/elysium/sto.cpp deleted file mode 100644 index 6516137744..0000000000 --- a/src/elysium/sto.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "sto.h" - -#include "elysium.h" -#include "log.h" -#include "tally.h" -#include "uint256_extensions.h" - -#include "../arith_uint256.h" -#include "../validation.h" -#include "../sync.h" - -#include -#include -#include -#include - -#include -#include - -namespace elysium { - -/** - * Compares two owner/receiver entries, based on amount. - */ -bool SendToOwners_compare::operator()(const std::pair& p1, const std::pair& p2) const -{ - if (p1.first == p2.first) return p1.second > p2.second; // reverse check - else return p1.first < p2.first; -} - -/** - * Determines the receivers and amounts to distribute. - * - * The sender is excluded from the result set. - */ -OwnerAddrType STO_GetReceivers(const std::string& sender, uint32_t property, int64_t amount) -{ - int64_t totalTokens = 0; - int64_t senderTokens = 0; - OwnerAddrType ownerAddrSet; - - { - LOCK(cs_main); - std::unordered_map::iterator it; - - for (it = mp_tally_map.begin(); it != mp_tally_map.end(); ++it) { - const std::string& address = it->first; - const CMPTally& tally = it->second; - - int64_t tokens = 0; - tokens += tally.getMoney(property, BALANCE); - tokens += tally.getMoney(property, SELLOFFER_RESERVE); - tokens += tally.getMoney(property, ACCEPT_RESERVE); - tokens += tally.getMoney(property, METADEX_RESERVE); - - // Do not include the sender - if (address == sender) { - senderTokens = tokens; - continue; - } - - totalTokens += tokens; - - // Only holders with balance are relevant - if (0 < tokens) { - ownerAddrSet.insert(std::make_pair(tokens, address)); - } - } - } - - // Split up what was taken and distribute between all holders - int64_t sent_so_far = 0; - OwnerAddrType receiversSet; - - for (OwnerAddrType::reverse_iterator it = ownerAddrSet.rbegin(); it != ownerAddrSet.rend(); ++it) { - const std::string& address = it->second; - - arith_uint256 owns = ConvertTo256(it->first); - arith_uint256 temp = owns * ConvertTo256(amount); - arith_uint256 piece = DivideAndRoundUp(temp, ConvertTo256(totalTokens)); - - int64_t will_really_receive = 0; - int64_t should_receive = ConvertTo64(piece); - - // Ensure that no more than available is distributed - if ((amount - sent_so_far) < should_receive) { - will_really_receive = amount - sent_so_far; - } else { - will_really_receive = should_receive; - } - - sent_so_far += will_really_receive; - - if (elysium_debug_sto) { - PrintToLog("%14d = %s, temp= %38s, should_get= %19d, will_really_get= %14d, sent_so_far= %14d\n", - it->first, address, temp.ToString(), should_receive, will_really_receive, sent_so_far); - } - - // Stop, once the whole amount is allocated - if (will_really_receive > 0) { - receiversSet.insert(std::make_pair(will_really_receive, address)); - } else { - break; - } - } - - uint64_t numberOfOwners = receiversSet.size(); - PrintToLog("\t Total Tokens: %s\n", FormatMP(property, totalTokens + senderTokens)); - PrintToLog("\tExcluding Sender: %s\n", FormatMP(property, totalTokens)); - PrintToLog("\t Owners: %d\n", numberOfOwners); - - return receiversSet; -} - -} // namespace elysium diff --git a/src/elysium/sto.h b/src/elysium/sto.h deleted file mode 100644 index 609ff74181..0000000000 --- a/src/elysium/sto.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ELYSIUM_STO_H -#define ELYSIUM_STO_H - -#include -#include -#include -#include - -namespace elysium -{ -//! Comparator for owner/receiver entries -struct SendToOwners_compare -{ - bool operator()(const std::pair& p1, const std::pair& p2) const; -}; - -//! Fee required to be paid per owner/receiver, nominated in willets -const int64_t TRANSFER_FEE_PER_OWNER = 1; -const int64_t TRANSFER_FEE_PER_OWNER_V1 = 1000; - -//! Set of owner/receivers, sorted by amount they own or might receive -typedef std::set, SendToOwners_compare> OwnerAddrType; - -/** Determines the receivers and amounts to distribute. */ -OwnerAddrType STO_GetReceivers(const std::string& sender, uint32_t property, int64_t amount); -} - - -#endif // ELYSIUM_STO_H diff --git a/src/elysium/tally.cpp b/src/elysium/tally.cpp deleted file mode 100644 index 4e1ced56b1..0000000000 --- a/src/elysium/tally.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include "elysium/tally.h" - -#include "elysium/log.h" -#include "elysium/elysium.h" - -#include -#include - -/** - * Creates an empty tally. - */ -CMPTally::CMPTally() -{ - my_it = mp_token.begin(); -} - -/** - * Resets the internal iterator. - * - * @return Identifier of the first tally element. - */ -uint32_t CMPTally::init() -{ - uint32_t propertyId = 0; - my_it = mp_token.begin(); - if (my_it != mp_token.end()) { - propertyId = my_it->first; - } - return propertyId; -} - -/** - * Advances the internal iterator. - * - * @return Identifier of the tally element before the update. - */ -uint32_t CMPTally::next() -{ - uint32_t ret = 0; - if (my_it != mp_token.end()) { - ret = my_it->first; - ++my_it; - } - return ret; -} - -/** - * Checks whether the addition of a + b overflows. - * - * @param a The number - * @param b The other number - * @return True, if a + b overflows - */ -static bool isOverflow(int64_t a, int64_t b) -{ - return (((b > 0) && (a > (std::numeric_limits::max() - b))) || - ((b < 0) && (a < (std::numeric_limits::min() - b)))); -} - -/** - * Updates the number of tokens for the given tally type. - * - * Negative balances are only permitted for pending balances. - * - * @param propertyId The identifier of the tally to update - * @param amount The amount to add - * @param ttype The tally type - * @return True, if the update was successful - */ -bool CMPTally::updateMoney(uint32_t propertyId, int64_t amount, TallyType ttype) -{ - if (TALLY_TYPE_COUNT <= ttype || amount == 0) { - return false; - } - bool fUpdated = false; - int64_t now64 = mp_token[propertyId].balance[ttype]; - - if (isOverflow(now64, amount)) { - PrintToLog("%s(): ERROR: arithmetic overflow [%d + %d]\n", __func__, now64, amount); - return false; - } - - if (PENDING != ttype && (now64 + amount) < 0) { - // NOTE: - // Negative balances are only permitted for pending balances - } else { - - now64 += amount; - mp_token[propertyId].balance[ttype] = now64; - - fUpdated = true; - } - - return fUpdated; -} - -/** - * Returns the number of tokens for the given tally type. - * - * @param propertyId The identifier of the tally to lookup - * @param ttype The tally type - * @return The balance - */ -int64_t CMPTally::getMoney(uint32_t propertyId, TallyType ttype) const -{ - if (TALLY_TYPE_COUNT <= ttype) { - return 0; - } - int64_t money = 0; - TokenMap::const_iterator it = mp_token.find(propertyId); - - if (it != mp_token.end()) { - const BalanceRecord& record = it->second; - money = record.balance[ttype]; - } - - return money; -} - -/** - * Returns the number of available tokens. - * - * The number of available tokens can be negative, if there is a pending - * balance. - * - * @param propertyId The identifier of the tally to lookup - * @return The available balance - */ -int64_t CMPTally::getMoneyAvailable(uint32_t propertyId) const -{ - TokenMap::const_iterator it = mp_token.find(propertyId); - - if (it != mp_token.end()) { - const BalanceRecord& record = it->second; - if (record.balance[PENDING] < 0) { - return record.balance[BALANCE] + record.balance[PENDING]; - } else { - return record.balance[BALANCE]; - } - } - - return 0; -} - -/** - * Returns the number of reserved tokens. - * - * Balances can be reserved by sell offers, pending accepts, or offers - * on the distributed exchange. - * - * @param propertyId The identifier of the tally to lookup - * @return The reserved balance - */ -int64_t CMPTally::getMoneyReserved(uint32_t propertyId) const -{ - int64_t money = 0; - TokenMap::const_iterator it = mp_token.find(propertyId); - - if (it != mp_token.end()) { - const BalanceRecord& record = it->second; - money += record.balance[SELLOFFER_RESERVE]; - money += record.balance[ACCEPT_RESERVE]; - money += record.balance[METADEX_RESERVE]; - } - - return money; -} - -/** - * Compares the tally with another tally and returns true, if they are equal. - * - * @param rhs The other tally - * @return True, if both tallies are equal - */ -bool CMPTally::operator==(const CMPTally& rhs) const -{ - if (mp_token.size() != rhs.mp_token.size()) { - return false; - } - TokenMap::const_iterator pc1 = mp_token.begin(); - TokenMap::const_iterator pc2 = rhs.mp_token.begin(); - - for (unsigned int i = 0; i < mp_token.size(); ++i) { - if (pc1->first != pc2->first) { - return false; - } - const BalanceRecord& record1 = pc1->second; - const BalanceRecord& record2 = pc2->second; - - for (int ttype = 0; ttype < TALLY_TYPE_COUNT; ++ttype) { - if (record1.balance[ttype] != record2.balance[ttype]) { - return false; - } - } - ++pc1; - ++pc2; - } - - assert(pc1 == mp_token.end()); - assert(pc2 == rhs.mp_token.end()); - - return true; -} - -/** - * Compares the tally with another tally and returns true, if they are not equal. - * - * @param rhs The other tally - * @return True, if both tallies are not equal - */ -bool CMPTally::operator!=(const CMPTally& rhs) const -{ - return !operator==(rhs); -} - -/** - * Prints a balance record to the console. - * - * @param propertyId The identifier of the tally to print - * @param bDivisible Whether the token is divisible or indivisible - * @return The total number of tokens of the tally - */ -int64_t CMPTally::print(uint32_t propertyId, bool bDivisible) const -{ - int64_t balance = 0; - int64_t selloffer_reserve = 0; - int64_t accept_reserve = 0; - int64_t pending = 0; - int64_t metadex_reserve = 0; - - TokenMap::const_iterator it = mp_token.find(propertyId); - - if (it != mp_token.end()) { - const BalanceRecord& record = it->second; - balance = record.balance[BALANCE]; - selloffer_reserve = record.balance[SELLOFFER_RESERVE]; - accept_reserve = record.balance[ACCEPT_RESERVE]; - pending = record.balance[PENDING]; - metadex_reserve = record.balance[METADEX_RESERVE]; - } - - if (bDivisible) { - PrintToLog("%22s [ SO_RESERVE= %22s, ACCEPT_RESERVE= %22s, METADEX_RESERVE= %22s ] %22s\n", - FormatDivisibleMP(balance, true), FormatDivisibleMP(selloffer_reserve, true), - FormatDivisibleMP(accept_reserve, true), FormatDivisibleMP(metadex_reserve, true), - FormatDivisibleMP(pending, true)); - } else { - PrintToLog("%14d [ SO_RESERVE= %14d, ACCEPT_RESERVE= %14d, METADEX_RESERVE= %14d ] %14d\n", - balance, selloffer_reserve, accept_reserve, metadex_reserve, pending); - } - - return (balance + selloffer_reserve + accept_reserve + metadex_reserve); -} diff --git a/src/elysium/tally.h b/src/elysium/tally.h deleted file mode 100644 index c96ff91917..0000000000 --- a/src/elysium/tally.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef ELYSIUM_TALLY_H -#define ELYSIUM_TALLY_H - -#include -#include - -//! Balance record types -enum TallyType { - BALANCE = 0, - SELLOFFER_RESERVE = 1, - ACCEPT_RESERVE = 2, - PENDING = 3, - METADEX_RESERVE = 4, - TALLY_TYPE_COUNT -}; - -/** Balance records of a single entity. - */ -class CMPTally -{ -private: - typedef struct { - int64_t balance[TALLY_TYPE_COUNT]; - } BalanceRecord; - - //! Map of balance records - typedef std::map TokenMap; - //! Balance records for different tokens - TokenMap mp_token; - //! Internal iterator pointing to a balance record - TokenMap::iterator my_it; - -public: - /** Creates an empty tally. */ - CMPTally(); - - /** Resets the internal iterator. */ - uint32_t init(); - - /** Advances the internal iterator. */ - uint32_t next(); - - /** Updates the number of tokens for the given tally type. */ - bool updateMoney(uint32_t propertyId, int64_t amount, TallyType ttype); - - /** Returns the number of tokens for the given tally type. */ - int64_t getMoney(uint32_t propertyId, TallyType ttype) const; - - /** Returns the number of available tokens. */ - int64_t getMoneyAvailable(uint32_t propertyId) const; - - /** Returns the number of reserved tokens. */ - int64_t getMoneyReserved(uint32_t propertyId) const; - - /** Compares the tally with another tally and returns true, if they are equal. */ - bool operator==(const CMPTally& rhs) const; - - /** Compares the tally with another tally and returns true, if they are not equal. */ - bool operator!=(const CMPTally& rhs) const; - - /** Prints a balance record to the console. */ - int64_t print(uint32_t propertyId = 1, bool bDivisible = true) const; -}; - - -#endif // ELYSIUM_TALLY_H diff --git a/src/elysium/test/alert_tests.cpp b/src/elysium/test/alert_tests.cpp deleted file mode 100644 index 42147bc7c1..0000000000 --- a/src/elysium/test/alert_tests.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "elysium/notifications.h" -#include "elysium/version.h" - -#include "util.h" -#include "test/test_bitcoin.h" -#include "tinyformat.h" - -#include - -#include -#include -#include -#include - -using namespace elysium; - -// TODO: redo test with immutable mapMultiArgs - -/* - -// Is only temporarily modified and restored after each test -extern std::map mapArgs; -extern std::map > mapMultiArgs; - -BOOST_FIXTURE_TEST_SUITE(elysium_alert_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(alert_positive_authorization) -{ - // Confirm authorized sources for mainnet - BOOST_CHECK(CheckAlertAuthorization("48UM25xTXCxPRwnv36YjjJNaAK4whKR8Rd")); // Poramin Insom -} - -BOOST_AUTO_TEST_CASE(alert_unauthorized_source) -{ - // Confirm unauthorized sources are not accepted - BOOST_CHECK(!CheckAlertAuthorization("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T")); -} - -BOOST_AUTO_TEST_CASE(alert_manual_sources) -{ - std::map mapArgsOriginal = mapArgs; - std::map > mapMultiArgsOriginal = mapMultiArgs; - - mapArgs["-elysiumalertallowsender"] = ""; - mapArgs["-elysiumalertignoresender"] = ""; - - // Add 1JwSSu as allowed source for alerts - mapMultiArgs["-elysiumalertallowsender"].push_back("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T"); - BOOST_CHECK(CheckAlertAuthorization("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T")); - - // Then ignore some sources explicitly - mapMultiArgs["-elysiumalertignoresender"].push_back("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T"); - mapMultiArgs["-elysiumalertignoresender"].push_back("16oDZYCspsczfgKXVj3xyvsxH21NpEj94F"); - BOOST_CHECK(CheckAlertAuthorization("48UM25xTXCxPRwnv36YjjJNaAK4whKR8Rd")); // should still be authorized - BOOST_CHECK(!CheckAlertAuthorization("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T")); - BOOST_CHECK(!CheckAlertAuthorization("16oDZYCspsczfgKXVj3xyvsxH21NpEj94F")); - - mapMultiArgs = mapMultiArgsOriginal; - mapArgs = mapArgsOriginal; -} - -BOOST_AUTO_TEST_CASE(alert_authorize_any_source) -{ - std::map mapArgsOriginal = mapArgs; - std::map > mapMultiArgsOriginal = mapMultiArgs; - - mapArgs["-elysiumalertallowsender"] = ""; - - // Allow any source (e.g. for tests!) - mapMultiArgs["-elysiumalertallowsender"].push_back("any"); - BOOST_CHECK(CheckAlertAuthorization("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T")); - BOOST_CHECK(CheckAlertAuthorization("137uFtQ5EgMsreg4FVvL3xuhjkYGToVPqs")); - BOOST_CHECK(CheckAlertAuthorization("16oDZYCspsczfgKXVj3xyvsxH21NpEj94F")); - - mapMultiArgs = mapMultiArgsOriginal; - mapArgs = mapArgsOriginal; -} - -BOOST_AUTO_TEST_SUITE_END() -*/ \ No newline at end of file diff --git a/src/elysium/test/build_tx_tests.cpp b/src/elysium/test/build_tx_tests.cpp deleted file mode 100644 index 3fee8fbec0..0000000000 --- a/src/elysium/test/build_tx_tests.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "../createtx.h" -#include "../errors.h" -#include "../elysium.h" -#include "../packetencoder.h" -#include "../utilsbitcoin.h" -#include "../wallettxs.h" - -#include "../../base58.h" -#include "../../coins.h" -#include "../../core_io.h" -#include "../../validation.h" -#include "../../utilstrencodings.h" - -#include "../../primitives/transaction.h" - -#include "../../script/script.h" -#include "../../script/standard.h" - -#include "../../test/test_bitcoin.h" -#include "../../test/fixtures.h" - -#include "../../wallet/wallet.h" - -#include -#include - -#include -#include -#include - -#include - -using namespace std; - -namespace elysium { - -BOOST_FIXTURE_TEST_SUITE(elysium_build_tx_tests, ZerocoinTestingSetup200) - -BOOST_AUTO_TEST_CASE(wallettxbuilder_create_normal_c) -{ - std::vector data(80); - - std::string fromAddress = CBitcoinAddress(pubkey.GetID()).ToString(); - - uint256 txid; - std::string rawHex; - BOOST_CHECK_EQUAL( - 0, // No error - elysium::WalletTxBuilder(fromAddress, "", "", 0, data, txid, rawHex, false) - ); - - CMutableTransaction decTx; - BOOST_CHECK(DecodeHexTx(decTx, rawHex)); - - BOOST_CHECK(!CTransaction(decTx).IsSigmaSpend()); - - BOOST_CHECK_EQUAL( - PacketClass::C, - DeterminePacketClass(decTx, chainActive.Height()) - ); -} - -BOOST_AUTO_TEST_CASE(wallettxbuilder_create_sigma_without_mints) -{ - pwalletMain->SetBroadcastTransactions(true); - CreateAndProcessEmptyBlocks(200, scriptPubKey); - - std::vector data(80); - - uint256 txid; - std::string rawHex; - BOOST_CHECK_EQUAL( - MPRPCErrorCode::MP_SIGMA_INPUTS_INVALID, - elysium::WalletTxBuilder("", "", "", 0, data, txid, rawHex, false, elysium::InputMode::SIGMA) - ); -} - -BOOST_AUTO_TEST_CASE(wallettxbuilder_create_sigma_with_toolarge_data) -{ - pwalletMain->SetBroadcastTransactions(true); - - string stringError; - sigma::CoinDenomination denomination; - sigma::StringToDenomination("1", denomination); - const auto& sigmaParams = sigma::Params::get_default(); - std::vector privCoins(10, sigma::PrivateCoin(sigmaParams, denomination)); - - CWalletTx wtx; - vector vDMints; - auto vecSend = CWallet::CreateSigmaMintRecipients(privCoins, vDMints); - stringError = pwalletMain->MintAndStoreSigma(vecSend, privCoins, vDMints, wtx); - - BOOST_CHECK_MESSAGE(stringError == "", "Mint Failed"); - - CreateAndProcessBlock(scriptPubKey); - CreateAndProcessEmptyBlocks(5, scriptPubKey); - - std::vector data(nMaxDatacarrierBytes + 1); - - uint256 txid; - std::string rawHex; - BOOST_CHECK_EQUAL( - MPRPCErrorCode::MP_ENCODING_ERROR, - elysium::WalletTxBuilder("", "", "", 0, data, txid, rawHex, false, elysium::InputMode::SIGMA) - ); -} - -BOOST_AUTO_TEST_CASE(wallettxbuilder_create_sigma_success) -{ - pwalletMain->SetBroadcastTransactions(true); - - string stringError; - sigma::CoinDenomination denomination; - sigma::StringToDenomination("1", denomination); - const auto& sigmaParams = sigma::Params::get_default(); - std::vector privCoins(10, sigma::PrivateCoin(sigmaParams, denomination)); - - CWalletTx wtx; - vector vDMints; - auto vecSend = CWallet::CreateSigmaMintRecipients(privCoins, vDMints); - stringError = pwalletMain->MintAndStoreSigma(vecSend, privCoins, vDMints, wtx); - - BOOST_CHECK_MESSAGE(stringError == "", "Mint Failed"); - - CreateAndProcessBlock(scriptPubKey); - CreateAndProcessEmptyBlocks(5, scriptPubKey); - - std::vector data(80); - - uint256 txid; - std::string rawHex; - BOOST_CHECK_EQUAL( - 0, // No error - elysium::WalletTxBuilder("", "", "", 0, data, txid, rawHex, false, elysium::InputMode::SIGMA) - ); - - CMutableTransaction decTx; - BOOST_CHECK(DecodeHexTx(decTx, rawHex)); - - BOOST_CHECK(CTransaction(decTx).IsSigmaSpend()); - - BOOST_CHECK_EQUAL( - PacketClass::C, - DeterminePacketClass(decTx, chainActive.Height()) - ); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/checkpoint_tests.cpp b/src/elysium/test/checkpoint_tests.cpp deleted file mode 100644 index f0ef8052e2..0000000000 --- a/src/elysium/test/checkpoint_tests.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "elysium/consensushash.h" -#include "elysium/dex.h" -#include "elysium/mdex.h" -#include "elysium/sp.h" -#include "elysium/elysium.h" -#include "elysium/rules.h" -#include "elysium/tally.h" - -#include "arith_uint256.h" -#include "sync.h" -#include "test/test_bitcoin.h" -#include "uint256.h" - -#include - -#include -#include - -namespace elysium -{ -extern std::string GenerateConsensusString(const CMPTally& tallyObj, const std::string& address, const uint32_t propertyId); // done -extern std::string GenerateConsensusString(const CMPOffer& offerObj, const std::string& address); // half -extern std::string GenerateConsensusString(const CMPAccept& acceptObj, const std::string& address); -extern std::string GenerateConsensusString(const CMPMetaDEx& tradeObj); -extern std::string GenerateConsensusString(const CMPCrowd& crowdObj); -extern std::string GenerateConsensusString(const uint32_t propertyId, const std::string& address); -} - -extern void clear_all_state(); - -using namespace elysium; - -BOOST_FIXTURE_TEST_SUITE(elysium_checkpoint_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(consensus_string_tally) -{ - CMPTally tally; - BOOST_CHECK_EQUAL("", GenerateConsensusString(tally, "3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b", 1)); - BOOST_CHECK_EQUAL("", GenerateConsensusString(tally, "3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b", 3)); - - BOOST_CHECK(tally.updateMoney(3, 7, BALANCE)); - BOOST_CHECK_EQUAL("3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b|3|7|0|0|0", - GenerateConsensusString(tally, "3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b", 3)); - - BOOST_CHECK(tally.updateMoney(3, 7, BALANCE)); - BOOST_CHECK(tally.updateMoney(3, 100, SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(3, int64_t(9223372036854775807LL), ACCEPT_RESERVE)); - BOOST_CHECK(tally.updateMoney(3, (-int64_t(9223372036854775807LL)-1), PENDING)); // ignored - BOOST_CHECK(tally.updateMoney(3, int64_t(4294967296L), METADEX_RESERVE)); - BOOST_CHECK_EQUAL("3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b|3|14|100|9223372036854775807|4294967296", - GenerateConsensusString(tally, "3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b", 3)); -} - -BOOST_AUTO_TEST_CASE(consensus_string_offer) -{ - CMPOffer offerA; - BOOST_CHECK_EQUAL("0000000000000000000000000000000000000000000000000000000000000000|3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b|0|0|0|0|0", - GenerateConsensusString(offerA, "3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b")); - - CMPOffer offerB(340000, 3000, 2, 100000, 1000, 10, uint256S("3c9a055899147b03b2c5240a020c1f94d243a834ecc06ab8cfa504ee29d07b7d")); - BOOST_CHECK_EQUAL("3c9a055899147b03b2c5240a020c1f94d243a834ecc06ab8cfa504ee29d07b7d|1HG3s4Ext3sTqBTHrgftyUzG3cvx5ZbPCj|2|3000|100000|1000|10", - GenerateConsensusString(offerB, "1HG3s4Ext3sTqBTHrgftyUzG3cvx5ZbPCj")); -} - -BOOST_AUTO_TEST_CASE(consensus_string_accept) -{ - CMPAccept accept(1234, 1000, 350000, 10, 2, 2000, 4000, uint256S("2c9a055899147b03b2c5240a020c1f94d243a834ecc06ab8cfa504ee29d07b7b")); - BOOST_CHECK_EQUAL("2c9a055899147b03b2c5240a020c1f94d243a834ecc06ab8cfa504ee29d07b7b|3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b|1234|1000|350000", - GenerateConsensusString(accept, "3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b")); -} - -BOOST_AUTO_TEST_CASE(consensus_string_mdex) -{ - CMPMetaDEx tradeA; - BOOST_CHECK_EQUAL("0000000000000000000000000000000000000000000000000000000000000000||0|0|0|0|0", - GenerateConsensusString(tradeA)); - - CMPMetaDEx tradeB("1PxejjeWZc9ZHph7A3SYDo2sk2Up4AcysH", 395000, 31, 1000000, 1, 2000000, - uint256S("2c9a055899147b03b2c5240a020c1f94d243a834ecc06ab8cfa504ee29d07b7d"), 1, 1, 900000); - BOOST_CHECK_EQUAL("2c9a055899147b03b2c5240a020c1f94d243a834ecc06ab8cfa504ee29d07b7d|1PxejjeWZc9ZHph7A3SYDo2sk2Up4AcysH|31|1000000|1|2000000|900000", - GenerateConsensusString(tradeB)); -} - -BOOST_AUTO_TEST_CASE(consensus_string_crowdsale) -{ - CMPCrowd crowdsaleA; - BOOST_CHECK_EQUAL("0|0|0|0|0", - GenerateConsensusString(crowdsaleA)); - - CMPCrowd crowdsaleB(77, 500000, 3, 1514764800, 10, 255, 10000, 25500); - BOOST_CHECK_EQUAL("77|3|1514764800|10000|25500", - GenerateConsensusString(crowdsaleB)); -} - -BOOST_AUTO_TEST_CASE(consensus_string_property_issuer) -{ - BOOST_CHECK_EQUAL("5|3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b", - GenerateConsensusString(5, "3CwZ7FiQ4MqBenRdCkjjc41M5bnoKQGC2b")); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/create_payload_tests.cpp b/src/elysium/test/create_payload_tests.cpp deleted file mode 100644 index b942d91a7b..0000000000 --- a/src/elysium/test/create_payload_tests.cpp +++ /dev/null @@ -1,615 +0,0 @@ -#include "../createpayload.h" -#include "../elysium.h" - -#include "../../test/test_bitcoin.h" -#include "../../utilstrencodings.h" - -#include - -#include -#include - -#include - -namespace elysium { - -BOOST_FIXTURE_TEST_SUITE(elysium_create_payload_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(payload_simple_send) -{ - // Simple send [type 0, version 0] - std::vector vch = CreatePayload_SimpleSend( - static_cast(1), // property: MSC - static_cast(100000000)); // amount to transfer: 1.0 MSC (in willets) - - BOOST_CHECK_EQUAL(HexStr(vch), "00000000000000010000000005f5e100"); -} - -BOOST_AUTO_TEST_CASE(payload_send_to_owners) -{ - // Send to owners [type 3, version 0] (same property) - std::vector vch = CreatePayload_SendToOwners( - static_cast(1), // property: OMNI - static_cast(100000000), // amount to transfer: 1.0 OMNI (in willets) - static_cast(1)); // property: OMNI - - BOOST_CHECK_EQUAL(HexStr(vch), "00000003000000010000000005f5e100"); -} - -BOOST_AUTO_TEST_CASE(payload_send_to_owners_v1) -{ - // Send to owners [type 3, version 1] (cross property) - std::vector vch = CreatePayload_SendToOwners( - static_cast(1), // property: OMNI - static_cast(100000000), // amount to transfer: 1.0 OMNI (in willets) - static_cast(3)); // property: SP#3 - - BOOST_CHECK_EQUAL(HexStr(vch), "00010003000000010000000005f5e10000000003"); -} - -BOOST_AUTO_TEST_CASE(payload_send_all) -{ - // Send to owners [type 4, version 0] - std::vector vch = CreatePayload_SendAll( - static_cast(2)); // ecosystem: Test - - BOOST_CHECK_EQUAL(HexStr(vch), "0000000402"); -} - -BOOST_AUTO_TEST_CASE(payload_dex_offer) -{ - // Sell tokens for bitcoins [type 20, version 1] - std::vector vch = CreatePayload_DExSell( - static_cast(1), // property: MSC - static_cast(100000000), // amount to transfer: 1.0 MSC (in willets) - static_cast(20000000), // amount desired: 0.2 BTC (in satoshis) - static_cast(10), // payment window in blocks - static_cast(10000), // commitment fee in satoshis - static_cast(1)); // sub-action: new offer - - BOOST_CHECK_EQUAL(HexStr(vch), - "00010014000000010000000005f5e1000000000001312d000a000000000000271001"); -} - -BOOST_AUTO_TEST_CASE(payload_meta_dex_new_trade) -{ - // Trade tokens for tokens [type 25, version 0] - std::vector vch = CreatePayload_MetaDExTrade( - static_cast(1), // property: MSC - static_cast(250000000), // amount for sale: 2.5 MSC - static_cast(31), // property desired: TetherUS - static_cast(5000000000)); // amount desired: 50.0 TetherUS - - BOOST_CHECK_EQUAL(HexStr(vch), - "0000001900000001000000000ee6b2800000001f000000012a05f200"); -} - -BOOST_AUTO_TEST_CASE(payload_meta_dex_cancel_at_price) -{ - // Trade tokens for tokens [type 26, version 0] - std::vector vch = CreatePayload_MetaDExCancelPrice( - static_cast(1), // property: MSC - static_cast(250000000), // amount for sale: 2.5 MSC - static_cast(31), // property desired: TetherUS - static_cast(5000000000)); // amount desired: 50.0 TetherUS - - BOOST_CHECK_EQUAL(HexStr(vch), - "0000001a00000001000000000ee6b2800000001f000000012a05f200"); -} - -BOOST_AUTO_TEST_CASE(payload_meta_dex_cancel_pair) -{ - // Trade tokens for tokens [type 27, version 0] - std::vector vch = CreatePayload_MetaDExCancelPair( - static_cast(1), // property: MSC - static_cast(31)); // property desired: TetherUS - - BOOST_CHECK_EQUAL(HexStr(vch), - "0000001b000000010000001f"); -} - -BOOST_AUTO_TEST_CASE(payload_meta_dex_cancel_ecosystem) -{ - // Trade tokens for tokens [type 28, version 0] - std::vector vch = CreatePayload_MetaDExCancelEcosystem( - static_cast(1)); // ecosystem: Main - - BOOST_CHECK_EQUAL(HexStr(vch), - "0000001c01"); -} - -BOOST_AUTO_TEST_CASE(payload_accept_dex_offer) -{ - // Purchase tokens with bitcoins [type 22, version 0] - std::vector vch = CreatePayload_DExAccept( - static_cast(1), // property: MSC - static_cast(130000000)); // amount to transfer: 1.3 MSC (in willets) - - BOOST_CHECK_EQUAL(HexStr(vch), "00000016000000010000000007bfa480"); -} - -BOOST_AUTO_TEST_CASE(payload_create_property) -{ - // Create property [type 50, version 0] - std::vector vch = CreatePayload_IssuanceFixed( - static_cast(1), // ecosystem: main - static_cast(1), // property type: indivisible tokens - static_cast(0), // previous property: none - std::string("Companies"), // category - std::string("Bitcoin Mining"), // subcategory - std::string("Quantum Miner"), // label - std::string("builder.bitwatch.co"), // website - std::string(""), // additional information - static_cast(1000000)); // number of units to create - - BOOST_CHECK_EQUAL(HexStr(vch), - "0000003201000100000000436f6d70616e69657300426974636f696e204d696e696e67" - "005175616e74756d204d696e6572006275696c6465722e62697477617463682e636f00" - "0000000000000f4240"); -} - -BOOST_AUTO_TEST_CASE(payload_create_property_empty) -{ - // Create property [type 50, version 0] - std::vector vch = CreatePayload_IssuanceFixed( - static_cast(1), // ecosystem: main - static_cast(1), // property type: indivisible tokens - static_cast(0), // previous property: none - std::string(""), // category - std::string(""), // subcategory - std::string(""), // label - std::string(""), // website - std::string(""), // additional information - static_cast(1000000)); // number of units to create - - BOOST_CHECK_EQUAL(vch.size(), 24); -} - -BOOST_AUTO_TEST_CASE(payload_create_property_full) -{ - // Create property [type 50, version 0] - std::vector vch = CreatePayload_IssuanceFixed( - static_cast(1), // ecosystem: main - static_cast(1), // property type: indivisible tokens - static_cast(0), // previous property: none - std::string(700, 'x'), // category - std::string(700, 'x'), // subcategory - std::string(700, 'x'), // label - std::string(700, 'x'), // website - std::string(700, 'x'), // additional information - static_cast(1000000)); // number of units to create - - BOOST_CHECK_EQUAL(vch.size(), 1299); -} - -BOOST_AUTO_TEST_CASE(payload_create_crowdsale) -{ - // Create crowdsale [type 51, version 0] - std::vector vch = CreatePayload_IssuanceVariable( - static_cast(1), // ecosystem: main - static_cast(1), // property type: indivisible tokens - static_cast(0), // previous property: none - std::string("Companies"), // category - std::string("Bitcoin Mining"), // subcategory - std::string("Quantum Miner"), // label - std::string("builder.bitwatch.co"), // website - std::string(""), // additional information - static_cast(1), // property desired: MSC - static_cast(100), // tokens per unit vested - static_cast(7731414000L), // deadline: 31 Dec 2214 23:00:00 UTC - static_cast(10), // early bird bonus: 10 % per week - static_cast(12)); // issuer bonus: 12 % - - BOOST_CHECK_EQUAL(HexStr(vch), - "0000003301000100000000436f6d70616e69657300426974636f696e204d696e696e67" - "005175616e74756d204d696e6572006275696c6465722e62697477617463682e636f00" - "0000000001000000000000006400000001ccd403f00a0c"); -} - -BOOST_AUTO_TEST_CASE(payload_create_crowdsale_empty) -{ - // Create crowdsale [type 51, version 0] - std::vector vch = CreatePayload_IssuanceVariable( - static_cast(1), // ecosystem: main - static_cast(1), // property type: indivisible tokens - static_cast(0), // previous property: none - std::string(""), // category - std::string(""), // subcategory - std::string(""), // label - std::string(""), // website - std::string(""), // additional information - static_cast(1), // property desired: MSC - static_cast(100), // tokens per unit vested - static_cast(7731414000L), // deadline: 31 Dec 2214 23:00:00 UTC - static_cast(10), // early bird bonus: 10 % per week - static_cast(12)); // issuer bonus: 12 % - - BOOST_CHECK_EQUAL(vch.size(), 38); -} - -BOOST_AUTO_TEST_CASE(payload_create_crowdsale_full) -{ - // Create crowdsale [type 51, version 0] - std::vector vch = CreatePayload_IssuanceVariable( - static_cast(1), // ecosystem: main - static_cast(1), // property type: indivisible tokens - static_cast(0), // previous property: none - std::string(700, 'x'), // category - std::string(700, 'x'), // subcategory - std::string(700, 'x'), // label - std::string(700, 'x'), // website - std::string(700, 'x'), // additional information - static_cast(1), // property desired: MSC - static_cast(100), // tokens per unit vested - static_cast(7731414000L), // deadline: 31 Dec 2214 23:00:00 UTC - static_cast(10), // early bird bonus: 10 % per week - static_cast(12)); // issuer bonus: 12 % - - BOOST_CHECK_EQUAL(vch.size(), 1313); -} - -BOOST_AUTO_TEST_CASE(payload_close_crowdsale) -{ - // Close crowdsale [type 53, version 0] - std::vector vch = CreatePayload_CloseCrowdsale( - static_cast(9)); // property: SP #9 - - BOOST_CHECK_EQUAL(HexStr(vch), "0000003500000009"); -} - -BOOST_AUTO_TEST_CASE(payload_create_managed_property) -{ - // create managed property [type 54, version 0] - std::vector vch = CreatePayload_IssuanceManaged( - static_cast(1), // ecosystem: main - static_cast(1), // property type: indivisible tokens - static_cast(0), // previous property: none - std::string("Companies"), // category - std::string("Bitcoin Mining"), // subcategory - std::string("Quantum Miner"), // label - std::string("builder.bitwatch.co"), // website - std::string("")); // additional information - - BOOST_CHECK_EQUAL(HexStr(vch), - "0000003601000100000000436f6d70616e69657300426974636f696e204d696e696e67" - "005175616e74756d204d696e6572006275696c6465722e62697477617463682e636f00" - "00"); -} - -BOOST_AUTO_TEST_CASE(payload_create_managed_property_empty) -{ - // create managed property [type 54, version 0] - std::vector vch = CreatePayload_IssuanceManaged( - static_cast(1), // ecosystem: main - static_cast(1), // property type: indivisible tokens - static_cast(0), // previous property: none - std::string(""), // category - std::string(""), // subcategory - std::string(""), // label - std::string(""), // website - std::string("")); // additional information - - BOOST_CHECK_EQUAL(vch.size(), 16); -} - -BOOST_AUTO_TEST_CASE(payload_create_managed_property_full) -{ - // create managed property [type 54, version 0] - std::vector vch = CreatePayload_IssuanceManaged( - static_cast(1), // ecosystem: main - static_cast(1), // property type: indivisible tokens - static_cast(0), // previous property: none - std::string(700, 'x'), // category - std::string(700, 'x'), // subcategory - std::string(700, 'x'), // label - std::string(700, 'x'), // website - std::string(700, 'x')); // additional information - - BOOST_CHECK_EQUAL(vch.size(), 1291); -} - -BOOST_AUTO_TEST_CASE(payload_grant_tokens) -{ - // Grant tokens [type 55, version 0] - std::vector vch = CreatePayload_Grant( - static_cast(8), // property: SP #8 - static_cast(1000), // number of units to issue - std::string("First Milestone Reached!")); // additional information - - BOOST_CHECK_EQUAL(HexStr(vch), - "000000370000000800000000000003e84669727374204d696c6573746f6e6520526561" - "636865642100"); -} - -BOOST_AUTO_TEST_CASE(payload_grant_tokens_empty) -{ - // Grant tokens [type 55, version 0] - std::vector vch = CreatePayload_Grant( - static_cast(8), // property: SP #8 - static_cast(1000), // number of units to issue - std::string("")); // additional information - - BOOST_CHECK_EQUAL(vch.size(), 17); -} - -BOOST_AUTO_TEST_CASE(payload_grant_tokens_full) -{ - // Grant tokens [type 55, version 0] - std::vector vch = CreatePayload_Grant( - static_cast(8), // property: SP #8 - static_cast(1000), // number of units to issue - std::string(700, 'x')); // additional information - - BOOST_CHECK_EQUAL(vch.size(), 272); -} - -BOOST_AUTO_TEST_CASE(payload_revoke_tokens) -{ - // Revoke tokens [type 56, version 0] - std::vector vch = CreatePayload_Revoke( - static_cast(8), // property: SP #8 - static_cast(1000), // number of units to revoke - std::string("Redemption of tokens for Bob, Thanks Bob!")); // additional information - - BOOST_CHECK_EQUAL(HexStr(vch), - "000000380000000800000000000003e8526564656d7074696f6e206f6620746f6b656e" - "7320666f7220426f622c205468616e6b7320426f622100"); -} - -BOOST_AUTO_TEST_CASE(payload_revoke_tokens_empty) -{ - // Revoke tokens [type 56, version 0] - std::vector vch = CreatePayload_Revoke( - static_cast(8), // property: SP #8 - static_cast(1000), // number of units to revoke - std::string("")); // additional information - - BOOST_CHECK_EQUAL(vch.size(), 17); -} - -BOOST_AUTO_TEST_CASE(payload_revoke_tokens_full) -{ - // Revoke tokens [type 56, version 0] - std::vector vch = CreatePayload_Revoke( - static_cast(8), // property: SP #8 - static_cast(1000), // number of units to revoke - std::string(700, 'x')); // additional information - - BOOST_CHECK_EQUAL(vch.size(), 272); -} - -BOOST_AUTO_TEST_CASE(payload_change_property_manager) -{ - // Change property manager [type 70, version 0] - std::vector vch = CreatePayload_ChangeIssuer( - static_cast(13)); // property: SP #13 - - BOOST_CHECK_EQUAL(HexStr(vch), "000000460000000d"); -} - -BOOST_AUTO_TEST_CASE(payload_enable_freezing) -{ - // Enable freezing [type 71, version 0] - std::vector vch = CreatePayload_EnableFreezing( - static_cast(4)); // property: SP #4 - - BOOST_CHECK_EQUAL(HexStr(vch), "0000004700000004"); -} - -BOOST_AUTO_TEST_CASE(payload_disable_freezing) -{ - // Disable freezing [type 72, version 0] - std::vector vch = CreatePayload_DisableFreezing( - static_cast(4)); // property: SP #4 - - BOOST_CHECK_EQUAL(HexStr(vch), "0000004800000004"); -} - -BOOST_AUTO_TEST_CASE(payload_freeze_tokens) -{ - // Freeze tokens [type 185, version 0] - std::vector vch = CreatePayload_FreezeTokens( - static_cast(4), // property: SP #4 - static_cast(1000), // amount to freeze (unused) - std::string("1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P")); // reference address - - BOOST_CHECK_EQUAL(HexStr(vch), - "000000b90000000400000000000003e800946cb2e08075bcbaf157e47bcb67eb2b2339d242"); -} - -BOOST_AUTO_TEST_CASE(payload_unfreeze_tokens) -{ - // Freeze tokens [type 186, version 0] - std::vector vch = CreatePayload_UnfreezeTokens( - static_cast(4), // property: SP #4 - static_cast(1000), // amount to freeze (unused) - std::string("1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P")); // reference address - - BOOST_CHECK_EQUAL(HexStr(vch), - "000000ba0000000400000000000003e800946cb2e08075bcbaf157e47bcb67eb2b2339d242"); -} - -BOOST_AUTO_TEST_CASE(payload_feature_deactivation) -{ - // Elysium Core feature activation [type 65533, version 65535] - std::vector vch = CreatePayload_DeactivateFeature( - static_cast(1)); // feature identifier: 1 (OP_RETURN) - - BOOST_CHECK_EQUAL(HexStr(vch), "fffffffd0001"); -} - -BOOST_AUTO_TEST_CASE(payload_feature_activation) -{ - // Elysium Core feature activation [type 65534, version 65535] - std::vector vch = CreatePayload_ActivateFeature( - static_cast(1), // feature identifier: 1 (OP_RETURN) - static_cast(370000), // activation block - static_cast(999)); // min client version - - BOOST_CHECK_EQUAL(HexStr(vch), "fffffffe00010005a550000003e7"); -} - -BOOST_AUTO_TEST_CASE(payload_elysium_alert_block) -{ - // Elysium Core client notification [type 65535, version 65535] - std::vector vch = CreatePayload_ElysiumAlert( - static_cast(1), // alert target: by block number - static_cast(300000), // expiry value: 300000 - static_cast("test")); // alert message: test - - BOOST_CHECK_EQUAL(HexStr(vch), "ffffffff0001000493e07465737400"); -} - -BOOST_AUTO_TEST_CASE(payload_elysium_alert_blockexpiry) -{ - // Elysium Core client notification [type 65535, version 65535] - std::vector vch = CreatePayload_ElysiumAlert( - static_cast(2), // alert target: by block time - static_cast(1439528630), // expiry value: 1439528630 - static_cast("test")); // alert message: test - - BOOST_CHECK_EQUAL(HexStr(vch), "ffffffff000255cd76b67465737400"); -} - -BOOST_AUTO_TEST_CASE(payload_elysium_alert_minclient) -{ - // Elysium Core client notification [type 65535, version 65535] - std::vector vch = CreatePayload_ElysiumAlert( - static_cast(3), // alert target: by client version - static_cast(900100), // expiry value: v0.0.9.1 - static_cast("test")); // alert message: test - - BOOST_CHECK_EQUAL(HexStr(vch), "ffffffff0003000dbc047465737400"); -} - -BOOST_AUTO_TEST_CASE(payload_create_denomination) -{ - // Simple send [type 1025, version 0] - std::vector vch = CreatePayload_CreateDenomination( - static_cast(1), // property: MSC - static_cast(100000000)); // value of denomination: 1.0 MSC (in willets) - - BOOST_CHECK_EQUAL(HexStr(vch), "00000401000000010000000005f5e100"); -} - -BOOST_AUTO_TEST_CASE(payload_create_simple_mint) -{ - std::string data = "40a2bc96cfd3911902843529cd674472b423164756eef7f7845fdfdc3a548f620100"; - std::string data2 = "7cbfec8ffd9b56c607c94975f90f95b3aaa84422357ceb293b6b0c42d2d7bb920000"; - - elysium::SigmaPublicKey publicKey, publicKey2; - CDataStream(ParseHex(data), SER_NETWORK, CLIENT_VERSION) >> publicKey; - CDataStream(ParseHex(data2), SER_NETWORK, CLIENT_VERSION) >> publicKey2; - - // Simple mint [type 1026, version 0] - std::vector vch = CreatePayload_SimpleMint( - static_cast(1), // property: MSC - { - std::make_pair(0, publicKey), - std::make_pair(1, publicKey2) - } - ); - - BOOST_CHECK_EQUAL(HexStr(vch), - "0000040200000001020040a2bc96cfd3911902843529cd674472b423164756eef7f7845fdfdc3a548f620100" \ - "017cbfec8ffd9b56c607c94975f90f95b3aaa84422357ceb293b6b0c42d2d7bb920000" - ); -} - -BOOST_AUTO_TEST_CASE(payload_create_simple_mint_no_mints) -{ - // Simple mint [type 1026, version 0] - BOOST_CHECK_EXCEPTION( - CreatePayload_SimpleMint( - static_cast(1), - {} - ), - std::invalid_argument, - [](const std::invalid_argument& e) { - return std::string("no mints provided") == e.what(); - } - ); -} - -BOOST_AUTO_TEST_CASE(payload_create_simple_mint_exceed_limit) -{ - std::vector> pubs; - pubs.resize(ELYSIUM_MAX_SIMPLE_MINTS + 1); - - // Simple mint [type 1026, version 0] - BOOST_CHECK_EXCEPTION( - CreatePayload_SimpleMint( - static_cast(1), - pubs - ), - std::invalid_argument, - [](const std::invalid_argument& e) { - return std::string("amount of mints exceeded limit") == e.what(); - } - ); -} - -BOOST_AUTO_TEST_CASE(payload_create_simple_spend) -{ - auto& params = DefaultSigmaParams; - SigmaPrivateKey key1, key2; - std::vector anonimitySet; - SigmaProof spend(params); - CDataStream buffer(SER_DISK, CLIENT_VERSION); - - key1.Generate(); - key2.Generate(); - anonimitySet = { SigmaPublicKey(key1, params), SigmaPublicKey(key2, params) }; - spend.Generate(key1, anonimitySet.begin(), anonimitySet.end(), false); - buffer << key1.serial; - buffer << spend; - - std::vector payload; - BOOST_CHECK_NO_THROW( - payload = CreatePayload_SimpleSpend(1, 2, 3, anonimitySet.size(), spend, key1.serial) - ); - - BOOST_CHECK_EQUAL( - HexStr(payload), - "000004000000000102000000030002" + HexStr(buffer.vch) - ); -} - -BOOST_AUTO_TEST_CASE(payload_create_simple_spendv1) -{ - auto& params = DefaultSigmaParams; - SigmaPrivateKey key1, key2; - std::vector anonimitySet; - SigmaProof spend(params); - CDataStream buffer(SER_DISK, CLIENT_VERSION); - - std::array rawSignature; - std::array publicKey; - - std::fill(rawSignature.begin(), rawSignature.end(), 0x11); - std::fill(publicKey.begin(), publicKey.end(), 0xFF); - publicKey[0] = 0x02; // Compressed - - auto signature = ECDSASignature::ParseCompact(ECDSAContext::CreateSignContext(), rawSignature.begin()); - - key1.Generate(); - key2.Generate(); - anonimitySet = { SigmaPublicKey(key1, params), SigmaPublicKey(key2, params) }; - spend.Generate(key1, anonimitySet.begin(), anonimitySet.end(), false); - buffer << spend.proof; - - std::vector payload; - BOOST_CHECK_NO_THROW( - payload = CreatePayload_SimpleSpend(1, 2, 3, anonimitySet.size(), spend, signature, CPubKey(publicKey.begin(), publicKey.end())) - ); - - BOOST_CHECK_EQUAL( - HexStr(payload), - "000104000000000102000000030002" + - HexStr(publicKey) + HexStr(buffer.vch) + HexStr(rawSignature) - ); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/create_tx_tests.cpp b/src/elysium/test/create_tx_tests.cpp deleted file mode 100644 index df6ac0aa65..0000000000 --- a/src/elysium/test/create_tx_tests.cpp +++ /dev/null @@ -1,269 +0,0 @@ -#include "elysium/createtx.h" - -#include "base58.h" -#include "coins.h" -#include "core_io.h" -#include "validation.h" -#include "primitives/transaction.h" -#include "script/script.h" -#include "script/standard.h" -#include "test/test_bitcoin.h" -#include "utilstrencodings.h" - -#include - -#include -#include -#include -#include - -// Is resetted after the last test -extern CFeeRate minRelayTxFee; -static CFeeRate minRelayTxFeeOriginal = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); - -BOOST_FIXTURE_TEST_SUITE(elysium_create_tx_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(txbuilder_empty) -{ - TxBuilder builder; - CMutableTransaction tx = builder.build(); - - BOOST_CHECK_EQUAL("01000000000000000000", EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(txbuilder_from_existing) -{ - std::string rawTx("0100000001ea6f7b27245fb97eca56c942600b31102d42ef2cc04b3990e63fea9619e137110300000000" - "ffffffff0141e40000000000001976a9140b15428b98e6a459cc2ffeed085153dc1bc8078188ac00000000"); - - CMutableTransaction txBasis; - BOOST_CHECK(DecodeHexTx(txBasis, rawTx)); - - CMutableTransaction tx = TxBuilder(txBasis).build(); - BOOST_CHECK_EQUAL(rawTx, EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(txbuilder_add_outpoint) -{ - std::string rawTx("010000000270ef6bf12e5155116532c4696e59c354d39c639db7498ce86f1e479b4ac6fbdd0200000000" - "ffffffff50259f6673c372006ffa6f52309bc3b68501e3dbdaadc910b81846a0202792b10000000000ffffffff00000000" - "00"); - - CMutableTransaction tx = TxBuilder() - .addInput(COutPoint(uint256S("ddfbc64a9b471e6fe88c49b79d639cd354c3596e69c432651155512ef16bef70"), 2)) - .addInput(COutPoint(uint256S("b1922720a04618b810c9addadbe30185b6c39b30526ffa6f0072c373669f2550"), 0)) - .build(); - - BOOST_CHECK_EQUAL(rawTx, EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(txbuilder_add_input) -{ - std::string rawTx("010000000270ef6bf12e5155116532c4696e59c354d39c639db7498ce86f1e479b4ac6fbdd0200000000" - "ffffffff50259f6673c372006ffa6f52309bc3b68501e3dbdaadc910b81846a0202792b10000000000ffffffff00000000" - "00"); - - CMutableTransaction tx = TxBuilder() - .addInput(uint256S("ddfbc64a9b471e6fe88c49b79d639cd354c3596e69c432651155512ef16bef70"), 2) - .addInput(uint256S("b1922720a04618b810c9addadbe30185b6c39b30526ffa6f0072c373669f2550"), 0) - .build(); - - BOOST_CHECK_EQUAL(rawTx, EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(txbuilder_add_output) -{ - std::string rawTxBasis("0100000001bfdad3c09f11cdff041295dc83cf4df8a76a8478b73ab3bf6695e37f8068c20800000" - "00000ffffffff0100e1f505000000001976a9140a45d5830d00b972fe00f92f919889875ec5437e88ac00000000"); - std::string rawTx("0100000001bfdad3c09f11cdff041295dc83cf4df8a76a8478b73ab3bf6695e37f8068c2080000000000" - "ffffffff0200e1f505000000001976a9140a45d5830d00b972fe00f92f919889875ec5437e88ac008d1418000000001976" - "a9140e609a27d6389989a0fa7ffaac1ae8ad3e92650e88ac00000000"); - std::vector script = ParseHex("76a9140e609a27d6389989a0fa7ffaac1ae8ad3e92650e88ac"); - - CMutableTransaction txBasis; - BOOST_CHECK(DecodeHexTx(txBasis, rawTxBasis)); - - CMutableTransaction tx = TxBuilder(txBasis) - .addOutput(CScript(script.begin(), script.end()), 404000000LL) - .build(); - - BOOST_CHECK_EQUAL(rawTx, EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(txbuilder_add_outputs) -{ - std::string rawTx("0100000000031203000000000000695121028f925841f1a8090b6d98e3272eacda571f9dceec50c9ca0b" - "24d1d7da57a3ab4821020abd5dadd6326adab819bc643ab7c6f30af81fcfe6ba2cb0ac697a8bba67288a2102ecb5ba7bcc" - "e4579855c9e5f250a90747433f79c080cd6865c6163012dbe6434353ae22020000000000001976a914643ce12b15906330" - "77b8620316f43a9362ef18e588acfc150f00000000001976a9142123d4b097b822b58c3798c1a01cebf0b0ff6edc88ac00" - "000000"); - std::vector scriptA = ParseHex("5121028f925841f1a8090b6d98e3272eacda571f9dceec50c9ca0b24" - "d1d7da57a3ab4821020abd5dadd6326adab819bc643ab7c6f30af81fcfe6ba2cb0ac697a8bba67288a2102ecb5ba7bcce4" - "579855c9e5f250a90747433f79c080cd6865c6163012dbe6434353ae"); - std::vector scriptB = ParseHex("76a914643ce12b1590633077b8620316f43a9362ef18e588ac"); - std::vector scriptC = ParseHex("76a9142123d4b097b822b58c3798c1a01cebf0b0ff6edc88ac"); - - std::vector > outputs; - outputs.push_back(std::make_pair(CScript(scriptA.begin(), scriptA.end()), 786LL)); - outputs.push_back(std::make_pair(CScript(scriptB.begin(), scriptB.end()), 546LL)); - outputs.push_back(std::make_pair(CScript(scriptC.begin(), scriptC.end()), 988668LL)); - - TxBuilder builder; - builder.addOutputs(outputs); - - CMutableTransaction tx = builder.build(); - BOOST_CHECK_EQUAL(rawTx, EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(txbuilder_add_change) -{ - std::string rawTx("0100000002605842f019601de54248b9fb4a32b498a7762c6513213b39041fbd89890e3a010200000000" - "ffffffff878b454ca384a37d72762477406003397ed90b1f8d5ad4061af29ee541162c260000000000ffffffff0280d1f0" - "08000000001976a91474da251d772d3a0dad3ef97d6a5e35892975542a88ac5622b701000000001976a9145d66ebf06ac9" - "2ecd1ec6c3b67550379bea86885688ac00000000"); - std::vector scriptA = ParseHex("76a9146093da1c808a3a93c7c729ef9b09e9a29bcfc9ed88ac"); - std::vector scriptB = ParseHex("21036f617ea0d03059cfaf9959b35717906a131a69b1438cc0eaa026" - "5ddb5faf95dcac"); - - std::vector prevTxs; - prevTxs.push_back(PrevTxsEntry( - uint256S("013a0e8989bd1f04393b2113652c76a798b4324afbb94842e51d6019f0425860"), - 2, - 99967336LL, - CScript(scriptA.begin(), scriptA.end()))); - prevTxs.push_back(PrevTxsEntry( - uint256S("262c1641e59ef21a06d45a8d1f0bd97e39036040772476727da384a34c458b87"), - 0, - 78825000LL, - CScript(scriptB.begin(), scriptB.end()))); - - CBitcoinAddress addrA("aBNKT8rnDdiTymZb5GjgoSrpuFt9c6E4V6"); - CBitcoinAddress addrB("a9EKssBGHFP6ZnZm98pb64sT1xxyeZCjM7"); - - CCoinsView viewDummy; - CCoinsViewCache viewTemp(&viewDummy); - InputsToView(prevTxs, viewTemp); - - CMutableTransaction tx = TxBuilder() - .addInput(prevTxs[0].outPoint) - .addOutput(GetScriptForDestination(addrA.Get()), 150000000LL) - .addInput(prevTxs[1].outPoint) - .build(); - - BOOST_CHECK(viewTemp.HaveInputs(CTransaction(tx))); - - tx = TxBuilder(tx) - .addChange(addrB.Get(), viewTemp, 13242LL) - .build(); - - BOOST_CHECK_EQUAL(rawTx, EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(txbuilder_add_change_position) -{ - std::string rawTxBasis("0100000001e83e80ce7b1c618bb21acc4ffdf1f420998a2dea7f6f974edae7e5f3dd28be4401000" - "00000ffffffff028058840c000000001976a914390ba459d1746d49221e031e5038b78e0d99e7b688ac80778e060000000" - "01976a914c656177b31a1cf5f9f319ce67c6de16bb56922b788ac00000000"); - std::string rawTx("0100000001e83e80ce7b1c618bb21acc4ffdf1f420998a2dea7f6f974edae7e5f3dd28be440100000000" - "ffffffff038058840c000000001976a914390ba459d1746d49221e031e5038b78e0d99e7b688acb0d1b90a000000001976" - "a91474da251d772d3a0dad3ef97d6a5e35892975542a88ac80778e06000000001976a914c656177b31a1cf5f9f319ce67c" - "6de16bb56922b788ac00000000"); - std::vector script = ParseHex("76a91453d3a1e3aa03063d660d769acbe2be84821a0b1388ac"); - - std::vector prevTxs; - prevTxs.push_back(PrevTxsEntry( - uint256S("44be28ddf3e5e7da4e976f7fea2d8a9920f4f1fd4fcc1ab28b611c7bce803ee8"), - 1, - 500000000LL, - CScript(script.begin(), script.end()))); - - CBitcoinAddress addr("aBNKT8rnDdiTymZb5GjgoSrpuFt9c6E4V6"); - - CMutableTransaction txBasis; - BOOST_CHECK(DecodeHexTx(txBasis, rawTxBasis)); - - CCoinsView viewDummy; - CCoinsViewCache viewTemp(&viewDummy); - InputsToView(prevTxs, viewTemp); - BOOST_CHECK(viewTemp.HaveInputs(CTransaction(txBasis))); - - CMutableTransaction tx = TxBuilder(txBasis) - .addChange(addr.Get(), viewTemp, 50000LL, 1) - .build(); - - BOOST_CHECK_EQUAL(rawTx, EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(elysiumtxbuilder_empty) -{ - ElysiumTxBuilder builder; - CMutableTransaction tx = builder.build(); - - BOOST_CHECK_EQUAL("01000000000000000000", EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(elysiumtxbuilder_from_existing) -{ - std::string rawTx("01000000017f63a90b9f89c1ad0616825d2565050e53ef044721f58822148193da511e76f8010000006b" - "483045022100c135ed7eb933d97e59ea758e394f93a83ddc5861277da3ccfd28bd77d02d55c70220568e4255aa69fdb860" - "7c54aeed434d6bb5ee6b5f2f0aa9886526e6b99af427320121037e60c8486de3b67c931b6ef9b07e814e58d027ff0134a9" - "da45b5e3ae97ebc6e7ffffffff02d058ea05000000001976a914616cfeaf60ed1a4831dfa238f6e8c676e660aa9588ac00" - "00000000000000166a146f6d6e6900000003000000260000001cede08a8000000000"); - - CMutableTransaction txBasis; - BOOST_CHECK(DecodeHexTx(txBasis, rawTx)); - - CMutableTransaction tx = ElysiumTxBuilder(txBasis).build(); - BOOST_CHECK_EQUAL(rawTx, EncodeHexTx(CTransaction(tx))); -} - -BOOST_AUTO_TEST_CASE(elysiumtxbuilder_op_return) -{ - minRelayTxFee = CFeeRate(1000); - - std::string rawTx("01000000021dc7f242305900960a80cadd2a5d06d2cbbc4bbdd029db37c56a975487b8d4b20100000000" - "fffffffff1c05e491be9b9c73b918e96b0774d0db4632b41ace5bfbc2fcb0a58561b02bc0200000000ffffffff03000000" - "0000000000186a1665786f6475730000000000000001000000009502f9006449f605000000001976a9145d66ebf06ac92e" - "cd1ec6c3b67550379bea86885688acaa0a0000000000001976a91474da251d772d3a0dad3ef97d6a5e35892975542a88ac" - "00000000"); - std::vector scriptA = ParseHex("76a914c359d7d2e140127dd2adbeb1b3e9fa644e7dbd8e88ac"); - std::vector scriptB = ParseHex("76a914c359d7d2e140127dd2adbeb1b3e9fa644e7dbd8e88ac"); - std::vector payload = ParseHex("0000000000000001000000009502f900"); - - std::vector prevTxs; - prevTxs.push_back(PrevTxsEntry( - uint256S("b2d4b88754976ac537db29d0bd4bbccbd2065d2addca800a9600593042f2c71d"), - 1, - 50000LL, - CScript(scriptA.begin(), scriptA.end()))); - prevTxs.push_back(PrevTxsEntry( - uint256S("bc021b56580acb2fbcbfe5ac412b63b40d4d77b0968e913bc7b9e91b495ec0f1"), - 2, - 99989454LL, - CScript(scriptB.begin(), scriptB.end()))); - - CCoinsView viewDummy; - CCoinsViewCache viewTemp(&viewDummy); - InputsToView(prevTxs, viewTemp); - - CMutableTransaction tx = ElysiumTxBuilder() - .addInputs(prevTxs) - .build(); - - BOOST_CHECK(viewTemp.HaveInputs(CTransaction(tx))); - - tx = ElysiumTxBuilder(tx) - .addOpReturn(payload) - .addReference("aBNKT8rnDdiTymZb5GjgoSrpuFt9c6E4V6", 2730LL) - .addChange("a9EKssBGHFP6ZnZm98pb64sT1xxyeZCjM7", viewTemp, 10000LL, 1) - .build(); - - BOOST_CHECK_EQUAL(rawTx, EncodeHexTx(CTransaction(tx))); - - minRelayTxFee = minRelayTxFeeOriginal; -} - -// TODO: test addMultisig -- currently an issue due to the non-deterministic ECDSA point manipulation - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/crowdsale_participation_tests.cpp b/src/elysium/test/crowdsale_participation_tests.cpp deleted file mode 100644 index 69434cdcc9..0000000000 --- a/src/elysium/test/crowdsale_participation_tests.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "elysium/sp.h" - -#include "test/test_bitcoin.h" - -#include - -#include -#include -#include - -BOOST_FIXTURE_TEST_SUITE(elysium_crowdsale_participation_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(overpayment_close) -{ - // - // txid: eda3d2bbb8125397f4d4909ea25d845dc451e8a3206035bf0d736bb3ece5d758 - // - // http://builder.bitwatch.co/?version=1&type=51&ecosystem=2&property_type=2& - // currency_identifier=0&text=436f696e436f696e00&text=436f696e436f696e00& - // text=43726f7764436f696e00&text=687474703a2f2f616c6c746865636f696e2e757300& - // text=69646b00¤cy_identifier=2&number_of_coins=3133700000000& - // timestamp=1407064860000&percentage=6&percentage=10 - // - int64_t amountPerUnitInvested = 3133700000000LL; - int64_t deadline = 1407064860000LL; - uint8_t earlyBirdBonus = 6; - uint8_t issuerBonus = 10; - - // - // txid: 8fbd96005aba5671daf8288f89df8026a7ce4782a0bb411937537933956b827b - // - int64_t timestamp = 1407877014LL; - int64_t amountInvested = 3000000000LL; - - int64_t totalTokens = 0; - std::pair tokensCreated; - bool fClosed = false; - - elysium::calculateFundraiser(true, amountInvested, earlyBirdBonus, deadline, - timestamp, amountPerUnitInvested, issuerBonus, totalTokens, - tokensCreated, fClosed); - - BOOST_CHECK(fClosed); - BOOST_CHECK_EQUAL(8384883669867978007LL, tokensCreated.first); // user - BOOST_CHECK_EQUAL(838488366986797800LL, tokensCreated.second); // issuer -} - -BOOST_AUTO_TEST_CASE(max_limits) -{ - int64_t amountPerUnitInvested = std::numeric_limits::max(); - int64_t deadline = std::numeric_limits::max(); - uint8_t earlyBirdBonus = std::numeric_limits::max(); - uint8_t issuerBonus = std::numeric_limits::max(); - - int64_t timestamp = 0; - int64_t amountInvested = std::numeric_limits::max(); - - int64_t totalTokens = std::numeric_limits::max() - 1LL; - std::pair tokensCreated; - bool fClosed = false; - - elysium::calculateFundraiser(true, amountInvested, earlyBirdBonus, deadline, - timestamp, amountPerUnitInvested, issuerBonus, totalTokens, - tokensCreated, fClosed); - - BOOST_CHECK(fClosed); - BOOST_CHECK_EQUAL(1, tokensCreated.first); // user - BOOST_CHECK_EQUAL(0, tokensCreated.second); // issuer -} - -BOOST_AUTO_TEST_CASE(negative_time) -{ - int64_t amountPerUnitInvested = 50; - int64_t deadline = 500000000; - uint8_t earlyBirdBonus = 255; - uint8_t issuerBonus = 19; - - int64_t timestamp = 500007119; - int64_t amountInvested = 1000000000L; - - int64_t totalTokens = 0; - std::pair tokensCreated; - bool fClosed = false; - - elysium::calculateFundraiser(false, amountInvested, earlyBirdBonus, deadline, - timestamp, amountPerUnitInvested, issuerBonus, totalTokens, - tokensCreated, fClosed); - - BOOST_CHECK(!fClosed); - BOOST_CHECK_EQUAL(500, tokensCreated.first); // user - BOOST_CHECK_EQUAL(95, tokensCreated.second); // issuer -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/dex_purchase_tests.cpp b/src/elysium/test/dex_purchase_tests.cpp deleted file mode 100644 index bf37bfeb4a..0000000000 --- a/src/elysium/test/dex_purchase_tests.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "elysium/dex.h" - -#include "test/test_bitcoin.h" - -#include - -#include - -// forward declaration -namespace elysium { -extern int64_t calculateDExPurchase(const int64_t amountOffered, const int64_t amountDesired, const int64_t amountPaid); -} - -using elysium::calculateDExPurchase; - -BOOST_FIXTURE_TEST_SUITE(elysium_dex_purchase_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(purchase_amount_exact) -{ - const int64_t MAX = 9223372036854775807LL; - - BOOST_CHECK_EQUAL(0, calculateDExPurchase(1, 1, 0)); - BOOST_CHECK_EQUAL(1, calculateDExPurchase(1, 1, 1)); - BOOST_CHECK_EQUAL(2, calculateDExPurchase(4, 8, 4)); - BOOST_CHECK_EQUAL(3, calculateDExPurchase(9, 9, 3)); - BOOST_CHECK_EQUAL(7, calculateDExPurchase(MAX, MAX, 7)); - BOOST_CHECK_EQUAL(MAX, calculateDExPurchase(MAX, 1, 1)); - BOOST_CHECK_EQUAL(MAX, calculateDExPurchase(MAX, MAX, MAX)); -} - -BOOST_AUTO_TEST_CASE(purchase_amount_ladder) -{ - const int64_t MAX = 9223372036854775807LL; - - BOOST_CHECK_EQUAL(1, calculateDExPurchase(MAX, MAX, 1)); - BOOST_CHECK_EQUAL(10, calculateDExPurchase(MAX, MAX, 10)); - BOOST_CHECK_EQUAL(100, calculateDExPurchase(MAX, MAX, 100)); - BOOST_CHECK_EQUAL(1000, calculateDExPurchase(MAX, MAX, 1000)); - BOOST_CHECK_EQUAL(10000, calculateDExPurchase(MAX, MAX, 10000)); - BOOST_CHECK_EQUAL(100000L, calculateDExPurchase(MAX, MAX, 100000L)); - BOOST_CHECK_EQUAL(1000000L, calculateDExPurchase(MAX, MAX, 1000000L)); - BOOST_CHECK_EQUAL(10000000L, calculateDExPurchase(MAX, MAX, 10000000L)); - BOOST_CHECK_EQUAL(100000000L, calculateDExPurchase(MAX, MAX, 100000000L)); - BOOST_CHECK_EQUAL(1000000000L, calculateDExPurchase(MAX, MAX, 1000000000L)); - BOOST_CHECK_EQUAL(10000000000LL, calculateDExPurchase(MAX, MAX, 10000000000LL)); - BOOST_CHECK_EQUAL(100000000000LL, calculateDExPurchase(MAX, MAX, 100000000000LL)); - BOOST_CHECK_EQUAL(1000000000000LL, calculateDExPurchase(MAX, MAX, 1000000000000LL)); - BOOST_CHECK_EQUAL(10000000000000LL, calculateDExPurchase(MAX, MAX, 10000000000000LL)); - BOOST_CHECK_EQUAL(100000000000000LL, calculateDExPurchase(MAX, MAX, 100000000000000LL)); - BOOST_CHECK_EQUAL(1000000000000000LL, calculateDExPurchase(MAX, MAX, 1000000000000000LL)); - BOOST_CHECK_EQUAL(10000000000000000LL, calculateDExPurchase(MAX, MAX, 10000000000000000LL)); - BOOST_CHECK_EQUAL(100000000000000000LL, calculateDExPurchase(MAX, MAX, 100000000000000000LL)); - BOOST_CHECK_EQUAL(1000000000000000000LL, calculateDExPurchase(MAX, MAX, 1000000000000000000LL)); - BOOST_CHECK_EQUAL(2345678901234567890LL, calculateDExPurchase(MAX, MAX, 2345678901234567890LL)); - BOOST_CHECK_EQUAL(3333333333333333333LL, calculateDExPurchase(MAX, MAX, 3333333333333333333LL)); - BOOST_CHECK_EQUAL(4008001500160023042LL, calculateDExPurchase(MAX, MAX, 4008001500160023042LL)); - BOOST_CHECK_EQUAL(5000000000000000001LL, calculateDExPurchase(MAX, MAX, 5000000000000000001LL)); - BOOST_CHECK_EQUAL(6777677767776777677LL, calculateDExPurchase(MAX, MAX, 6777677767776777677LL)); - BOOST_CHECK_EQUAL(7107297387477567653LL, calculateDExPurchase(MAX, MAX, 7107297387477567653LL)); - BOOST_CHECK_EQUAL(8999999999999999999LL, calculateDExPurchase(MAX, MAX, 8999999999999999999LL)); - BOOST_CHECK_EQUAL(9111111111111111111LL, calculateDExPurchase(MAX, MAX, 9111111111111111111LL)); -} - -BOOST_AUTO_TEST_CASE(purchase_amount_fraction) -{ - BOOST_CHECK_EQUAL(10, calculateDExPurchase(17, 13, 7)); - BOOST_CHECK_EQUAL(14, calculateDExPurchase(19, 11, 8)); - BOOST_CHECK_EQUAL(100000000000000000LL, calculateDExPurchase(200000000000000000LL, 1000000000000000000LL, 499999999999999999LL)); - BOOST_CHECK_EQUAL(100000000000000001LL, calculateDExPurchase(200000000000000001LL, 1000000000000000000LL, 500000000000000000LL)); -} - -BOOST_AUTO_TEST_CASE(overflow_protection) -{ - BOOST_CHECK_EQUAL(0, calculateDExPurchase(100000000, 10000, 0)); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/ecdsa_signature_tests.cpp b/src/elysium/test/ecdsa_signature_tests.cpp deleted file mode 100644 index e54497d3ad..0000000000 --- a/src/elysium/test/ecdsa_signature_tests.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "../ecdsa_signature.h" - -#include "../../test/fixtures.h" - -#include - -namespace std { - -template -basic_ostream& operator<<(basic_ostream& os, const vector& vch) -{ - return os << HexStr(vch); -} - -} // namespace std - -namespace elysium { - -class ECDSASignatureTestingSetup : public BasicTestingSetup -{ -public: - std::vector rawSig; - std::vector compact; - ECDSAContext context; - -public: - ECDSASignatureTestingSetup() - : context(ECDSAContext::CreateVerifyContext()) - { - rawSig = ParseHex("30440220741a563fc29ff077533d74a10940fc9a2a397c6f12bb482142d16d0bac2330ad0220698346e9dedd390c2691878336ced8f3f21452aa6346e677fdbf68a1094fbd94"); - compact = ParseHex("741a563fc29ff077533d74a10940fc9a2a397c6f12bb482142d16d0bac2330ad698346e9dedd390c2691878336ced8f3f21452aa6346e677fdbf68a1094fbd94"); - } - -public: - ECDSASignature GetSignature() const - { - return ECDSASignature::ParseDER(context, rawSig.data(), rawSig.size()); - } -}; - -BOOST_FIXTURE_TEST_SUITE(elysium_ecdsa_signature, ECDSASignatureTestingSetup) - -BOOST_AUTO_TEST_CASE(default_contruct_should_invalid) -{ - ECDSASignature sig; - auto valid = sig.Valid(); - - BOOST_CHECK(!valid); -} - -BOOST_AUTO_TEST_CASE(construct_and_get_data) -{ - auto sig = GetSignature(); - auto sigVec = sig.GetDER(context); - - std::vector expected; - expected.insert(expected.end(), rawSig.begin(), rawSig.end()); - expected.push_back(0x00); - expected.push_back(0x00); - - BOOST_CHECK_EQUAL(expected, sigVec); - BOOST_CHECK(sig.Valid()); -} - -BOOST_AUTO_TEST_CASE(parse_signature) -{ - auto sig = ECDSASignature::ParseCompact(context, compact.data()); - auto derSig = ECDSASignature::ParseDER(context, rawSig.data(), rawSig.size()); - auto sigVec = sig.GetDER(context); - auto derSigVec = derSig.GetDER(context); - - std::vector expected; - expected.insert(expected.end(), rawSig.begin(), rawSig.end()); - expected.push_back(0x00); - expected.push_back(0x00); - - BOOST_CHECK_EQUAL(expected, sigVec); - BOOST_CHECK(sig.Valid()); - - BOOST_CHECK_EQUAL(expected, derSigVec); - BOOST_CHECK(derSig.Valid()); -} - -BOOST_AUTO_TEST_CASE(serialize) -{ - auto sig = GetSignature(); - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << sig; - - std::vector serialized(ss.begin(), ss.end()); - - BOOST_CHECK_EQUAL(compact, serialized); -} - -BOOST_AUTO_TEST_CASE(serialize_invalid) -{ - ECDSASignature sig; - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - - BOOST_CHECK_THROW(ss << sig, std::logic_error); -} - -BOOST_AUTO_TEST_CASE(unserialize) -{ - ECDSASignature sig; - - CDataStream ss(compact, SER_NETWORK, PROTOCOL_VERSION); - ss >> sig; - - std::vector expected; - expected.insert(expected.end(), rawSig.begin(), rawSig.end()); - expected.push_back(0x00); - expected.push_back(0x00); - - BOOST_CHECK_EQUAL(expected, sig.GetDER(context)); - BOOST_CHECK(sig.Valid()); -} - -BOOST_AUTO_TEST_CASE(unserialize_non_compact) -{ - std::vector shrinkedCompact; - shrinkedCompact.insert(shrinkedCompact.end(), compact.begin(), compact.end()); - shrinkedCompact.resize(shrinkedCompact.size() - 1); - - ECDSASignature sig; - CDataStream ss(shrinkedCompact, SER_NETWORK, PROTOCOL_VERSION); - - BOOST_CHECK_THROW(ss >> sig, std::runtime_error); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium \ No newline at end of file diff --git a/src/elysium/test/elysium_handler_tx.cpp b/src/elysium/test/elysium_handler_tx.cpp deleted file mode 100644 index 7ed5d27315..0000000000 --- a/src/elysium/test/elysium_handler_tx.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include "../convert.h" -#include "../createpayload.h" -#include "../createtx.h" -#include "../errors.h" -#include "../elysium.h" -#include "../tx.h" -#include "../utilsbitcoin.h" -#include "../wallettxs.h" - -#include "../../base58.h" -#include "../../coins.h" -#include "../../core_io.h" -#include "../../validation.h" -#include "../../utilstrencodings.h" - -#include "../../primitives/transaction.h" - -#include "../../script/script.h" -#include "../../script/standard.h" - -#include "../../test/fixtures.h" -#include "../../test/test_bitcoin.h" - -#include "../../wallet/wallet.h" - -#include - -#include -#include -#include - -#include - -/** - * Pushes bytes to the end of a vector. - */ -#define PUSH_BACK_BYTES(vector, value)\ - vector.insert(vector.end(), reinterpret_cast(&(value)),\ - reinterpret_cast(&(value)) + sizeof((value))); - -BOOST_FIXTURE_TEST_SUITE(elysium_handler_tx_tests, ZerocoinTestingSetup200) - -static std::vector createMockSpendPayload() -{ - std::vector payload; - - uint16_t messageType = 1024; - uint16_t messageVer = 0; - elysium::swapByteOrder16(messageVer); - elysium::swapByteOrder16(messageType); - - PUSH_BACK_BYTES(payload, messageVer); - PUSH_BACK_BYTES(payload, messageType); - - return payload; -} - -CBlock getHeighestBlock() -{ - CBlock block; - auto idx = chainActive.Tip(); - BOOST_CHECK(ReadBlockFromDisk(block, idx, Params().GetConsensus())); - return block; -} - -BOOST_AUTO_TEST_CASE(elysium_parse_normal_tx) -{ - pwalletMain->SetBroadcastTransactions(true); - std::string fromAddress = CBitcoinAddress(pubkey.GetID()).ToString(); - - auto ecosystem = 2; // test - auto type = 1; // indivisible - auto previousId = 0; // new token - CAmount amount(1); - - std::vector payload = CreatePayload_IssuanceFixed( - ecosystem, type, previousId, "Companies", "", "non-sigma", "", "", amount - ); - - uint256 txid; - std::string rawHex; - BOOST_CHECK_EQUAL( - 0, // No error - elysium::WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, true) - ); - - CreateAndProcessBlock(scriptPubKey); - auto block = getHeighestBlock(); - BOOST_CHECK_EQUAL(2, block.vtx.size()); - - CTransactionRef elysiumTx = block.vtx[1]; - CMPTransaction mp_obj; - - BOOST_CHECK_EQUAL(0, ParseTransaction(*elysiumTx, chainActive.Height(), 1, mp_obj, block.GetBlockTime())); -} - -BOOST_AUTO_TEST_CASE(elysium_parse_normal_tx_with_spend) -{ - pwalletMain->SetBroadcastTransactions(true); - std::string fromAddress = CBitcoinAddress(pubkey.GetID()).ToString(); - - auto ecosystem = 2; // test - auto type = 1; // indivisible - auto previousId = 0; // new token - CAmount amount(1); - - std::vector payload = createMockSpendPayload(); - - uint256 txid; - std::string rawHex; - BOOST_CHECK_EQUAL( - 0, // No error - elysium::WalletTxBuilder(fromAddress, "", "", 0, payload, txid, rawHex, true) - ); - - CreateAndProcessBlock(scriptPubKey); - - auto block = getHeighestBlock(); - BOOST_CHECK_EQUAL(2, block.vtx.size()); - - CTransactionRef elysiumTx = block.vtx[1]; - CMPTransaction mp_obj; - - BOOST_CHECK_EQUAL(0, ParseTransaction(*elysiumTx, chainActive.Height(), 1, mp_obj, block.GetBlockTime())); -} - -BOOST_AUTO_TEST_CASE(elysium_parse_sigma_tx_with_non_spend) -{ - pwalletMain->SetBroadcastTransactions(true); - - string stringError; - sigma::CoinDenomination denomination; - sigma::StringToDenomination("1", denomination); - const auto& sigmaParams = sigma::Params::get_default(); - std::vector privCoins(10, sigma::PrivateCoin(sigmaParams, denomination)); - - CWalletTx wtx; - std::vector vDMints; - auto vecSend = CWallet::CreateSigmaMintRecipients(privCoins, vDMints); - stringError = pwalletMain->MintAndStoreSigma(vecSend, privCoins, vDMints, wtx); - - BOOST_CHECK_MESSAGE(stringError == "", "Mint Failed"); - - CreateAndProcessBlock(scriptPubKey); - CreateAndProcessEmptyBlocks(5, scriptPubKey); - - auto ecosystem = 2; // test - auto type = 1; // indivisible - auto previousId = 0; // new token - CAmount amount(1); - - std::vector payload = CreatePayload_IssuanceFixed( - ecosystem, type, previousId, "Companies", "", "non-sigma", "", "", amount - ); - - uint256 txid; - std::string rawHex; - BOOST_CHECK_EQUAL( - 0, // No error - elysium::WalletTxBuilder("", "", "", 0, payload, txid, rawHex, true, elysium::InputMode::SIGMA) - ); - - CreateAndProcessBlock(scriptPubKey); - - auto block = getHeighestBlock(); - BOOST_CHECK_EQUAL(2, block.vtx.size()); - - CTransactionRef sigmaTx = block.vtx[1]; - CMPTransaction mp_obj; - - BOOST_CHECK_EQUAL(0, ParseTransaction(*sigmaTx, chainActive.Height(), 1, mp_obj, block.GetBlockTime())); -} - -BOOST_AUTO_TEST_CASE(elysium_parse_sigma_tx_with_spend) -{ - pwalletMain->SetBroadcastTransactions(true); - - string stringError; - sigma::CoinDenomination denomination; - sigma::StringToDenomination("1", denomination); - const auto& sigmaParams = sigma::Params::get_default(); - std::vector privCoins(10, sigma::PrivateCoin(sigmaParams, denomination)); - - CWalletTx wtx; - std::vector vDMints; - auto vecSend = CWallet::CreateSigmaMintRecipients(privCoins, vDMints); - stringError = pwalletMain->MintAndStoreSigma(vecSend, privCoins, vDMints, wtx); - - BOOST_CHECK_MESSAGE(stringError == "", "Mint Failed"); - - CreateAndProcessBlock(scriptPubKey); - CreateAndProcessEmptyBlocks(5, scriptPubKey); - - std::vector data = createMockSpendPayload(); - - uint256 txid; - std::string rawHex; - BOOST_CHECK_EQUAL( - 0, // No error - elysium::WalletTxBuilder("", "", "", 0, data, txid, rawHex, true, elysium::InputMode::SIGMA) - ); - - CreateAndProcessBlock(scriptPubKey); - - auto block = getHeighestBlock(); - BOOST_CHECK_EQUAL(2, block.vtx.size()); - - CTransactionRef sigmaTx = block.vtx[1]; - CMPTransaction mp_obj; - - BOOST_CHECK_EQUAL(0, ParseTransaction(*sigmaTx, chainActive.Height(), 1, mp_obj, block.GetBlockTime())); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/elysium_tests.cpp b/src/elysium/test/elysium_tests.cpp deleted file mode 100644 index 128af24166..0000000000 --- a/src/elysium/test/elysium_tests.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "../elysium.h" -#include "../rules.h" -#include "../sp.h" - -#include "base58.h" -#include "chainparams.h" -#include "test/test_bitcoin.h" - -#include - -#include - -using namespace elysium; - -BOOST_FIXTURE_TEST_SUITE(elysium_elysium_tests, TestingSetup) - -BOOST_AUTO_TEST_CASE(elysium_mints_overflow) -{ - _my_sps = new CMPSPInfo(pathTemp / "MP_spinfo_test", false); - - CMPSPInfo::Entry sp; - sp.denominations = {MAX_INT_8_BYTES}; - auto property = _my_sps->putSP(0, sp); // non-standard - - std::vector denoms = {0, 0}; - BOOST_CHECK_EXCEPTION( - SumDenominationsValue(property, denoms.begin(), denoms.end()), - std::overflow_error, - [](std::overflow_error const &e) -> bool { - return std::string("summation of mints is overflow") == e.what(); - } - ); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/encoding_b_tests.cpp b/src/elysium/test/encoding_b_tests.cpp deleted file mode 100644 index 8b51336639..0000000000 --- a/src/elysium/test/encoding_b_tests.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "../packetencoder.h" -#include "../script.h" - -#include "../../base58.h" -#include "../../pubkey.h" -#include "../../utilstrencodings.h" - -#include "../../script/script.h" -#include "../../script/standard.h" - -#include "../../test/test_bitcoin.h" - -#include - -#include -#include -#include - -#include - -using namespace elysium; - -BOOST_FIXTURE_TEST_SUITE(elysium_encoding_b_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(class_b_empty) -{ - const std::string strSeed; - const CPubKey pubKey; - const std::vector vchPayload; - - std::vector vTxOuts; - EncodeClassB(strSeed, pubKey, vchPayload.begin(), vchPayload.end(), std::back_inserter(vTxOuts)); - BOOST_CHECK_EQUAL(vTxOuts.size(), 1); - - const CScript& scriptPubKey = vTxOuts[0].scriptPubKey; - CTxDestination dest; - BOOST_CHECK(ExtractDestination(scriptPubKey, dest)); - BOOST_CHECK_EQUAL(CBitcoinAddress(dest).ToString(), "ZzzcQkPmXomcTcSVGsDHsGBCvxg67joaj5"); -} - -BOOST_AUTO_TEST_CASE(class_b_maidsafe) -{ - // Transaction hash (mainnet): - // 86f214055a7f4f5057922fd1647e00ef31ab0a3ff15217f8b90e295f051873a7 - const std::string strSeed("1ARjWDkZ7kT9fwjPrjcQyvbXDkEySzKHwu"); - - const std::vector vchPubKey = ParseHex( - "02619c30f643a4679ec2f690f3d6564df7df2ae23ae4a55393ae0bef22db9dbcaf"); - - const CPubKey pubKey(vchPubKey.begin(), vchPubKey.end()); - - const std::vector vchPayload = ParseHex( - // Transaction version: 0 - "0000" - // Transaction type: Create Crowdsale (51) - "0033" - // Eco system: Main (1) - "01" - // Property type: Indivisible tokens (1) - "0001" - // Previous property identifier: None (0) - "00000000" - // Category: "Crowdsale" - "43726f776473616c6500" - // Sub category: "MaidSafe" - "4d6169645361666500" - // Property name: "MaidSafeCoin" - "4d61696453616665436f696e00" - // URL: "www.buysafecoins.com" - "7777772e62757973616665636f696e732e636f6d00" - // Information: "SAFE Network Crowdsale (MSAFE)" - "53414645204e6574776f726b2043726f776473616c6520284d534146452900" - // Desired property: Mastercoin (SP #1) - "00000001" - // Amount per unit invested: 3400 - "0000000000000d48" - // Deadline: Thu, 22 May 2014 09:00:00 UTC (1400749200) - "00000000537dbc90" - // Early bird bonus: 10 % per week - "0a" - // Percentage for issuer: 0 % - "00"); - - std::vector vTxOuts; - EncodeClassB(strSeed, pubKey, vchPayload.begin(), vchPayload.end(), std::back_inserter(vTxOuts)); - BOOST_CHECK_EQUAL(vTxOuts.size(), 3); - - const CScript& scriptPubKeyA = vTxOuts[0].scriptPubKey; - const CScript& scriptPubKeyB = vTxOuts[1].scriptPubKey; - const CScript& scriptPubKeyC = vTxOuts[2].scriptPubKey; - - txnouttype outtypeA; - BOOST_CHECK(GetOutputType(scriptPubKeyA, outtypeA)); - BOOST_CHECK_EQUAL(outtypeA, TX_MULTISIG); - txnouttype outtypeB; - BOOST_CHECK(GetOutputType(scriptPubKeyB, outtypeB)); - BOOST_CHECK_EQUAL(outtypeB, TX_MULTISIG); - txnouttype outtypeC; - BOOST_CHECK(GetOutputType(scriptPubKeyC, outtypeC)); - BOOST_CHECK_EQUAL(outtypeC, TX_PUBKEYHASH); - - std::vector> solutions; - - GetPushedValues(scriptPubKeyA, std::back_inserter(solutions)); - BOOST_CHECK_EQUAL(solutions.empty(), false); - - GetPushedValues(scriptPubKeyB, std::back_inserter(solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 6); - - // Vout 0 - BOOST_CHECK_EQUAL(HexStr(solutions[0]), - "02619c30f643a4679ec2f690f3d6564df7df2ae23ae4a55393ae0bef22db9dbcaf"); - BOOST_CHECK_EQUAL(HexStr(solutions[1].begin() + 1, solutions[1].begin() + 32), // Remove prefix ... - "6766a63686d2cc5d82c929d339b7975010872aa6bf76f6fac69f28f8e293a9"); - BOOST_CHECK_EQUAL(HexStr(solutions[2].begin() + 1, solutions[2].begin() + 32), // ... and ECDSA byte - "959b8e2f2e4fb67952cda291b467a1781641c94c37feaa0733a12782977da2"); - // Vout 1 - BOOST_CHECK_EQUAL(HexStr(solutions[3]), - "02619c30f643a4679ec2f690f3d6564df7df2ae23ae4a55393ae0bef22db9dbcaf"); - BOOST_CHECK_EQUAL(HexStr(solutions[4].begin() + 1, solutions[4].begin() + 32), // Because these ... - "61a017029ec4688ec9bf33c44ad2e595f83aaf3ed4f3032d1955715f5ffaf6"); - BOOST_CHECK_EQUAL(HexStr(solutions[5].begin() + 1, solutions[5].begin() + 32), // ... are semi-random - "dc1a0afc933d703557d9f5e86423a5cec9fee4bfa850b3d02ceae721171788"); -} - -BOOST_AUTO_TEST_CASE(class_b_tetherus) -{ - // Transaction hash (mainnet): - // 5ed3694e8a4fa8d3ec5c75eb6789492c69e65511522b220e94ab51da2b6dd53f - const std::string strSeed("3MbYQMMmSkC3AgWkj9FMo5LsPTW1zBTwXL"); - - const std::vector vchPubKey = ParseHex( - "04ad90e5b6bc86b3ec7fac2c5fbda7423fc8ef0d58df594c773fa05e2c281b2bfe" - "877677c668bd13603944e34f4818ee03cadd81a88542b8b4d5431264180e2c28"); - - const CPubKey pubKey(vchPubKey.begin(), vchPubKey.end()); - - const std::vector vchPayload = ParseHex( - "000000360100020000000046696e616e6369616c20616e6420696e737572" - "616e63652061637469766974696573004163746976697469657320617578" - "696c6961727920746f2066696e616e6369616c207365727669636520616e" - "6420696e737572616e636520616374697669746965730054657468657255" - "530068747470733a2f2f7465746865722e746f00546865206e6578742070" - "6172616469676d206f66206d6f6e65792e00"); - - std::vector vTxOuts; - EncodeClassB(strSeed, pubKey, vchPayload.begin(), vchPayload.end(), std::back_inserter(vTxOuts)); - BOOST_CHECK_EQUAL(vTxOuts.size(), 4); - - const CScript& scriptPubKeyA = vTxOuts[0].scriptPubKey; - const CScript& scriptPubKeyB = vTxOuts[1].scriptPubKey; - const CScript& scriptPubKeyC = vTxOuts[2].scriptPubKey; - const CScript& scriptPubKeyD = vTxOuts[3].scriptPubKey; - - txnouttype outtypeA; - BOOST_CHECK(GetOutputType(scriptPubKeyA, outtypeA)); - BOOST_CHECK_EQUAL(outtypeA, TX_MULTISIG); - txnouttype outtypeB; - BOOST_CHECK(GetOutputType(scriptPubKeyB, outtypeB)); - BOOST_CHECK_EQUAL(outtypeB, TX_MULTISIG); - txnouttype outtypeC; - BOOST_CHECK(GetOutputType(scriptPubKeyC, outtypeC)); - BOOST_CHECK_EQUAL(outtypeC, TX_MULTISIG); - txnouttype outtypeD; - BOOST_CHECK(GetOutputType(scriptPubKeyD, outtypeD)); - BOOST_CHECK_EQUAL(outtypeD, TX_PUBKEYHASH); - - std::vector> solutions; - - GetPushedValues(scriptPubKeyA, std::back_inserter(solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 3); - - GetPushedValues(scriptPubKeyB, std::back_inserter(solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 6); - - GetPushedValues(scriptPubKeyC, std::back_inserter(solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 9); - - // Vout 0 - BOOST_CHECK_EQUAL(HexStr(solutions[0]), HexStr(pubKey.begin(), pubKey.end())); - BOOST_CHECK_EQUAL(HexStr(solutions[1].begin() + 1, solutions[1].begin() + 32), - "f88f01791557f6d57e6b7ddf86d2de2117e6cc4ba325a4e309d4a1a55015d7"); - BOOST_CHECK_EQUAL(HexStr(solutions[2].begin() + 1, solutions[2].begin() + 32), - "a94f47f4c3b8c36876399f19ecd61cf452248330fa5da9a1947d6dc7a189a1"); - // Vout 1 - BOOST_CHECK_EQUAL(HexStr(solutions[3]), HexStr(pubKey.begin(), pubKey.end())); - BOOST_CHECK_EQUAL(HexStr(solutions[4].begin() + 1, solutions[4].begin() + 32), - "6d7e7235fc2c6769e351196c9ccdc4c804184b5bb9b210f27d3f0a613654fe"); - BOOST_CHECK_EQUAL(HexStr(solutions[5].begin() + 1, solutions[5].begin() + 32), - "8991cff7cc6d93c266615d2a9223cef4d7b11c05c16b0cec12a90ee7b39cf8"); - // Vout 2 - BOOST_CHECK_EQUAL(HexStr(solutions[6]), HexStr(pubKey.begin(), pubKey.end())); - BOOST_CHECK_EQUAL(HexStr(solutions[7].begin() + 1, solutions[7].begin() + 32), - "29b3e0919adc41a316aad4f41444d9bf3a9b639550f2aa735676ffff25ba38"); - BOOST_CHECK_EQUAL(HexStr(solutions[8].begin() + 1, solutions[8].begin() + 32), - "f15446771c5c585dd25d8d62df5195b77799aa8eac2f2196c54b73ca05f72f"); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/encoding_c_tests.cpp b/src/elysium/test/encoding_c_tests.cpp deleted file mode 100644 index e45b4fc2ce..0000000000 --- a/src/elysium/test/encoding_c_tests.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "../packetencoder.h" -#include "../script.h" - -#include "../../utilstrencodings.h" - -#include "../../script/script.h" - -#include "../../test/test_bitcoin.h" - -#include - -#include -#include -#include - -#include - -using namespace elysium; - -// Is resetted to a norm value in each test -extern unsigned nMaxDatacarrierBytes; - -BOOST_FIXTURE_TEST_SUITE(elysium_encoding_c_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(class_c_marker) -{ - // Store initial data carrier size - unsigned nMaxDatacarrierBytesOriginal = nMaxDatacarrierBytes; - - nMaxDatacarrierBytes = 40; // byte - - std::vector vchMarker; - vchMarker.push_back(0x65); // "e" - vchMarker.push_back(0x78); // "x" - vchMarker.push_back(0x6f); // "o" - vchMarker.push_back(0x64); // "d" - vchMarker.push_back(0x75); // "u" - vchMarker.push_back(0x73); // "s" - - std::vector vchPayload = ParseHex( - "00000000000000010000000006dac2c0"); - - auto scriptData = EncodeClassC(vchPayload.begin(), vchPayload.end()).scriptPubKey; - - std::vector> pushes; - GetPushedValues(scriptData, std::back_inserter(pushes)); - BOOST_CHECK_EQUAL(pushes.size(), 1); - - // The embedded data has a size of the payload plus marker - BOOST_CHECK_EQUAL( - pushes[0].size(), - vchMarker.size() + vchPayload.size()); - - // The output script really starts with the marker - for (size_t n = 0; n < vchMarker.size(); ++n) { - BOOST_CHECK_EQUAL(vchMarker[n], pushes[0][n]); - } - - // The output script really ends with the payload - std::vector vchEmbeddedPayload( - pushes[0].begin() + vchMarker.size(), - pushes[0].end()); - - BOOST_CHECK_EQUAL(HexStr(vchEmbeddedPayload), HexStr(vchPayload)); - - // Restore original data carrier size settings - nMaxDatacarrierBytes = nMaxDatacarrierBytesOriginal; -} - -BOOST_AUTO_TEST_CASE(class_c_with_empty_payload) -{ - // Store initial data carrier size - unsigned nMaxDatacarrierBytesOriginal = nMaxDatacarrierBytes; - - const std::vector vchEmptyPayload; - - // Even less than the size of the marker - nMaxDatacarrierBytes = 0; // byte - - BOOST_CHECK_THROW(EncodeClassC(vchEmptyPayload.begin(), vchEmptyPayload.end()), std::invalid_argument); - - // Exactly the size of the marker - nMaxDatacarrierBytes = 8; // byte - - BOOST_CHECK_NO_THROW(EncodeClassC(vchEmptyPayload.begin(), vchEmptyPayload.end())); - - // Restore original data carrier size settings - nMaxDatacarrierBytes = nMaxDatacarrierBytesOriginal; -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/lock_tests.cpp b/src/elysium/test/lock_tests.cpp deleted file mode 100644 index 73c0392032..0000000000 --- a/src/elysium/test/lock_tests.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "random.h" -#include "sync.h" -#include "test/test_bitcoin.h" -#include "utiltime.h" - -#include -#include -#include - -namespace number -{ - int n = 0; -} - -namespace locker -{ - CCriticalSection cs_number; -} - -static void plusOneThread(int nIterations) -{ - for (int i = 0; i < nIterations; ++i) { - LOCK(locker::cs_number); - int n = number::n; - int nSleep = GetRandInt(10); - MilliSleep(nSleep); - number::n = n + 1; - } -} - -BOOST_FIXTURE_TEST_SUITE(elysium_lock_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(multithread_locking) -{ - int nThreadsNum = 4; - int nIterations = 20; - - boost::thread_group threadGroup; - for (int i = 0; i < nThreadsNum; ++i) { - threadGroup.create_thread(boost::bind(&plusOneThread, nIterations)); - } - - threadGroup.join_all(); - BOOST_CHECK_EQUAL(number::n, (nThreadsNum * nIterations)); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/marker_tests.cpp b/src/elysium/test/marker_tests.cpp deleted file mode 100644 index e93d31b598..0000000000 --- a/src/elysium/test/marker_tests.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "utils_tx.h" - -#include "../elysium.h" -#include "../packetencoder.h" -#include "../rules.h" -#include "../script.h" - -#include "../../primitives/transaction.h" -#include "../../test/test_bitcoin.h" - -#include -#include - -#include - -namespace elysium { - -BOOST_FIXTURE_TEST_SUITE(elysium_marker_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(class_no_marker) -{ - { - int nBlock = std::numeric_limits::max(); - - CMutableTransaction mutableTx; - CTransaction tx(mutableTx); - - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), boost::none); - } - { - int nBlock = 0; - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(OpReturn_Unrelated()); - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - mutableTx.vout.push_back(NonStandardOutput()); - mutableTx.vout.push_back(OpReturn_UnrelatedShort()); - mutableTx.vout.push_back(OpReturn_Empty()); - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), boost::none); - } - { - int nBlock = std::numeric_limits::max(); - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - mutableTx.vout.push_back(OpReturn_UnrelatedShort()); - mutableTx.vout.push_back(OpReturn_Unrelated()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(OpReturn_Empty()); - mutableTx.vout.push_back(NonStandardOutput()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), boost::none); - } - { - int nBlock = std::numeric_limits::max(); - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(PayToBareMultisig_3of5()); - mutableTx.vout.push_back(OpReturn_Unrelated()); - mutableTx.vout.push_back(NonStandardOutput()); - mutableTx.vout.push_back(OpReturn_UnrelatedShort()); - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - mutableTx.vout.push_back(OpReturn_Empty()); - mutableTx.vout.push_back(PayToBareMultisig_1of3()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), boost::none); - } -} - -BOOST_AUTO_TEST_CASE(class_class_b) -{ - { - int nBlock = 0; - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(PayToPubKeyHash_Elysium()); - mutableTx.vout.push_back(PayToBareMultisig_1of3()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::B); - } - { - int nBlock = ConsensusParams().NULLDATA_BLOCK; - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(PayToBareMultisig_3of5()); - mutableTx.vout.push_back(PayToBareMultisig_3of5()); - mutableTx.vout.push_back(PayToPubKeyHash_Elysium()); - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::B); - } - { - int nBlock = 0; - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(OpReturn_Empty()); - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(PayToBareMultisig_1of3()); - mutableTx.vout.push_back(OpReturn_UnrelatedShort()); - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - mutableTx.vout.push_back(PayToBareMultisig_3of5()); - mutableTx.vout.push_back(OpReturn_Unrelated()); - mutableTx.vout.push_back(NonStandardOutput()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - mutableTx.vout.push_back(PayToPubKeyHash_Elysium()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::B); - } - { - int nBlock = std::numeric_limits::max(); - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(OpReturn_UnrelatedShort()); - mutableTx.vout.push_back(PayToPubKeyHash_Elysium()); - mutableTx.vout.push_back(OpReturn_Empty()); - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - mutableTx.vout.push_back(NonStandardOutput()); - mutableTx.vout.push_back(PayToBareMultisig_1of3()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - mutableTx.vout.push_back(OpReturn_Unrelated()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::B); - } -} - -BOOST_AUTO_TEST_CASE(class_class_c) -{ - { - int nBlock = ConsensusParams().NULLDATA_BLOCK; - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(OpReturn_PlainMarker()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::C); - } - { - int nBlock = std::numeric_limits::max(); - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(OpReturn_SimpleSend()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::C); - } - { - int nBlock = std::numeric_limits::max(); - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(NonStandardOutput()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - mutableTx.vout.push_back(OpReturn_PlainMarker()); - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - mutableTx.vout.push_back(OpReturn_Empty()); - mutableTx.vout.push_back(OpReturn_Unrelated()); - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(OpReturn_UnrelatedShort()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::C); - } - { - int nBlock = ConsensusParams().NULLDATA_BLOCK; - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - mutableTx.vout.push_back(OpReturn_Unrelated()); - mutableTx.vout.push_back(OpReturn_UnrelatedShort()); - mutableTx.vout.push_back(OpReturn_Empty()); - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - mutableTx.vout.push_back(PayToBareMultisig_1of3()); - mutableTx.vout.push_back(NonStandardOutput()); - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(OpReturn_MultiSimpleSend()); - mutableTx.vout.push_back(PayToBareMultisig_3of5()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::C); - } - { - int nBlock = std::numeric_limits::max(); - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(OpReturn_UnrelatedShort()); - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(OpReturn_Unrelated()); - mutableTx.vout.push_back(OpReturn_Empty()); - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - mutableTx.vout.push_back(NonStandardOutput()); - mutableTx.vout.push_back(OpReturn_PlainMarker()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::C); - } - { - int nBlock = ConsensusParams().NULLDATA_BLOCK; - - CMutableTransaction mutableTx; - mutableTx.vout.push_back(PayToPubKey_Unrelated()); - mutableTx.vout.push_back(OpReturn_MultiSimpleSend()); - mutableTx.vout.push_back(PayToBareMultisig_1of3()); - mutableTx.vout.push_back(PayToBareMultisig_1of3()); - mutableTx.vout.push_back(OpReturn_SimpleSend()); - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - mutableTx.vout.push_back(PayToScriptHash_Unrelated()); - mutableTx.vout.push_back(NonStandardOutput()); - mutableTx.vout.push_back(OpReturn_PlainMarker()); - mutableTx.vout.push_back(PayToPubKeyHash_Elysium()); - - CTransaction tx(mutableTx); - BOOST_CHECK_EQUAL(DeterminePacketClass(tx, nBlock), PacketClass::C); - } -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/output_restriction_tests.cpp b/src/elysium/test/output_restriction_tests.cpp deleted file mode 100644 index 37c8481c67..0000000000 --- a/src/elysium/test/output_restriction_tests.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "elysium/elysium.h" -#include "elysium/rules.h" - -#include "chainparams.h" -#include "script/standard.h" -#include "test/test_bitcoin.h" - -#include - -#include -#include - -using namespace elysium; - -BOOST_FIXTURE_TEST_SUITE(elysium_output_restriction_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(input_nonstandard) -{ - BOOST_CHECK(!IsAllowedInputType(TX_NONSTANDARD, 0)); - BOOST_CHECK(!IsAllowedInputType(TX_NONSTANDARD, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(input_pubkey) -{ - BOOST_CHECK(!IsAllowedInputType(TX_PUBKEY, 0)); - BOOST_CHECK(!IsAllowedInputType(TX_PUBKEY, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(input_pubkeyhash) -{ - BOOST_CHECK(IsAllowedInputType(TX_PUBKEYHASH, 0)); - BOOST_CHECK(IsAllowedInputType(TX_PUBKEYHASH, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(input_scripthash) -{ - int P2SH_BLOCK = ConsensusParams().SCRIPTHASH_BLOCK; - - BOOST_CHECK(!IsAllowedInputType(TX_SCRIPTHASH, P2SH_BLOCK-1)); - BOOST_CHECK(IsAllowedInputType(TX_SCRIPTHASH, P2SH_BLOCK)); - BOOST_CHECK(IsAllowedInputType(TX_SCRIPTHASH, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(input_scripthash_testnet) -{ - SelectParams(CBaseChainParams::TESTNET); - BOOST_CHECK(IsAllowedInputType(TX_SCRIPTHASH, 0)); - BOOST_CHECK(IsAllowedInputType(TX_SCRIPTHASH, std::numeric_limits::max())); - SelectParams(CBaseChainParams::MAIN); -} - -BOOST_AUTO_TEST_CASE(input_multisig) -{ - BOOST_CHECK(!IsAllowedInputType(TX_MULTISIG, 0)); - BOOST_CHECK(!IsAllowedInputType(TX_MULTISIG, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(input_nulldata) -{ - BOOST_CHECK(!IsAllowedInputType(TX_NULL_DATA, 0)); - BOOST_CHECK(!IsAllowedInputType(TX_NULL_DATA, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(output_nonstandard) -{ - BOOST_CHECK(!IsAllowedOutputType(TX_NONSTANDARD, 0)); - BOOST_CHECK(!IsAllowedOutputType(TX_NONSTANDARD, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(output_pubkey) -{ - BOOST_CHECK(!IsAllowedOutputType(TX_PUBKEY, 0)); - BOOST_CHECK(!IsAllowedOutputType(TX_PUBKEY, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(output_pubkeyhash) -{ - BOOST_CHECK(IsAllowedOutputType(TX_PUBKEYHASH, 0)); - BOOST_CHECK(IsAllowedOutputType(TX_PUBKEYHASH, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(output_scripthash) -{ - int P2SH_BLOCK = ConsensusParams().SCRIPTHASH_BLOCK; - - BOOST_CHECK(!IsAllowedOutputType(TX_SCRIPTHASH, P2SH_BLOCK-1)); - BOOST_CHECK(IsAllowedOutputType(TX_SCRIPTHASH, P2SH_BLOCK)); - BOOST_CHECK(IsAllowedOutputType(TX_SCRIPTHASH, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(output_scripthash_testnet) -{ - SelectParams(CBaseChainParams::TESTNET); - BOOST_CHECK(IsAllowedOutputType(TX_SCRIPTHASH, 0)); - BOOST_CHECK(IsAllowedOutputType(TX_SCRIPTHASH, std::numeric_limits::max())); - SelectParams(CBaseChainParams::MAIN); -} - -BOOST_AUTO_TEST_CASE(output_multisig) -{ - BOOST_CHECK(IsAllowedOutputType(TX_MULTISIG, 0)); - BOOST_CHECK(IsAllowedOutputType(TX_MULTISIG, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(output_nulldata) -{ - int OP_RETURN_BLOCK = ConsensusParams().NULLDATA_BLOCK; - - BOOST_CHECK(!IsAllowedOutputType(TX_NULL_DATA, OP_RETURN_BLOCK-1)); - BOOST_CHECK(IsAllowedOutputType(TX_NULL_DATA, OP_RETURN_BLOCK)); - BOOST_CHECK(IsAllowedOutputType(TX_NULL_DATA, std::numeric_limits::max())); -} - -BOOST_AUTO_TEST_CASE(output_nulldata_testnet) -{ - SelectParams(CBaseChainParams::TESTNET); - BOOST_CHECK(IsAllowedOutputType(TX_NULL_DATA, 0)); - BOOST_CHECK(IsAllowedOutputType(TX_NULL_DATA, std::numeric_limits::max())); - SelectParams(CBaseChainParams::MAIN); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/packetencoder_tests.cpp b/src/elysium/test/packetencoder_tests.cpp deleted file mode 100644 index 9f22d2d0b6..0000000000 --- a/src/elysium/test/packetencoder_tests.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "../packetencoder.h" - -#include "../../utilstrencodings.h" - -#include - -#include - -namespace std { - -template -basic_ostream& operator<<(basic_ostream& os, const CBase58Data& v) -{ - return os << v.ToString(); -} - -} // namespace std - -namespace elysium { - -BOOST_AUTO_TEST_SUITE(elysium_packetencoder_tests) - -BOOST_AUTO_TEST_CASE(key_generator) -{ - PacketKeyGenerator g("1CdighsfdfRcj4ytQSskZgQXbUEamuMUNF"); - - BOOST_CHECK_EQUAL(HexStr(g.Next()), "1d9a3de5c2e22bf89a1e41e6fedab54582f8a0c3ae14394a59366293dd130c59"); - BOOST_CHECK_EQUAL(HexStr(g.Next()), "0800ed44f1300fb3a5980ecfa8924fedb2d5fdbef8b21bba6526b4fd5f9c167c"); - BOOST_CHECK_EQUAL(HexStr(g.Next()), "7110a59d22d5af6a34b7a196dae7ccc0f27354b34e257832b9955611a9d79b06"); - BOOST_CHECK_EQUAL(HexStr(g.Next()), "aa3f890d32864bea31ee9bd57d2247d8f8ce07b5abaed9372f0b8999d28db963"); -} - -BOOST_AUTO_TEST_CASE(system_address_mainnet) -{ - SelectParams(CBaseChainParams::MAIN); - - BOOST_CHECK_EQUAL(GetSystemAddress(), CBitcoinAddress("ZzzcQkPmXomcTcSVGsDHsGBCvxg67joaj5")); -} - -BOOST_AUTO_TEST_CASE(system_address_testnet) -{ - SelectParams(CBaseChainParams::TESTNET); - - BOOST_CHECK_EQUAL(GetSystemAddress(), CBitcoinAddress("TTFL4sPFHP22Dzqbw9mPQJEjdG7Wf1ajjZ")); - - SelectParams(CBaseChainParams::MAIN); -} - -BOOST_AUTO_TEST_CASE(system_address_regtest) -{ - SelectParams(CBaseChainParams::REGTEST); - - BOOST_CHECK_EQUAL(GetSystemAddress(), CBitcoinAddress("TTFL4sPFHP22Dzqbw9mPQJEjdG7Wf1ajjZ")); - - SelectParams(CBaseChainParams::MAIN); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/parsing_b_tests.cpp b/src/elysium/test/parsing_b_tests.cpp deleted file mode 100644 index aa52da0742..0000000000 --- a/src/elysium/test/parsing_b_tests.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "utils_tx.h" - -#include "../createpayload.h" -#include "../elysium.h" -#include "../script.h" -#include "../tx.h" - -#include "../../base58.h" -#include "../../coins.h" - -#include "../../primitives/transaction.h" - -#include "../../script/script.h" -#include "../../script/standard.h" - -#include "../../test/test_bitcoin.h" - -#include - -#include -#include -#include - -#include - -namespace elysium { - -BOOST_FIXTURE_TEST_SUITE(elysium_parsing_b_tests, BasicTestingSetup) - -/** Creates a dummy transaction with the given inputs and outputs. */ -static CTransaction TxClassB(const std::vector& txInputs, const std::vector& txOuts) -{ - CMutableTransaction mutableTx; - - // Inputs: - for (std::vector::const_iterator it = txInputs.begin(); it != txInputs.end(); ++it) - { - const CTxOut& txOut = *it; - - // Create transaction for input: - CMutableTransaction inputTx; - unsigned int nOut = 0; - inputTx.vout.push_back(txOut); - CTransaction tx(inputTx); - - // Populate transaction cache: - ModifyCoin(view, COutPoint(tx.GetHash(), 0), - [&txOut](Coin & coin){ - coin.out.scriptPubKey = txOut.scriptPubKey; - coin.out.nValue = txOut.nValue; - }); - - // Add input: - CTxIn txIn(tx.GetHash(), nOut); - mutableTx.vin.push_back(txIn); - } - - for (std::vector::const_iterator it = txOuts.begin(); it != txOuts.end(); ++it) - { - const CTxOut& txOut = *it; - mutableTx.vout.push_back(txOut); - } - - return CTransaction(mutableTx); -} - -/** Helper to create a CTxOut object. */ -static CTxOut createTxOut(int64_t amount, const std::string& dest) -{ - return CTxOut(amount, GetScriptForDestination(CBitcoinAddress(dest).Get())); -} - -static size_t getPayloadSize(unsigned int nPackets) -{ - return CLASS_B_CHUNK_PAYLOAD_SIZE * nPackets; -} - -BOOST_AUTO_TEST_CASE(valid_common_class_b) -{ - int nBlock = 0; - - std::vector txInputs; - txInputs.push_back(createTxOut(1000000, "a1SNP5FDj2HykF2Yg2Jr3Kzu8vMbyuVoyV")); - txInputs.push_back(createTxOut(1000000, "a1YSuZWb1vvWx5Fp6oHuCXRjPDmW4nSJ4N")); - txInputs.push_back(createTxOut(2000001, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - txOutputs.push_back(PayToPubKeyHash_Elysium()); - txOutputs.push_back(PayToBareMultisig_1of3()); - txOutputs.push_back(PayToBareMultisig_3of5()); - txOutputs.push_back(PayToBareMultisig_3of5()); - txOutputs.push_back(PayToPubKeyHash_Unrelated()); - - CTransaction dummyTx = TxClassB(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(metaTx.getRaw().size(), getPayloadSize(10)); -} - -BOOST_AUTO_TEST_CASE(valid_arbitrary_output_number_class_b) -{ - int nBlock = std::numeric_limits::max(); - - int nOutputs = 3000 * 8; // due to the junk - - std::vector txInputs; - txInputs.push_back(createTxOut(5550000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - for (int i = 0; i < nOutputs / 8; ++i) { - txOutputs.push_back(PayToBareMultisig_1of2()); - txOutputs.push_back(PayToBareMultisig_1of3()); - txOutputs.push_back(PayToBareMultisig_3of5()); - txOutputs.push_back(OpReturn_Unrelated()); - txOutputs.push_back(NonStandardOutput()); - txOutputs.push_back(PayToPubKey_Unrelated()); - txOutputs.push_back(PayToScriptHash_Unrelated()); - txOutputs.push_back(PayToPubKeyHash_Elysium()); - } - - Shuffle(txOutputs.begin(), txOutputs.end(), FastRandomContext()); - - CTransaction dummyTx = TxClassB(txInputs, txOutputs); - BOOST_CHECK_EQUAL(dummyTx.vout.size(), nOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(metaTx.getRaw().size(), getPayloadSize(CLASS_B_MAX_CHUNKS)); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/parsing_c_tests.cpp b/src/elysium/test/parsing_c_tests.cpp deleted file mode 100644 index 9e4fb5cb69..0000000000 --- a/src/elysium/test/parsing_c_tests.cpp +++ /dev/null @@ -1,441 +0,0 @@ -#include "utils_tx.h" - -#include "../createpayload.h" -#include "../elysium.h" -#include "../packetencoder.h" -#include "../rules.h" -#include "../script.h" -#include "../tx.h" - -#include "../../base58.h" -#include "../../coins.h" -#include "../../utilstrencodings.h" - -#include "../../primitives/transaction.h" - -#include "../../script/script.h" -#include "../../script/standard.h" - -#include "../../test/test_bitcoin.h" - -#include - -#include -#include - -#include - -namespace elysium { - -BOOST_FIXTURE_TEST_SUITE(elysium_parsing_c_tests, BasicTestingSetup) - -/** Creates a dummy transaction with the given inputs and outputs. */ -static CTransaction TxClassC(const std::vector& txInputs, const std::vector& txOuts) -{ - CMutableTransaction mutableTx; - - // Inputs: - for (std::vector::const_iterator it = txInputs.begin(); it != txInputs.end(); ++it) - { - const CTxOut& txOut = *it; - - // Create transaction for input: - CMutableTransaction inputTx; - unsigned int nOut = 0; - inputTx.vout.push_back(txOut); - CTransaction tx(inputTx); - - // Populate transaction cache: - ModifyCoin(view, COutPoint(tx.GetHash(), 0), - [&txOut](Coin & coin){ - coin.out.scriptPubKey = txOut.scriptPubKey; - coin.out.nValue = txOut.nValue; - }); - - // Add input: - CTxIn txIn(tx.GetHash(), nOut); - mutableTx.vin.push_back(txIn); - } - - for (std::vector::const_iterator it = txOuts.begin(); it != txOuts.end(); ++it) - { - const CTxOut& txOut = *it; - mutableTx.vout.push_back(txOut); - } - - return CTransaction(mutableTx); -} - -/** Helper to create a CTxOut object. */ -static CTxOut createTxOut(int64_t amount, const std::string& dest) -{ - return CTxOut(amount, GetScriptForDestination(CBitcoinAddress(dest).Get())); -} - -BOOST_AUTO_TEST_CASE(reference_identification) -{ - { - int nBlock = ConsensusParams().NULLDATA_BLOCK; - - std::vector txInputs; - txInputs.push_back(createTxOut(5000000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - txOutputs.push_back(OpReturn_SimpleSend()); - txOutputs.push_back(createTxOut(2700000, GetSystemAddress().ToString())); - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK(metaTx.getReceiver().empty()); - BOOST_CHECK_EQUAL(metaTx.getFeePaid(), 2300000); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(HexStr(metaTx.getRaw()), "00000000000000070000000006dac2c0"); - } - { - int nBlock = ConsensusParams().NULLDATA_BLOCK + 1000; - - std::vector txInputs; - txInputs.push_back(createTxOut(6000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - txOutputs.push_back(OpReturn_SimpleSend()); - txOutputs.push_back(createTxOut(6000, "a11WeUi6HFkHNdG5puD9LHCXTySddeNcu8")); - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getFeePaid(), 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(metaTx.getReceiver(), "a11WeUi6HFkHNdG5puD9LHCXTySddeNcu8"); - BOOST_CHECK_EQUAL(HexStr(metaTx.getRaw()), "00000000000000070000000006dac2c0"); - } - { - int nBlock = std::numeric_limits::max(); - - std::vector txInputs; - txInputs.push_back(createTxOut(80000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - txOutputs.push_back(OpReturn_SimpleSend()); - txOutputs.push_back(createTxOut(6000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getFeePaid(), 74000); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(metaTx.getReceiver(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(HexStr(metaTx.getRaw()), "00000000000000070000000006dac2c0"); - } - { - int nBlock = std::numeric_limits::max(); - - std::vector txInputs; - txInputs.push_back(createTxOut(80000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - txOutputs.push_back(OpReturn_SimpleSend()); - txOutputs.push_back(createTxOut(6000, "a1SNP5FDj2HykF2Yg2Jr3Kzu8vMbyuVoyV")); - txOutputs.push_back(PayToPubKey_Unrelated()); - txOutputs.push_back(NonStandardOutput()); - txOutputs.push_back(createTxOut(6000, "a1ALDLF27Efz4NEAkQPLkfUXmBCG7YfwMN")); - txOutputs.push_back(PayToBareMultisig_1of3()); - txOutputs.push_back(createTxOut(6000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(metaTx.getReceiver(), "a1ALDLF27Efz4NEAkQPLkfUXmBCG7YfwMN"); - } - { - int nBlock = std::numeric_limits::max(); - - std::vector txInputs; - txInputs.push_back(createTxOut(55550, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - txOutputs.push_back(createTxOut(6000, "a1ALDLF27Efz4NEAkQPLkfUXmBCG7YfwMN")); - txOutputs.push_back(PayToPubKey_Unrelated()); - txOutputs.push_back(NonStandardOutput()); - txOutputs.push_back(createTxOut(6000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - txOutputs.push_back(createTxOut(6000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - txOutputs.push_back(PayToPubKeyHash_Elysium()); - txOutputs.push_back(OpReturn_SimpleSend()); - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(metaTx.getReceiver(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - } -} - -BOOST_AUTO_TEST_CASE(empty_op_return) -{ - { - int nBlock = std::numeric_limits::max(); - - std::vector txInputs; - txInputs.push_back(createTxOut(900000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - txOutputs.push_back(OpReturn_PlainMarker()); - txOutputs.push_back(PayToPubKeyHash_Unrelated()); - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK(metaTx.getRaw().empty()); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - // via PayToPubKeyHash_Unrelated: - BOOST_CHECK_EQUAL(metaTx.getReceiver(), "a6FFPX9EvcDCtKCzootN4EMwMv2K9xnVcV"); - } -} - - -BOOST_AUTO_TEST_CASE(trimmed_op_return) -{ - { - int nBlock = std::numeric_limits::max(); - - std::vector txInputs; - txInputs.push_back(createTxOut(100000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - - std::vector vchFiller(CLASS_B_MAX_CHUNKS * CLASS_B_CHUNK_SIZE, 0x07); - std::vector vchPayload(magic.begin(), magic.end()); - vchPayload.insert(vchPayload.end(), vchFiller.begin(), vchFiller.end()); - - // These will be trimmed: - vchPayload.push_back(0x44); - vchPayload.push_back(0x44); - vchPayload.push_back(0x44); - - CScript scriptPubKey; - scriptPubKey << OP_RETURN; - scriptPubKey << vchPayload; - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(HexStr(metaTx.getRaw()), HexStr(vchFiller.begin(), vchFiller.end())); - BOOST_CHECK_EQUAL(metaTx.getRaw().size(), CLASS_B_MAX_CHUNKS * CLASS_B_CHUNK_SIZE); - } -} - -BOOST_AUTO_TEST_CASE(multiple_op_return_short) -{ - { - int nBlock = ConsensusParams().NULLDATA_BLOCK; - - std::vector txInputs; - txInputs.push_back(createTxOut(100000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("65786f6475730000111122223333"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN; - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("65786f6475730001000200030004"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("65786f647573"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(HexStr(metaTx.getRaw()), "00001111222233330001000200030004"); - } -} - -BOOST_AUTO_TEST_CASE(multiple_op_return) -{ - { - int nBlock = ConsensusParams().NULLDATA_BLOCK; - - std::vector txInputs; - txInputs.push_back(createTxOut(100000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("65786f6475731222222222222222222222222223"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("65786f6475734555555555555555555555555556"); - CTxOut txOut = CTxOut(5, scriptPubKey); - txOutputs.push_back(txOut); - } - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("65786f647573788888888889"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - { - CScript scriptPubKey; // has no marker and will be ignored! - scriptPubKey << OP_RETURN << ParseHex("4d756c686f6c6c616e64204472697665"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("65786f647573ffff11111111111111111111" - "11111111111111111111111111111111111111111111111111111111111111" - "11111111111111111111111111111111111111111111111111111111111111" - "111111111111111111111111111111111111111111111117"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(HexStr(metaTx.getRaw()), "12222222222222222222222222234555555" - "555555555555555555556788888888889ffff11111111111111111111111111111" - "111111111111111111111111111111111111111111111111111111111111111111" - "111111111111111111111111111111111111111111111111111111111111111111" - "1111111111111111111111111111117"); - } -} - -BOOST_AUTO_TEST_CASE(multiple_op_return_pushes) -{ - { - int nBlock = std::numeric_limits::max(); - - std::vector txInputs; - txInputs.push_back(createTxOut(100000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - txInputs.push_back(PayToBareMultisig_3of5()); - - std::vector txOutputs; - txOutputs.push_back(OpReturn_SimpleSend()); - txOutputs.push_back(PayToScriptHash_Unrelated()); - txOutputs.push_back(OpReturn_MultiSimpleSend()); - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(HexStr(metaTx.getRaw()), - // OpReturn_SimpleSend (without marker): - "00000000000000070000000006dac2c0" - // OpReturn_MultiSimpleSend (without marker): - "00000000000000070000000000002329" - "0062e907b15cbf27d5425399ebf6f0fb50ebb88f18" - "000000000000001f0000000001406f40" - "05da59767e81f4b019fe9f5984dbaa4f61bf197967"); - } - { - int nBlock = ConsensusParams().NULLDATA_BLOCK; - - std::vector txInputs; - txInputs.push_back(createTxOut(100000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN; - scriptPubKey << ParseHex("65786f64757300000000000000010000000006dac2c0"); - scriptPubKey << ParseHex("00000000000000030000000000000d48"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(metaTx.getSender(), "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd"); - BOOST_CHECK_EQUAL(HexStr(metaTx.getRaw()), - "00000000000000010000000006dac2c000000000000000030000000000000d48"); - } - { - int nBlock = std::numeric_limits::max(); - - std::vector txInputs; - txInputs.push_back(createTxOut(100000, "ZzjEgpoT2pARc5Un7xRJAJ4LPSpA9qLQxd")); - - std::vector txOutputs; - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN; - scriptPubKey << ParseHex("65786f647573"); - scriptPubKey << ParseHex("00000000000000010000000006dac2c0"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0); - BOOST_CHECK_EQUAL(HexStr(metaTx.getRaw()), "00000000000000010000000006dac2c0"); - } - { - /** - * The following transaction is invalid, because the first pushed data - * doesn't contain the class C marker. - */ - int nBlock = ConsensusParams().NULLDATA_BLOCK; - - std::vector txInputs; - txInputs.push_back(createTxOut(100000, "3LzuqJs1deHYeFyJz5JXqrZXpuMk3GBEX2")); - - std::vector txOutputs; - { - CScript scriptPubKey; - scriptPubKey << OP_RETURN; - scriptPubKey << ParseHex("6f6d"); - scriptPubKey << ParseHex("6e69"); - scriptPubKey << ParseHex("00000000000000010000000006dac2c0"); - CTxOut txOut = CTxOut(0, scriptPubKey); - txOutputs.push_back(txOut); - } - - CTransaction dummyTx = TxClassC(txInputs, txOutputs); - - CMPTransaction metaTx; - BOOST_CHECK(ParseTransaction(dummyTx, nBlock, 1, metaTx) != 0); - } -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/property_tests.cpp b/src/elysium/test/property_tests.cpp deleted file mode 100644 index 40d66bfa07..0000000000 --- a/src/elysium/test/property_tests.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "../property.h" - -#include - -#include -#include - -namespace elysium { - -BOOST_AUTO_TEST_SUITE(elysium_property_tests) - -BOOST_AUTO_TEST_CASE(sigma_status_is_enabled_flag) -{ - typedef std::underlying_type::type SigmaStatusBaseType; - - auto i = std::numeric_limits::min(); - - do { - auto flag = static_cast(i); - auto res = IsEnabledFlag(flag); - - switch (flag) { - case SigmaStatus::SoftEnabled: - case SigmaStatus::HardEnabled: - BOOST_CHECK_EQUAL(res, true); - break; - default: - BOOST_CHECK_EQUAL(res, false); - } - } while (i++ == std::numeric_limits::max()); -} - -BOOST_AUTO_TEST_SUITE_END() - -} diff --git a/src/elysium/test/rounduint64_tests.cpp b/src/elysium/test/rounduint64_tests.cpp deleted file mode 100644 index 6c0a4182f5..0000000000 --- a/src/elysium/test/rounduint64_tests.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "elysium/convert.h" - -#include "test/test_bitcoin.h" - -#include - -#include - -using namespace elysium; - -BOOST_FIXTURE_TEST_SUITE(elysium_rounduint64_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(rounduint64_simple) -{ - const int64_t COIN = 100000000; - double unit_price = 23.45678923999; - BOOST_CHECK_EQUAL(2345678924U, rounduint64(COIN * unit_price)); -} - -BOOST_AUTO_TEST_CASE(rounduint64_whole_units) -{ - BOOST_CHECK_EQUAL(0U, rounduint64(0.0)); - BOOST_CHECK_EQUAL(1U, rounduint64(1.0)); - BOOST_CHECK_EQUAL(2U, rounduint64(2.0)); - BOOST_CHECK_EQUAL(3U, rounduint64(3.0)); -} - -BOOST_AUTO_TEST_CASE(rounduint64_round_below_point_5) -{ - BOOST_CHECK_EQUAL(0U, rounduint64(0.49999999)); - BOOST_CHECK_EQUAL(1U, rounduint64(1.49999999)); - BOOST_CHECK_EQUAL(2U, rounduint64(2.49999999)); - BOOST_CHECK_EQUAL(3U, rounduint64(3.49999999)); -} - -BOOST_AUTO_TEST_CASE(rounduint64_round_point_5) -{ - BOOST_CHECK_EQUAL(1U, rounduint64(0.5)); - BOOST_CHECK_EQUAL(2U, rounduint64(1.5)); - BOOST_CHECK_EQUAL(3U, rounduint64(2.5)); - BOOST_CHECK_EQUAL(4U, rounduint64(3.5)); -} - -BOOST_AUTO_TEST_CASE(rounduint64_round_over_point_5) -{ - BOOST_CHECK_EQUAL(1U, rounduint64(0.50000001)); - BOOST_CHECK_EQUAL(2U, rounduint64(1.50000001)); - BOOST_CHECK_EQUAL(3U, rounduint64(2.50000001)); - BOOST_CHECK_EQUAL(4U, rounduint64(3.50000001)); -} - -BOOST_AUTO_TEST_CASE(rounduint64_limits) -{ - BOOST_CHECK_EQUAL( // 8 bits signed - 127U, - rounduint64(127.0)); - BOOST_CHECK_EQUAL( // 8 bits unsigned - 255U, - rounduint64(255.0)); - BOOST_CHECK_EQUAL( // 16 bits signed - 32767U, - rounduint64(32767.0)); - BOOST_CHECK_EQUAL( // 16 bits unsigned - 65535U, - rounduint64(65535.0)); - BOOST_CHECK_EQUAL( // 32 bits signed - 2147483647U, - rounduint64(2147483647.0)); - BOOST_CHECK_EQUAL( // 32 bits unsigned - 4294967295U, - rounduint64(4294967295.0)); - BOOST_CHECK_EQUAL( // 52 bits signed - 4503599627370496U, - rounduint64(4503599627370496.0)); - BOOST_CHECK_EQUAL( // 52 bits unsigned - 9007199254740992U, - rounduint64(9007199254740992.0)); -} - -BOOST_AUTO_TEST_CASE(rounduint64_types) -{ - BOOST_CHECK_EQUAL( - rounduint64(static_cast(1.23456789)), - rounduint64(static_cast(1.23456789))); - BOOST_CHECK_EQUAL( - rounduint64(static_cast(1.23456789)), - rounduint64(static_cast(1.23456789))); - BOOST_CHECK_EQUAL( - rounduint64(static_cast(1.23456789)), - rounduint64(static_cast(1.23456789))); - BOOST_CHECK_EQUAL( - rounduint64(static_cast(1.23456789)), - rounduint64(static_cast(1.23456789))); - BOOST_CHECK_EQUAL( - rounduint64(static_cast(1.23456789)), - rounduint64(static_cast(1.23456789))); - BOOST_CHECK_EQUAL( - rounduint64(static_cast(1.23456789)), - rounduint64(static_cast(1.23456789))); -} - -BOOST_AUTO_TEST_CASE(rounduint64_promotion) -{ - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); - BOOST_CHECK_EQUAL(42U, rounduint64(static_cast(42))); -} - -BOOST_AUTO_TEST_CASE(rounduint64_absolute) -{ - BOOST_CHECK_EQUAL( - rounduint64(-128.0f), - rounduint64(128.0f)); - BOOST_CHECK_EQUAL( - rounduint64(-32768.0), - rounduint64(32768.0)); - BOOST_CHECK_EQUAL( - rounduint64(-65536.0), - rounduint64(65536.0)); - BOOST_CHECK_EQUAL( - rounduint64(-2147483648.0), - rounduint64(2147483648.0)); - BOOST_CHECK_EQUAL( - rounduint64(-4294967296.0), - rounduint64(4294967296.0)); - BOOST_CHECK_EQUAL( - rounduint64(-9223372036854775807.0), - rounduint64(9223372036854775807.0)); -} - -BOOST_AUTO_TEST_CASE(rounduint64_special_cases) -{ - BOOST_CHECK_EQUAL(0U, rounduint64(static_cast(0.49999999999999994))); - BOOST_CHECK_EQUAL(2147483648U, rounduint64(static_cast(-2147483647-1))); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/rules_txs_tests.cpp b/src/elysium/test/rules_txs_tests.cpp deleted file mode 100644 index bf197b771e..0000000000 --- a/src/elysium/test/rules_txs_tests.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "../rules.h" -#include "../tx.h" - -#include "../../test/test_bitcoin.h" - -#include - -#include - -#include - -namespace elysium { - -const int MAX_BLOCK = std::numeric_limits::max(); -const int MAX_VERSION = std::numeric_limits::max(); - -BOOST_FIXTURE_TEST_SUITE(elysium_rules_txs_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(simple_send_restrictions) -{ - int ELYSIUM_SEND_BLOCK = ConsensusParams().ELYSIUM_SEND_BLOCK; - - BOOST_CHECK(!IsTransactionTypeAllowed(0, ELYSIUM_PROPERTY_XZC, ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V0)); - BOOST_CHECK(!IsTransactionTypeAllowed(ELYSIUM_SEND_BLOCK, ELYSIUM_PROPERTY_XZC, ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V0)); - BOOST_CHECK(!IsTransactionTypeAllowed(MAX_BLOCK, ELYSIUM_PROPERTY_XZC, ELYSIUM_TYPE_SIMPLE_SEND, MAX_VERSION)); - BOOST_CHECK(!IsTransactionTypeAllowed(0, ELYSIUM_PROPERTY_ELYSIUM, ELYSIUM_TYPE_SIMPLE_SEND, MAX_VERSION)); - BOOST_CHECK(!IsTransactionTypeAllowed(ELYSIUM_SEND_BLOCK-1, ELYSIUM_PROPERTY_ELYSIUM, ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V0)); - BOOST_CHECK(!IsTransactionTypeAllowed(MAX_BLOCK, ELYSIUM_PROPERTY_ELYSIUM, ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V1)); - BOOST_CHECK(!IsTransactionTypeAllowed(ELYSIUM_SEND_BLOCK, ELYSIUM_PROPERTY_TELYSIUM, ELYSIUM_TYPE_SIMPLE_SEND, MAX_VERSION)); - BOOST_CHECK(!IsTransactionTypeAllowed(MAX_BLOCK, ELYSIUM_PROPERTY_TELYSIUM, ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V1)); - - BOOST_CHECK(IsTransactionTypeAllowed(ELYSIUM_SEND_BLOCK, ELYSIUM_PROPERTY_ELYSIUM, ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V0)); - BOOST_CHECK(IsTransactionTypeAllowed(MAX_BLOCK, ELYSIUM_PROPERTY_ELYSIUM, ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V0)); - BOOST_CHECK(IsTransactionTypeAllowed(0, ELYSIUM_PROPERTY_TELYSIUM, ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V0)); - BOOST_CHECK(IsTransactionTypeAllowed(MAX_BLOCK, ELYSIUM_PROPERTY_TELYSIUM, ELYSIUM_TYPE_SIMPLE_SEND, MP_TX_PKT_V0)); -} - -BOOST_AUTO_TEST_SUITE_END() - -} diff --git a/src/elysium/test/script_extraction_tests.cpp b/src/elysium/test/script_extraction_tests.cpp deleted file mode 100644 index 0f2cf503a2..0000000000 --- a/src/elysium/test/script_extraction_tests.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#include "../script.h" - -#include "../../base58.h" -#include "../../pubkey.h" -#include "../../utilstrencodings.h" - -#include "../../script/script.h" - -#include "../../test/test_bitcoin.h" - -#include - -#include -#include -#include - -namespace std { - -template -basic_ostream& operator<<(basic_ostream& os, const std::vector& v) -{ - return os << HexStr(v); -} - -} // namespace std - -namespace elysium { - -BOOST_FIXTURE_TEST_SUITE(elysium_script_extraction_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(extract_pubkey_test) -{ - std::vector vchPayload = ParseHex( - "0347d08029b5cbc934f6079b650c50718eab5a56d51cf6b742ec9f865a41fcfca3"); - CPubKey pubKey(vchPayload.begin(), vchPayload.end()); - - // Pay-to-pubkey script - CScript script; - script << ToByteVector(pubKey) << OP_CHECKSIG; - - // Check script type - txnouttype outtype; - BOOST_CHECK(GetOutputType(script, outtype)); - BOOST_CHECK_EQUAL(outtype, TX_PUBKEY); - - // Confirm extracted data - std::vector> solutions; - - GetPushedValues(script, std::back_inserter(solutions)); - - BOOST_CHECK_EQUAL(solutions.size(), 1); - BOOST_CHECK_EQUAL(solutions[0], vchPayload); -} - -BOOST_AUTO_TEST_CASE(extract_pubkeyhash_test) -{ - std::vector vchPayload = ParseHex( - "0347d08029b5cbc934f6079b650c50718eab5a56d51cf6b742ec9f865a41fcfca3"); - - CPubKey pubKey(vchPayload.begin(), vchPayload.end()); - CKeyID keyId = pubKey.GetID(); - - // Pay-to-pubkey-hash script - CScript script; - script << OP_DUP << OP_HASH160 << ToByteVector(keyId) << OP_EQUALVERIFY << OP_CHECKSIG; - - // Check script type - txnouttype outtype; - BOOST_CHECK(GetOutputType(script, outtype)); - BOOST_CHECK_EQUAL(outtype, TX_PUBKEYHASH); - - // Confirm extracted data - std::vector> solutions; - - GetPushedValues(script, std::back_inserter(solutions)); - - BOOST_CHECK_EQUAL(solutions.size(), 1); - BOOST_CHECK_EQUAL(solutions[0], ToByteVector(keyId)); -} - -BOOST_AUTO_TEST_CASE(extract_multisig_test) -{ - std::vector vchPayload1 = ParseHex( - "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd"); - std::vector vchPayload2 = ParseHex( - "0276f798620d7d0930711ab68688fc67ee2f5bbe0c1481506b08bd65e6053c16ca"); - std::vector vchPayload3 = ParseHex( - "02bf12b315172dc1b261d62dd146868ef9c9e2e108fa347f347f66bc048e9b15e4"); - - CPubKey pubKey1(vchPayload1.begin(), vchPayload1.end()); - CPubKey pubKey2(vchPayload2.begin(), vchPayload2.end()); - CPubKey pubKey3(vchPayload3.begin(), vchPayload3.end()); - - // 1-of-3 bare multisig script - CScript script; - script << CScript::EncodeOP_N(1); - script << ToByteVector(pubKey1) << ToByteVector(pubKey2) << ToByteVector(pubKey3); - script << CScript::EncodeOP_N(3); - script << OP_CHECKMULTISIG; - - // Check script type - txnouttype outtype; - BOOST_CHECK(GetOutputType(script, outtype)); - BOOST_CHECK_EQUAL(outtype, TX_MULTISIG); - - // Confirm extracted data - std::vector> solutions; - - GetPushedValues(script, std::back_inserter(solutions)); - - BOOST_CHECK_EQUAL(solutions.size(), 3); - BOOST_CHECK_EQUAL(solutions[0], vchPayload1); - BOOST_CHECK_EQUAL(solutions[1], vchPayload2); - BOOST_CHECK_EQUAL(solutions[2], vchPayload3); -} - -BOOST_AUTO_TEST_CASE(extract_scripthash_test) -{ - std::vector vchInnerScript = ParseHex( - "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000"); - - // A transaction puzzle (not relevant) - CScript scriptInner; - scriptInner << OP_HASH256 << vchInnerScript << OP_EQUAL; - - // The actual hash - CScriptID innerId(scriptInner); - - // Pay-to-script-hash script - CScript script; - script << OP_HASH160 << ToByteVector(innerId) << OP_EQUAL; - - // Check script type - txnouttype outtype; - BOOST_CHECK(GetOutputType(script, outtype)); - BOOST_CHECK_EQUAL(outtype, TX_SCRIPTHASH); - - // Confirm extracted data - std::vector> solutions; - - GetPushedValues(script, std::back_inserter(solutions)); - - BOOST_CHECK_EQUAL(solutions.size(), 1); - BOOST_CHECK_EQUAL(solutions[0], ToByteVector(innerId)); -} - -BOOST_AUTO_TEST_CASE(extract_no_nulldata_test) -{ - // Null data script - CScript script; - script << OP_RETURN; - - // Check script type - txnouttype outtype; - BOOST_CHECK(GetOutputType(script, outtype)); - BOOST_CHECK_EQUAL(outtype, TX_NULL_DATA); - - // Confirm extracted data - std::vector> solutions; - - GetPushedValues(script, std::back_inserter(solutions)); - - BOOST_CHECK_EQUAL(solutions.size(), 0); -} - -BOOST_AUTO_TEST_CASE(extract_empty_nulldata_test) -{ - // Null data script - CScript script; - script << OP_RETURN << ParseHex(""); - - // Check script type - txnouttype outtype; - BOOST_CHECK(GetOutputType(script, outtype)); - BOOST_CHECK_EQUAL(outtype, TX_NULL_DATA); - - // Confirm extracted data - std::vector> solutions; - - GetPushedValues(script, std::back_inserter(solutions)); - - BOOST_CHECK_EQUAL(solutions.size(), 1); - BOOST_CHECK_EQUAL(solutions[0].size(), 0); -} - -BOOST_AUTO_TEST_CASE(extract_nulldata_test) -{ - std::vector vchPayload = ParseHex( - "657874726163745f6e756c6c646174615f74657374"); - - // Null data script - CScript script; - script << OP_RETURN << vchPayload; - - // Check script type - txnouttype outtype; - BOOST_CHECK(GetOutputType(script, outtype)); - BOOST_CHECK_EQUAL(outtype, TX_NULL_DATA); - - // Confirm extracted data - std::vector> solutions; - - GetPushedValues(script, std::back_inserter(solutions)); - - BOOST_CHECK_EQUAL(solutions.size(), 1); - BOOST_CHECK_EQUAL(solutions[0], vchPayload); -} - -BOOST_AUTO_TEST_CASE(extract_nulldata_multipush_test) -{ - std::vector vstrPayloads; - vstrPayloads.push_back("6f6d"); - vstrPayloads.push_back("00000000000000010000000006dac2c0"); - vstrPayloads.push_back("01d84bcec5b65aa1a03d6abfd975824c75856a2961"); - vstrPayloads.push_back("00000000000000030000000000000d48"); - vstrPayloads.push_back("05627138bb55251bfb289a1ec390eafd3755b1a698"); - vstrPayloads.push_back("00000032010001000000005465737473004f6d6e6920436f726500546573" - "7420546f6b656e7300687474703a2f2f6275696c6465722e62697477617463682e636f2f005" - "573656420746f2074657374207468652065787472616374696f6e206f66206d756c7469706c" - "652070757368657320696e20616e204f505f52455455524e207363726970742e00000000000" - "00f4240"); - - // Null data script - CScript script; - script << OP_RETURN; - for (unsigned n = 0; n < vstrPayloads.size(); ++n) { - script << ParseHex(vstrPayloads[n]); - } - - // Check script type - txnouttype outtype; - BOOST_CHECK(GetOutputType(script, outtype)); - BOOST_CHECK_EQUAL(outtype, TX_NULL_DATA); - - // Confirm extracted data - std::vector> solutions; - - GetPushedValues(script, std::back_inserter(solutions)); - - BOOST_CHECK_EQUAL(solutions.size(), vstrPayloads.size()); - - for (unsigned n = 0; n < solutions.size(); ++n) { - BOOST_CHECK_EQUAL(HexStr(solutions[n]), vstrPayloads[n]); - } -} - -BOOST_AUTO_TEST_CASE(extract_anypush_test) -{ - std::vector > vvchPayloads; - vvchPayloads.push_back(ParseHex("111111")); - vvchPayloads.push_back(ParseHex("222222")); - vvchPayloads.push_back(ParseHex("333333")); - vvchPayloads.push_back(ParseHex("444444")); - vvchPayloads.push_back(ParseHex("555555")); - - // Non-standard script - CScript script; - script << vvchPayloads[0] << OP_DROP; - script << vvchPayloads[1] << OP_DROP; - script << vvchPayloads[2] << OP_DROP; - script << vvchPayloads[3] << OP_DROP; - script << vvchPayloads[4]; - - // Check script type - txnouttype outtype; - BOOST_CHECK(!GetOutputType(script, outtype)); - BOOST_CHECK_EQUAL(outtype, TX_NONSTANDARD); - - // Confirm extracted data - std::vector> solutions; - - GetPushedValues(script, std::back_inserter(solutions)); - - BOOST_CHECK_EQUAL(solutions.size(), vvchPayloads.size()); - - for (size_t n = 0; n < solutions.size(); ++n) { - BOOST_CHECK_EQUAL(solutions[n], vvchPayloads[n]); - } -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/script_solver_tests.cpp b/src/elysium/test/script_solver_tests.cpp deleted file mode 100644 index b3c2eaa35c..0000000000 --- a/src/elysium/test/script_solver_tests.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "elysium/script.h" - -#include "script/script.h" -#include "test/test_bitcoin.h" -#include "util.h" - -#include - -#include - -/** To be set in the tests. */ -extern unsigned nMaxDatacarrierBytes; - -BOOST_FIXTURE_TEST_SUITE(elysium_script_solver_tests, BasicTestingSetup) - -/** Checks whether the custom solver is unaffected by user settings. */ -static void CheckOutputType(const CScript& script, txnouttype outTypeExpected) -{ - // Explicit check via SafeSolver - txnouttype outTypeExplicit; - std::vector > vSolutions; - BOOST_CHECK(SafeSolver(script, outTypeExplicit, vSolutions)); - BOOST_CHECK_EQUAL(outTypeExplicit, outTypeExpected); - - // Implicit check via GetOutputType - txnouttype outTypeImplicit; - BOOST_CHECK(GetOutputType(script, outTypeImplicit)); - BOOST_CHECK_EQUAL(outTypeImplicit, outTypeExpected); -} - -BOOST_AUTO_TEST_CASE(solve_op_return_test) -{ - // Store initial data carrier size - unsigned nMaxDatacarrierBytesOriginal = nMaxDatacarrierBytes; - - // Empty data script without payload - CScript scriptNoData; - scriptNoData << OP_RETURN; - - // Data script with standard sized 40 byte payload - CScript scriptDefault; - scriptDefault << OP_RETURN << std::vector(40, 0x40); - - // Data script with large 80 byte payload - CScript scriptLarge; - scriptLarge << OP_RETURN << std::vector(80, 0x80); - - // Data script with extremely large 2500 byte payload - CScript scriptExtreme; - scriptExtreme << OP_RETURN << std::vector(2500, 0x07); - - // Default settings - CheckOutputType(scriptNoData, TX_NULL_DATA); - CheckOutputType(scriptDefault, TX_NULL_DATA); - CheckOutputType(scriptLarge, TX_NULL_DATA); - CheckOutputType(scriptExtreme, TX_NULL_DATA); - - // Tests with different data carrier size settings following ... - nMaxDatacarrierBytes = 0; - CheckOutputType(scriptNoData, TX_NULL_DATA); - CheckOutputType(scriptDefault, TX_NULL_DATA); - CheckOutputType(scriptLarge, TX_NULL_DATA); - CheckOutputType(scriptExtreme, TX_NULL_DATA); - - nMaxDatacarrierBytes = 40; - CheckOutputType(scriptNoData, TX_NULL_DATA); - CheckOutputType(scriptDefault, TX_NULL_DATA); - CheckOutputType(scriptLarge, TX_NULL_DATA); - CheckOutputType(scriptExtreme, TX_NULL_DATA); - - nMaxDatacarrierBytes = 120; - CheckOutputType(scriptNoData, TX_NULL_DATA); - CheckOutputType(scriptDefault, TX_NULL_DATA); - CheckOutputType(scriptLarge, TX_NULL_DATA); - CheckOutputType(scriptExtreme, TX_NULL_DATA); - - nMaxDatacarrierBytes = 2500; - CheckOutputType(scriptNoData, TX_NULL_DATA); - CheckOutputType(scriptDefault, TX_NULL_DATA); - CheckOutputType(scriptLarge, TX_NULL_DATA); - CheckOutputType(scriptExtreme, TX_NULL_DATA); - - // Restore original data carrier size settings - nMaxDatacarrierBytes = nMaxDatacarrierBytesOriginal; -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/sender_bycontribution_tests.cpp b/src/elysium/test/sender_bycontribution_tests.cpp deleted file mode 100644 index 3f189dcc88..0000000000 --- a/src/elysium/test/sender_bycontribution_tests.cpp +++ /dev/null @@ -1,426 +0,0 @@ -#include "elysium/test/utils_tx.h" - -#include "elysium/elysium.h" -#include "elysium/script.h" -#include "elysium/tx.h" - -#include "base58.h" -#include "coins.h" -#include "primitives/transaction.h" -#include "random.h" -#include "script/script.h" -#include "script/standard.h" -#include "test/test_bitcoin.h" - -#include -#include -#include -#include - -#include - -using namespace elysium; - -BOOST_FIXTURE_TEST_SUITE(elysium_sender_bycontribution_tests, BasicTestingSetup) - -// Forward declarations -static CTransaction TxClassB(const std::vector& txInputs); -static bool GetSenderByContribution(const std::vector& vouts, std::string& strSender); -static CTxOut createTxOut(int64_t amount, const std::string& dest); -static CKeyID createRandomKeyId(); -static CScriptID createRandomScriptId(); -void shuffleAndCheck(std::vector& vouts, unsigned nRounds); - -// Test settings -static const unsigned nOutputs = 256; -static const unsigned nAllRounds = 2; -static const unsigned nShuffleRounds = 16; - -/** - * Tests the invalidation of the transaction, when there are not allowed inputs. - */ -BOOST_AUTO_TEST_CASE(invalid_inputs) -{ - { - std::vector vouts; - vouts.push_back(PayToPubKey_Unrelated()); - vouts.push_back(PayToPubKeyHash_Unrelated()); - std::string strSender; - BOOST_CHECK(!GetSenderByContribution(vouts, strSender)); - } - { - std::vector vouts; - vouts.push_back(PayToPubKeyHash_Unrelated()); - vouts.push_back(PayToBareMultisig_1of3()); - std::string strSender; - BOOST_CHECK(!GetSenderByContribution(vouts, strSender)); - } - { - std::vector vouts; - vouts.push_back(PayToScriptHash_Unrelated()); - vouts.push_back(PayToPubKeyHash_Elysium()); - vouts.push_back(NonStandardOutput()); - std::string strSender; - BOOST_CHECK(!GetSenderByContribution(vouts, strSender)); - } -} - -/** - * Tests sender selection "by sum" with pay-to-pubkey-hash outputs, where a single - * candidate has the highest output value. - */ -BOOST_AUTO_TEST_CASE(p2pkh_contribution_by_sum_test) -{ - std::vector vouts; - vouts.push_back(createTxOut(100, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(100, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(100, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(100, "aJThrdhEzf4yZmRwhzSMGxxmeC7BQEwAKC")); - vouts.push_back(createTxOut(100, "aJThrdhEzf4yZmRwhzSMGxxmeC7BQEwAKC")); - vouts.push_back(createTxOut(999, "aAVHyFLdKNH8qHZQYv4eN742hNiVJ9qzHk")); // Winner - vouts.push_back(createTxOut(100, "a5jQZJwpAr3tsEyCziq5NkeRTj8pJ5bakm")); - vouts.push_back(createTxOut(100, "a5jQZJwpAr3tsEyCziq5NkeRTj8pJ5bakm")); - vouts.push_back(createTxOut(100, "a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K")); - - std::string strExpected("aAVHyFLdKNH8qHZQYv4eN742hNiVJ9qzHk"); - - for (int i = 0; i < 10; ++i) { - Shuffle(vouts.begin(), vouts.end(), FastRandomContext()); - - std::string strSender; - BOOST_CHECK(GetSenderByContribution(vouts, strSender)); - BOOST_CHECK_EQUAL(strExpected, strSender); - } -} - -/** - * Tests sender selection "by sum" with pay-to-pubkey-hash outputs, where a candidate - * with the highest output value by sum, with more than one output, is chosen. - */ -BOOST_AUTO_TEST_CASE(p2pkh_contribution_by_total_sum_test) -{ - std::vector vouts; - vouts.push_back(createTxOut(499, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(501, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(295, "aJThrdhEzf4yZmRwhzSMGxxmeC7BQEwAKC")); // Winner - vouts.push_back(createTxOut(310, "aJThrdhEzf4yZmRwhzSMGxxmeC7BQEwAKC")); // Winner - vouts.push_back(createTxOut(400, "aJThrdhEzf4yZmRwhzSMGxxmeC7BQEwAKC")); // Winner - vouts.push_back(createTxOut(500, "aAVHyFLdKNH8qHZQYv4eN742hNiVJ9qzHk")); - vouts.push_back(createTxOut(500, "aAVHyFLdKNH8qHZQYv4eN742hNiVJ9qzHk")); - - std::string strExpected("aJThrdhEzf4yZmRwhzSMGxxmeC7BQEwAKC"); - - for (int i = 0; i < 10; ++i) { - Shuffle(vouts.begin(), vouts.end(), FastRandomContext()); - - std::string strSender; - BOOST_CHECK(GetSenderByContribution(vouts, strSender)); - BOOST_CHECK_EQUAL(strExpected, strSender); - } -} - -/** - * Tests sender selection "by sum" with pay-to-pubkey-hash outputs, where all outputs - * have equal values, and a candidate is chosen based on the lexicographical order of - * the base58 string representation (!) of the candidate. - * - * Note: it reflects the behavior of Elysium Core, but this edge case is not specified. - */ -BOOST_AUTO_TEST_CASE(p2pkh_contribution_by_sum_order_test) -{ - std::vector vouts; - vouts.push_back(createTxOut(1000, "a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K")); // Winner - vouts.push_back(createTxOut(1000, "a2oXxnaSLGfYskMzMh3YHyTre5mCbLL5Mn")); - vouts.push_back(createTxOut(1000, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(1000, "a5jQZJwpAr3tsEyCziq5NkeRTj8pJ5bakm")); - vouts.push_back(createTxOut(1000, "aA3ijhTqu7ywrft9fJGxnEHMUpVjW5ZnrL")); - vouts.push_back(createTxOut(1000, "aAVHyFLdKNH8qHZQYv4eN742hNiVJ9qzHk")); - vouts.push_back(createTxOut(1000, "aEotDaM7dpfUhL1pPdjXqKb5fnWqYwhQmw")); - vouts.push_back(createTxOut(1000, "aJThrdhEzf4yZmRwhzSMGxxmeC7BQEwAKC")); - vouts.push_back(createTxOut(1000, "aLaE4K5z7VeEqLH5KEPGjmv32eVkr9dKf5")); - - std::string strExpected("a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K"); - - for (int i = 0; i < 10; ++i) { - Shuffle(vouts.begin(), vouts.end(), FastRandomContext()); - - std::string strSender; - BOOST_CHECK(GetSenderByContribution(vouts, strSender)); - BOOST_CHECK_EQUAL(strExpected, strSender); - } -} - -/** - * Tests sender selection "by sum" with pay-to-script-hash outputs, where a single - * candidate has the highest output value. - */ -BOOST_AUTO_TEST_CASE(p2sh_contribution_by_sum_test) -{ - std::vector vouts; - vouts.push_back(createTxOut(100, "a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K")); - vouts.push_back(createTxOut(150, "a2oXxnaSLGfYskMzMh3YHyTre5mCbLL5Mn")); - vouts.push_back(createTxOut(400, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(100, "a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K")); - vouts.push_back(createTxOut(400, "a5jQZJwpAr3tsEyCziq5NkeRTj8pJ5bakm")); - vouts.push_back(createTxOut(100, "a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K")); - vouts.push_back(createTxOut(777, "aA3ijhTqu7ywrft9fJGxnEHMUpVjW5ZnrL")); // Winner - vouts.push_back(createTxOut(100, "aAVHyFLdKNH8qHZQYv4eN742hNiVJ9qzHk")); - - std::string strExpected("aA3ijhTqu7ywrft9fJGxnEHMUpVjW5ZnrL"); - - for (int i = 0; i < 10; ++i) { - Shuffle(vouts.begin(), vouts.end(), FastRandomContext()); - - std::string strSender; - BOOST_CHECK(GetSenderByContribution(vouts, strSender)); - BOOST_CHECK_EQUAL(strExpected, strSender); - } -} - -/** - * Tests sender selection "by sum" with pay-to-pubkey-hash and pay-to-script-hash - * outputs mixed, where a candidate with the highest output value by sum, with more - * than one output, is chosen. - */ -BOOST_AUTO_TEST_CASE(p2sh_contribution_by_total_sum_test) -{ - std::vector vouts; - - vouts.push_back(createTxOut(100, "a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K")); - vouts.push_back(createTxOut(500, "a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K")); - vouts.push_back(createTxOut(600, "a2oXxnaSLGfYskMzMh3YHyTre5mCbLL5Mn")); // Winner - vouts.push_back(createTxOut(500, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(100, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(350, "a2oXxnaSLGfYskMzMh3YHyTre5mCbLL5Mn")); // Winner - vouts.push_back(createTxOut(110, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - - std::string strExpected("a2oXxnaSLGfYskMzMh3YHyTre5mCbLL5Mn"); - - for (int i = 0; i < 10; ++i) { - Shuffle(vouts.begin(), vouts.end(), FastRandomContext()); - - std::string strSender; - BOOST_CHECK(GetSenderByContribution(vouts, strSender)); - BOOST_CHECK_EQUAL(strExpected, strSender); - } -} - -/** - * Tests sender selection "by sum" with pay-to-script-hash outputs, where all outputs - * have equal values, and a candidate is chosen based on the lexicographical order of - * the base58 string representation (!) of the candidate. - * - * Note: it reflects the behavior of Elysium Core, but this edge case is not specified. - */ -BOOST_AUTO_TEST_CASE(p2sh_contribution_by_sum_order_test) -{ - std::vector vouts; - vouts.push_back(createTxOut(1000, "a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K")); // Winner - vouts.push_back(createTxOut(1000, "a2oXxnaSLGfYskMzMh3YHyTre5mCbLL5Mn")); - vouts.push_back(createTxOut(1000, "a3mKUoQmmmJQJY2kTiEb2mdSaaJpExDR2r")); - vouts.push_back(createTxOut(1000, "a5jQZJwpAr3tsEyCziq5NkeRTj8pJ5bakm")); - vouts.push_back(createTxOut(1000, "aA3ijhTqu7ywrft9fJGxnEHMUpVjW5ZnrL")); - vouts.push_back(createTxOut(1000, "aAVHyFLdKNH8qHZQYv4eN742hNiVJ9qzHk")); - vouts.push_back(createTxOut(1000, "aEotDaM7dpfUhL1pPdjXqKb5fnWqYwhQmw")); - vouts.push_back(createTxOut(1000, "aJThrdhEzf4yZmRwhzSMGxxmeC7BQEwAKC")); - vouts.push_back(createTxOut(1000, "aLaE4K5z7VeEqLH5KEPGjmv32eVkr9dKf5")); - - std::string strExpected("a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K"); - - for (int i = 0; i < 10; ++i) { - Shuffle(vouts.begin(), vouts.end(), FastRandomContext()); - - std::string strSender; - BOOST_CHECK(GetSenderByContribution(vouts, strSender)); - BOOST_CHECK_EQUAL(strExpected, strSender); - } -} - -/** - * Tests sender selection "by sum", where the lexicographical order of the base58 - * representation as string (instead of uint160) determines the chosen candidate. - * - * In practise this implies selecting the sender "by sum" via a comparison of - * CBitcoinAddress objects would yield faulty results. - * - * Note: it reflects the behavior of Elysium Core, but this edge case is not specified. - */ -BOOST_AUTO_TEST_CASE(sender_selection_string_based_test) -{ - std::vector vouts; - vouts.push_back(createTxOut(1000, "a11WeUi6HFkHNdG5puD9LHCXTySddeNcu8")); // Winner - vouts.push_back(createTxOut(1000, "aA3ijhTqu7ywrft9fJGxnEHMUpVjW5ZnrL")); - vouts.push_back(createTxOut(1000, "aEotDaM7dpfUhL1pPdjXqKb5fnWqYwhQmw")); - // Hash 160: 06569c8f59f428db748c94bf1d5d9f5f9d0db116 - vouts.push_back(createTxOut(1000, "a1CJjinipg4PUDquNiUsP9cTfcyKLvyb3K")); // Not! - - std::string strExpected("a11WeUi6HFkHNdG5puD9LHCXTySddeNcu8"); - - for (int i = 0; i < 24; ++i) { - Shuffle(vouts.begin(), vouts.end(), FastRandomContext()); - - std::string strSender; - BOOST_CHECK(GetSenderByContribution(vouts, strSender)); - BOOST_CHECK_EQUAL(strExpected, strSender); - } -} - -/** - * Tests order independence of the sender selection "by sum" for pay-to-pubkey-hash - * outputs, where all output values are equal. - */ -BOOST_AUTO_TEST_CASE(sender_selection_same_amount_test) -{ - for (unsigned i = 0; i < nAllRounds; ++i) { - std::vector vouts; - for (unsigned n = 0; n < nOutputs; ++n) { - CTxOut output(static_cast(1000), - GetScriptForDestination(createRandomKeyId())); - vouts.push_back(output); - } - shuffleAndCheck(vouts, nShuffleRounds); - } -} - -/** - * Tests order independence of the sender selection "by sum" for pay-to-pubkey-hash - * outputs, where output values are different for each output. - */ -BOOST_AUTO_TEST_CASE(sender_selection_increasing_amount_test) -{ - for (unsigned i = 0; i < nAllRounds; ++i) { - std::vector vouts; - for (unsigned n = 0; n < nOutputs; ++n) { - CTxOut output(static_cast(1000 + n), - GetScriptForDestination(createRandomKeyId())); - vouts.push_back(output); - } - shuffleAndCheck(vouts, nShuffleRounds); - } -} - -/** - * Tests order independence of the sender selection "by sum" for pay-to-pubkey-hash - * and pay-to-script-hash outputs mixed together, where output values are equal for - * every second output. - */ -BOOST_AUTO_TEST_CASE(sender_selection_mixed_test) -{ - for (unsigned i = 0; i < nAllRounds; ++i) { - std::vector vouts; - for (unsigned n = 0; n < nOutputs; ++n) { - CScript scriptPubKey; - if (GetRandInt(2) == 0) { - scriptPubKey = GetScriptForDestination(createRandomKeyId()); - } else { - scriptPubKey = GetScriptForDestination(createRandomScriptId()); - }; - int64_t nAmount = static_cast(1000 - n * (n % 2 == 0)); - vouts.push_back(CTxOut(nAmount, scriptPubKey)); - } - shuffleAndCheck(vouts, nShuffleRounds); - } -} - -/** Creates a dummy class B transaction with the given inputs. */ -static CTransaction TxClassB(const std::vector& txInputs) -{ - CMutableTransaction mutableTx; - - // Inputs: - for (std::vector::const_iterator it = txInputs.begin(); it != txInputs.end(); ++it) - { - const CTxOut& txOut = *it; - - // Create transaction for input: - CMutableTransaction inputTx; - unsigned int nOut = 0; - inputTx.vout.push_back(txOut); - CTransaction tx(inputTx); - - // Populate transaction cache: - ModifyCoin(view, COutPoint(tx.GetHash(), 0), - [&txOut](Coin & coin){ - coin.out.scriptPubKey = txOut.scriptPubKey; - coin.out.nValue = txOut.nValue; - }); - - // Add input: - CTxIn txIn(tx.GetHash(), nOut); - mutableTx.vin.push_back(txIn); - } - - // Outputs: - mutableTx.vout.push_back(PayToPubKeyHash_Elysium()); - mutableTx.vout.push_back(PayToBareMultisig_1of3()); - mutableTx.vout.push_back(PayToPubKeyHash_Unrelated()); - - return CTransaction(mutableTx); -} - -/** Extracts the sender "by contribution". */ -static bool GetSenderByContribution(const std::vector& vouts, std::string& strSender) -{ - int nBlock = std::numeric_limits::max(); - - CMPTransaction metaTx; - CTransaction dummyTx = TxClassB(vouts); - - if (ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0) { - strSender = metaTx.getSender(); - return true; - } - - return false; -} - -/** Helper to create a CTxOut object. */ -static CTxOut createTxOut(int64_t amount, const std::string& dest) -{ - return CTxOut(amount, GetScriptForDestination(CBitcoinAddress(dest).Get())); -} - -/** Helper to create a CKeyID object with random value.*/ -static CKeyID createRandomKeyId() -{ - std::vector vch; - vch.reserve(20); - for (int i = 0; i < 20; ++i) { - vch.push_back(static_cast(GetRandInt(256))); - } - return CKeyID(uint160(vch)); -} - -/** Helper to create a CScriptID object with random value.*/ -static CScriptID createRandomScriptId() -{ - std::vector vch; - vch.reserve(20); - for (int i = 0; i < 20; ++i) { - vch.push_back(static_cast(GetRandInt(256))); - } - return CScriptID(uint160(vch)); -} - -/** - * Identifies the sender of a transaction, based on the list of provided transaction - * outputs, and then shuffles the list n times, while checking, if this produces the - * same result. The "contribution by sum" sender selection doesn't require specific - * positions or order of outputs, and should work in all cases. - */ -void shuffleAndCheck(std::vector& vouts, unsigned nRounds) -{ - std::string strSenderFirst; - BOOST_CHECK(GetSenderByContribution(vouts, strSenderFirst)); - - for (unsigned j = 0; j < nRounds; ++j) { - Shuffle(vouts.begin(), vouts.end(), FastRandomContext()); - - std::string strSender; - BOOST_CHECK(GetSenderByContribution(vouts, strSender)); - BOOST_CHECK_EQUAL(strSenderFirst, strSender); - } -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/sender_firstin_tests.cpp b/src/elysium/test/sender_firstin_tests.cpp deleted file mode 100644 index 0014392b5e..0000000000 --- a/src/elysium/test/sender_firstin_tests.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "utils_tx.h" - -#include "../createpayload.h" -#include "../elysium.h" -#include "../script.h" -#include "../tx.h" - -#include "../../base58.h" -#include "../../coins.h" - -#include "../../primitives/transaction.h" - -#include "../../script/script.h" -#include "../../script/standard.h" - -#include "../../test/test_bitcoin.h" - -#include - -#include -#include - -#include - -namespace elysium { - -BOOST_FIXTURE_TEST_SUITE(elysium_sender_firstin_tests, BasicTestingSetup) - -/** Creates a dummy class C transaction with the given inputs. */ -static CTransaction TxClassC(const std::vector& txInputs) -{ - CMutableTransaction mutableTx; - - // Inputs: - for (std::vector::const_iterator it = txInputs.begin(); it != txInputs.end(); ++it) - { - const CTxOut& txOut = *it; - - // Create transaction for input: - CMutableTransaction inputTx; - unsigned int nOut = 0; - inputTx.vout.push_back(txOut); - CTransaction tx(inputTx); - - // Populate transaction cache: - ModifyCoin(view, COutPoint(tx.GetHash(), 0), - [&txOut](Coin & coin){ - coin.out.scriptPubKey = txOut.scriptPubKey; - coin.out.nValue = txOut.nValue; - }); - - // Add input: - CTxIn txIn(tx.GetHash(), nOut); - mutableTx.vin.push_back(txIn); - } - - // Outputs: - std::vector vchPayload = CreatePayload_SimpleSend(1, 1000); - mutableTx.vout.push_back(EncodeClassC(vchPayload.begin(), vchPayload.end())); - - return CTransaction(mutableTx); -} - -/** Helper to create a CTxOut object. */ -static CTxOut createTxOut(int64_t amount, const std::string& dest) -{ - return CTxOut(amount, GetScriptForDestination(CBitcoinAddress(dest).Get())); -} - -/** Extracts the "first" sender. */ -static bool GetFirstSender(const std::vector& txInputs, std::string& strSender) -{ - int nBlock = std::numeric_limits::max(); - - CMPTransaction metaTx; - CTransaction dummyTx = TxClassC(txInputs); - - if (ParseTransaction(dummyTx, nBlock, 1, metaTx) == 0) { - strSender = metaTx.getSender(); - return true; - } - - return false; -} - -BOOST_AUTO_TEST_CASE(first_vin_is_sender) -{ - std::vector vouts; - vouts.push_back(createTxOut(100, "aByw7PqtCUPj2KggygecNahvPztyFBJw2q")); // Winner - vouts.push_back(createTxOut(999, "aN5vRJz8YDFUHsffaDqiviifJYvofacfKt")); - vouts.push_back(createTxOut(200, "a19njnihgJXU4k58KF7phjaLjcMy66d3Mj")); - - std::string strExpected("aByw7PqtCUPj2KggygecNahvPztyFBJw2q"); - - std::string strSender; - BOOST_CHECK(GetFirstSender(vouts, strSender)); - BOOST_CHECK_EQUAL(strExpected, strSender); -} - -BOOST_AUTO_TEST_CASE(less_input_restrictions) -{ - std::vector vouts; - vouts.push_back(createTxOut(555, "aByw7PqtCUPj2KggygecNahvPztyFBJw2q")); // Winner - vouts.push_back(PayToPubKey_Unrelated()); - vouts.push_back(PayToBareMultisig_1of3()); - vouts.push_back(NonStandardOutput()); - - std::string strExpected("aByw7PqtCUPj2KggygecNahvPztyFBJw2q"); - - std::string strSender; - BOOST_CHECK(GetFirstSender(vouts, strSender)); - BOOST_CHECK_EQUAL(strExpected, strSender); -} - -BOOST_AUTO_TEST_CASE(invalid_inputs) -{ - { - std::vector vouts; - vouts.push_back(PayToPubKey_Unrelated()); - std::string strSender; - BOOST_CHECK(!GetFirstSender(vouts, strSender)); - } - { - std::vector vouts; - vouts.push_back(PayToBareMultisig_1of3()); - std::string strSender; - BOOST_CHECK(!GetFirstSender(vouts, strSender)); - } - { - std::vector vouts; - vouts.push_back(NonStandardOutput()); - std::string strSender; - BOOST_CHECK(!GetFirstSender(vouts, strSender)); - } -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/sigma_tests.cpp b/src/elysium/test/sigma_tests.cpp deleted file mode 100644 index 7481fdd11c..0000000000 --- a/src/elysium/test/sigma_tests.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "../sigma.h" -#include "../sigmadb.h" -#include "../sigmaprimitives.h" - -#include "../../test/test_bitcoin.h" - -#include - -#include -#include - -namespace elysium { -namespace { - -struct SigmaDatabaseFixture : TestingSetup -{ - SigmaDatabaseFixture() - { - sigmaDb = new SigmaDatabase(pathTemp / "elysium-sigmadb", true, 10); - } - - ~SigmaDatabaseFixture() - { - delete sigmaDb; sigmaDb = nullptr; - } -}; - -SigmaPublicKey CreateMint() -{ - SigmaPrivateKey key; - key.Generate(); - return SigmaPublicKey(key, DefaultSigmaParams); -} - -std::vector CreateMints(size_t n) -{ - std::vector mints; - - while (n--) { - mints.push_back(CreateMint()); - } - - return mints; -} - -} // unnamed namespace - -BOOST_AUTO_TEST_SUITE(elysium_sigma_tests) - -BOOST_FIXTURE_TEST_CASE(verify_spend, SigmaDatabaseFixture) -{ - auto& params = DefaultSigmaParams; - SigmaPrivateKey key; - SigmaProof proof(params); - std::vector anonimitySet; - bool increaseBlock = false; - int block = 100; - - // Create set of mint that contains our spendable mint. - key.Generate(); - - anonimitySet.push_back(SigmaPublicKey(key, params)); - - for (auto& mint : CreateMints(sigmaDb->groupSize - 2)) { // -2 to make anonimitySet not a full group. - anonimitySet.push_back(mint); - } - - proof.Generate(key, anonimitySet.begin(), anonimitySet.end(), false); - - // Generate spendable group. - for (unsigned i = 0; i < sigmaDb->groupSize; i++) { - if (i < anonimitySet.size()) { - sigmaDb->RecordMint(3, 0, anonimitySet[i], block); - } else { - sigmaDb->RecordMint(3, 0, CreateMint(), block); - } - - sigmaDb->RecordMint(3, 1, CreateMint(), block); - sigmaDb->RecordMint(4, 0, CreateMint(), block); - - if (increaseBlock) { - block++; - increaseBlock = false; - } else { - increaseBlock = true; - } - } - - // Generate non-spendable group. - for (auto& mint : CreateMints(sigmaDb->groupSize)) { - sigmaDb->RecordMint(3, 0, mint, block); - } - - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size(), proof, key.serial, false), true); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size() - 1, proof, key.serial, false), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size() + 1, proof, key.serial, false), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, sigmaDb->groupSize + 1, proof, key.serial, false), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 1, 0, sigmaDb->groupSize, proof, key.serial, false), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(4, 0, 0, sigmaDb->groupSize, proof, key.serial, false), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 1, sigmaDb->groupSize, proof, key.serial, false), false); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/sigmadb_tests.cpp b/src/elysium/test/sigmadb_tests.cpp deleted file mode 100644 index a84b901754..0000000000 --- a/src/elysium/test/sigmadb_tests.cpp +++ /dev/null @@ -1,714 +0,0 @@ -#include "../createpayload.h" -#include "../sigmadb.h" -#include "../tx.h" - -#include "../../test/fixtures.h" -#include "../../test/test_bitcoin.h" - -#include - -#include - -#include -#include -#include -#include - -#define TEST_MAX_COINS_PER_GROUP 30 - -namespace std { - -template -basic_ostream& operator<<(basic_ostream& os, const pair& p) -{ - return os << '(' << p.first << ", " << p.second << ')'; -} - -template -basic_ostream& operator<<(basic_ostream& os, const vector& v) -{ - os << '('; - for (size_t i = 0; i < v.size();) { - os << v[i]; - if (++i != v.size()) { - os << ", "; - } - } - os << ')'; - - return os; -} - -} // namespace std - -namespace elysium { -namespace { - -struct MintAdded -{ - PropertyId property; - SigmaDenomination denomination; - SigmaMintGroup group; - SigmaMintIndex index; - SigmaPublicKey pubKey; - int block; -}; - -struct MintRemoved -{ - PropertyId property; - SigmaDenomination denomination; - SigmaPublicKey pubKey; -}; - -struct TestSigmaDb : SigmaDatabase -{ - TestSigmaDb(const boost::filesystem::path& path, bool wipe, uint16_t groupSize = TEST_MAX_COINS_PER_GROUP) : - SigmaDatabase(path, wipe, groupSize) - { - } - - uint16_t GetGroupSize() - { - return SigmaDatabase::GetGroupSize(); - } - - uint16_t InitGroupSize(uint16_t groupSize) - { - return SigmaDatabase::InitGroupSize(groupSize); - } - - std::vector GetAnonimityGroupAsVector( - PropertyId property, - SigmaDenomination denomination, - SigmaMintGroup group, - size_t count) - { - std::vector pubs; - SigmaDatabase::GetAnonimityGroup(property, denomination, group, count, std::back_inserter(pubs)); - return pubs; - } - - using SigmaDatabase::GetAnonimityGroup; -}; - -class SigmaDbTestingSetup : public TestingSetup -{ -public: - std::vector mintAdded; - std::vector mintRemoved; - -public: - SigmaDbTestingSetup() : TestingSetup(CBaseChainParams::REGTEST) - { - } - - std::unique_ptr CreateDb(uint16_t groupSize = TEST_MAX_COINS_PER_GROUP) - { - return CreateDb("MP_txlist_test", false, groupSize); - } - - std::unique_ptr CreateDb( - const std::string& fileName, - bool wipe, - uint16_t groupSize = TEST_MAX_COINS_PER_GROUP) - { - std::unique_ptr db(new TestSigmaDb(pathTemp / fileName, wipe, groupSize)); - - sigconns.emplace_front(db->MintAdded.connect([this] ( - PropertyId p, - SigmaDenomination d, - SigmaMintGroup g, - SigmaMintIndex i, - const SigmaPublicKey& k, - int b) { - mintAdded.push_back(MintAdded{ - .property = p, - .denomination = d, - .group = g, - .index = i, - .pubKey = k, - .block = b - }); - })); - - sigconns.emplace_front(db->MintRemoved.connect([this] ( - PropertyId p, - SigmaDenomination d, - const SigmaPublicKey& k) { - mintRemoved.push_back(MintRemoved{ - .property = p, - .denomination = d, - .pubKey = k - }); - })); - - return db; - } - -private: - std::forward_list sigconns; -}; - -SigmaPublicKey CreateMint() -{ - SigmaPrivateKey key; - key.Generate(); - return SigmaPublicKey(key, DefaultSigmaParams); -} - -std::vector CreateMints(size_t n) -{ - std::vector mints; - mints.reserve(n); - - while (n--) { - mints.push_back(CreateMint()); - } - - return mints; -} - -std::vector GetFirstN( - std::vector& org, size_t n) -{ - return std::vector - (org.begin(), n > org.size() ? org.end() : org.begin() + n); -} - -} // empty namespace - -BOOST_FIXTURE_TEST_SUITE(elysium_sigmadb_tests, SigmaDbTestingSetup) - -BOOST_AUTO_TEST_CASE(record_one_coin) -{ - auto db = CreateDb(); - auto mint = CreateMint(); - PropertyId propId = 1; - SigmaDenomination denom = 0; - - BOOST_CHECK_EQUAL(0, db->GetMintCount(propId, denom, 0)); - BOOST_CHECK_EQUAL(0, db->GetNextSequence()); - - BOOST_CHECK_EQUAL( - std::make_pair(SigmaMintGroup(0), SigmaMintIndex(0)), - db->RecordMint(propId, denom, mint, 100) - ); - - BOOST_CHECK_EQUAL(0, db->GetLastGroupId(propId, denom)); - BOOST_CHECK_EQUAL(1, db->GetMintCount(propId, denom, 0)); - BOOST_CHECK_EQUAL(0, db->GetMintCount(propId, denom, 1)); - BOOST_CHECK_EQUAL(1, db->GetNextSequence()); - - BOOST_CHECK_EQUAL(1, mintAdded.size()); - BOOST_CHECK_EQUAL(propId, mintAdded[0].property); - BOOST_CHECK_EQUAL(denom, mintAdded[0].denomination); - BOOST_CHECK_EQUAL(0, mintAdded[0].group); - BOOST_CHECK_EQUAL(0, mintAdded[0].index); - BOOST_CHECK_EQUAL(mint, mintAdded[0].pubKey); - BOOST_CHECK_EQUAL(100, mintAdded[0].block); -} - -BOOST_AUTO_TEST_CASE(getmint_notfound) -{ - auto db = CreateDb(); - - BOOST_CHECK_EXCEPTION( - db->GetMint(1, 1, 1, 1), - std::runtime_error, - [] (const std::runtime_error &e) { - return std::string("not found sigma mint") == e.what(); - } - ); -} - -BOOST_AUTO_TEST_CASE(getmint_test) -{ - auto db = CreateDb(); - auto mint = CreateMint(); - uint32_t propId = 1; - uint32_t denom = 0; - db->RecordMint(propId, denom, mint, 100); - - BOOST_CHECK_EQUAL(mint, db->GetMint(propId, denom, 0, 0)); -} - -BOOST_AUTO_TEST_CASE(get_anonymityset_no_anycoin) -{ - auto db = CreateDb(); - - BOOST_CHECK_EQUAL(db->GetAnonimityGroupAsVector(0, 0, 0, 100).empty(), true); -} - -BOOST_AUTO_TEST_CASE(get_anonymityset_have_coin_in_other_group) -{ - auto db = CreateDb(); - - for (auto& mint : CreateMints(10)) { - db->RecordMint(1, 1, mint, 10); - } - - BOOST_CHECK_EQUAL(db->GetAnonimityGroupAsVector(2, 2, 0, 11).empty(), true); - BOOST_CHECK_EQUAL(db->GetAnonimityGroupAsVector(2, 2, 0, 1).empty(), true); -} - -BOOST_AUTO_TEST_CASE(get_anonymityset_have_one_group) -{ - auto db = CreateDb(); - auto mints = CreateMints(10); - - for (auto& mint : mints) { - db->RecordMint(1, 1, mint, 10); - } - - BOOST_CHECK_EQUAL(mints, db->GetAnonimityGroupAsVector(1, 1, 0, 11)); - BOOST_CHECK_EQUAL(mints, db->GetAnonimityGroupAsVector(1, 1, 0, 10)); - BOOST_CHECK_EQUAL(GetFirstN(mints, 5), db->GetAnonimityGroupAsVector(1, 1, 0, 5)); -} - -BOOST_AUTO_TEST_CASE(get_anonymityset_many_properties) -{ - auto db = CreateDb(); - auto mints1 = CreateMints(10); - auto mints2 = CreateMints(10); - - for (auto& mint : mints1) { - db->RecordMint(1, 1, mint, 10); - } - - for (auto& mint : mints2) { - db->RecordMint(2, 1, mint, 10); - } - - BOOST_CHECK_EQUAL(mints1, db->GetAnonimityGroupAsVector(1, 1, 0, 11)); - BOOST_CHECK_EQUAL(mints2, db->GetAnonimityGroupAsVector(2, 1, 0, 11)); - BOOST_CHECK_EQUAL(mints1, db->GetAnonimityGroupAsVector(1, 1, 0, 10)); - BOOST_CHECK_EQUAL(mints2, db->GetAnonimityGroupAsVector(2, 1, 0, 10)); - BOOST_CHECK_EQUAL(GetFirstN(mints1, 5), db->GetAnonimityGroupAsVector(1, 1, 0, 5)); - BOOST_CHECK_EQUAL(GetFirstN(mints2, 5), db->GetAnonimityGroupAsVector(2, 1, 0, 5)); -} - -BOOST_AUTO_TEST_CASE(get_anonymity_set_many_denominations) -{ - auto db = CreateDb(); - auto mints1 = CreateMints(10); - auto mints2 = CreateMints(10); - int blocks = 10; - - for (auto& mint : mints1) { - db->RecordMint(1, 1, mint, blocks++); - } - - for (auto& mint : mints2) { - db->RecordMint(1, 2, mint, 10); - } - - BOOST_CHECK_EQUAL(mints1, db->GetAnonimityGroupAsVector(1, 1, 0, 11)); - BOOST_CHECK_EQUAL(mints2, db->GetAnonimityGroupAsVector(1, 2, 0, 11)); - BOOST_CHECK_EQUAL(mints1, db->GetAnonimityGroupAsVector(1, 1, 0, 10)); - BOOST_CHECK_EQUAL(mints2, db->GetAnonimityGroupAsVector(1, 2, 0, 10)); - BOOST_CHECK_EQUAL(GetFirstN(mints1, 5), db->GetAnonimityGroupAsVector(1, 1, 0, 5)); - BOOST_CHECK_EQUAL(GetFirstN(mints2, 5), db->GetAnonimityGroupAsVector(1, 2, 0, 5)); -} - -BOOST_AUTO_TEST_CASE(get_anonymity_set_many_groups) -{ - auto db = CreateDb(); - auto mints1 = CreateMints(10); - auto mints2 = CreateMints(10); - int count = 0; - - for (auto& mint : mints1) { - db->RecordMint(1, 1, mint, 10); - count++; - } - - for (; count < TEST_MAX_COINS_PER_GROUP; count++) { - db->RecordMint(1, 1, mints1[0], 10); - } - - for (auto& mint : mints2) { - db->RecordMint(1, 1, mint, 10); - } - - BOOST_CHECK_EQUAL(mints2, db->GetAnonimityGroupAsVector(1, 1, 1, 11)); - BOOST_CHECK_EQUAL(mints1, db->GetAnonimityGroupAsVector(1, 1, 0, 10)); - BOOST_CHECK_EQUAL(mints2, db->GetAnonimityGroupAsVector(1, 1, 1, 10)); - BOOST_CHECK_EQUAL(GetFirstN(mints1, 5), db->GetAnonimityGroupAsVector(1, 1, 0, 5)); - BOOST_CHECK_EQUAL(GetFirstN(mints2, 5), db->GetAnonimityGroupAsVector(1, 1, 1, 5)); -} - -BOOST_AUTO_TEST_CASE(delete_an_empty_set_of_coins) -{ - auto db = CreateDb(); - - BOOST_CHECK_EQUAL(0, db->GetNextSequence()); - BOOST_CHECK_NO_THROW(db->DeleteAll(1)); - BOOST_CHECK_EQUAL(0, db->GetNextSequence()); -} - -BOOST_AUTO_TEST_CASE(delete_block_which_have_no_coins) -{ - auto db = CreateDb(); - auto mints = CreateMints(1); - - db->RecordMint(1, 1, mints[0], 10); // store at block 10 - - BOOST_CHECK_NO_THROW(db->DeleteAll(11)); // delete at block 11 - BOOST_CHECK_EQUAL(mints, db->GetAnonimityGroupAsVector(1, 1, 0, 1)); - BOOST_CHECK_EQUAL(1, db->GetNextSequence()); -} - -BOOST_AUTO_TEST_CASE(delete_one_coin) -{ - auto db = CreateDb(); - auto mint = CreateMint(); - - db->RecordMint(1, 1, mint, 10); - - BOOST_CHECK_NO_THROW(db->DeleteAll(10)); - - BOOST_CHECK_EQUAL(0, db->GetAnonimityGroupAsVector(1, 1, 0, 1).size()); - BOOST_CHECK_EQUAL(0, db->GetNextSequence()); - - BOOST_CHECK_EQUAL(1, mintRemoved.size()); - BOOST_CHECK_EQUAL(1, mintRemoved[0].property); - BOOST_CHECK_EQUAL(1, mintRemoved[0].denomination); - BOOST_CHECK_EQUAL(mint, mintRemoved[0].pubKey); -} - -BOOST_AUTO_TEST_CASE(delete_one_of_two_coin) -{ - auto db = CreateDb(); - auto mints = CreateMints(2); - - db->RecordMint(1, 1, mints[0], 10); // store at block 10 - db->RecordMint(1, 1, mints[1], 11); // store at block 11 - - BOOST_CHECK_NO_THROW(db->DeleteAll(11)); // delete at block 11 - - BOOST_CHECK_EQUAL(GetFirstN(mints, 1), db->GetAnonimityGroupAsVector(1, 1, 0, 2)); - BOOST_CHECK_EQUAL(GetFirstN(mints, 1), db->GetAnonimityGroupAsVector(1, 1, 0, 1)); - BOOST_CHECK_EQUAL(1, db->GetNextSequence()); - - BOOST_CHECK_EQUAL(1, mintRemoved.size()); - BOOST_CHECK_EQUAL(1, mintRemoved[0].property); - BOOST_CHECK_EQUAL(1, mintRemoved[0].denomination); - BOOST_CHECK_EQUAL(mints[1], mintRemoved[0].pubKey); -} - -BOOST_AUTO_TEST_CASE(delete_two_coins_from_two_denominations) -{ - auto db = CreateDb(); - auto mints1 = CreateMints(2); - auto mints2 = CreateMints(2); - - db->RecordMint(1, 0, mints1[0], 10); - db->RecordMint(1, 1, mints2[0], 10); - db->RecordMint(1, 0, mints1[1], 11); - db->RecordMint(1, 1, mints2[1], 12); - - BOOST_CHECK_EQUAL(4, db->GetNextSequence()); - - BOOST_CHECK_NO_THROW(db->DeleteAll(11)); - - BOOST_CHECK_EQUAL(GetFirstN(mints1, 1), db->GetAnonimityGroupAsVector(1, 0, 0, 2)); - BOOST_CHECK_EQUAL(GetFirstN(mints2, 1), db->GetAnonimityGroupAsVector(1, 1, 0, 2)); - BOOST_CHECK_EQUAL(2, db->GetNextSequence()); - - BOOST_CHECK_EQUAL(2, mintRemoved.size()); - BOOST_CHECK_EQUAL(1, mintRemoved[0].property); - BOOST_CHECK_EQUAL(1, mintRemoved[0].denomination); - BOOST_CHECK_EQUAL(mints2[1], mintRemoved[0].pubKey); - - BOOST_CHECK_EQUAL(1, mintRemoved[1].property); - BOOST_CHECK_EQUAL(0, mintRemoved[1].denomination); - BOOST_CHECK_EQUAL(mints1[1], mintRemoved[1].pubKey); -} - -BOOST_AUTO_TEST_CASE(delete_two_coins_from_two_properties) -{ - auto db = CreateDb(); - auto mints1 = CreateMints(2); - auto mints2 = CreateMints(2); - - db->RecordMint(1, 0, mints1[0], 10); - db->RecordMint(2, 0, mints2[0], 10); - db->RecordMint(1, 0, mints1[1], 11); - db->RecordMint(2, 0, mints2[1], 12); - - BOOST_CHECK_EQUAL(4, db->GetNextSequence()); - - BOOST_CHECK_NO_THROW(db->DeleteAll(11)); - - BOOST_CHECK_EQUAL(GetFirstN(mints1, 1), db->GetAnonimityGroupAsVector(1, 0, 0, 2)); - BOOST_CHECK_EQUAL(GetFirstN(mints2, 1), db->GetAnonimityGroupAsVector(2, 0, 0, 2)); - BOOST_CHECK_EQUAL(2, db->GetNextSequence()); -} - -BOOST_AUTO_TEST_CASE(delete_three_coins_from_two_groups) -{ - auto db = CreateDb(); - auto mints1 = CreateMints(2); - auto mints2 = CreateMints(2); - unsigned count = 0; - - db->RecordMint(1, 0, mints1[0], 10); - db->RecordMint(1, 0, mints1[1], 11); - count += 2; - - for (;count < TEST_MAX_COINS_PER_GROUP; count++) { - db->RecordMint(1, 0, mints1[0], 11); - } - - BOOST_CHECK_EQUAL(std::make_pair(uint32_t(1), uint16_t(0)), db->RecordMint(1, 0, mints2[0], 12)); count++; - BOOST_CHECK_EQUAL(std::make_pair(uint32_t(1), uint16_t(1)), db->RecordMint(1, 0, mints2[1], 13)); count++; - BOOST_CHECK_EQUAL(1, db->GetLastGroupId(1, 0)); - BOOST_CHECK_EQUAL(count, db->GetNextSequence()); - - BOOST_CHECK_NO_THROW(db->DeleteAll(11)); - - BOOST_CHECK_EQUAL(GetFirstN(mints1, 1), db->GetAnonimityGroupAsVector(1, 0, 0, 2)); - BOOST_CHECK_EQUAL(db->GetAnonimityGroupAsVector(1, 0, 1, 1).empty(), true); - BOOST_CHECK_EQUAL(1, db->GetNextSequence()); - BOOST_CHECK_EQUAL(0, db->GetLastGroupId(1, 0)); // assert last group id of propertyId = 1 and denomination = 0 is decreased to 0 -} - -BOOST_AUTO_TEST_CASE(get_anonimity_group_by_back_insert_iterator) -{ - auto db = CreateDb(); - auto mints = CreateMints(10); - - for (auto& mint : mints) { - db->RecordMint(1, 1, mint, 10); - } - - std::vector anonimityGroup; - db->GetAnonimityGroup(1, 1, 0, 10, std::back_inserter(anonimityGroup)); - - BOOST_CHECK_EQUAL(mints, anonimityGroup); -} - -BOOST_AUTO_TEST_CASE(get_anonimity_group_by_iterator) -{ - auto db = CreateDb(); - auto mints = CreateMints(10); - std::vector result(10); - - for (auto& mint : mints) { - db->RecordMint(1, 1, mint, 10); - } - - db->GetAnonimityGroup(1, 1, 0, 10, result.begin()); - - BOOST_CHECK_EQUAL(mints, result); -} - -BOOST_AUTO_TEST_CASE(group_size_default) -{ - auto db = CreateDb(0); - - BOOST_CHECK_EQUAL(db->GetGroupSize(), SigmaDatabase::MAX_GROUP_SIZE); -} - -BOOST_AUTO_TEST_CASE(group_size_customsize) -{ - auto db = CreateDb(120); - - BOOST_CHECK_EQUAL(db->GetGroupSize(), 120); -} - -BOOST_AUTO_TEST_CASE(group_size_exceed_limit) -{ - BOOST_CHECK_EXCEPTION( - CreateDb(SigmaDatabase::MAX_GROUP_SIZE + 1), - std::invalid_argument, - [] (const std::invalid_argument& e) { - return std::string("group size exceed limit") == e.what(); - } - ); -} - -BOOST_AUTO_TEST_CASE(use_differnet_group_size_from_database) -{ - CreateDb(10); - - BOOST_CHECK_EXCEPTION( - CreateDb(11), - std::invalid_argument, - [] (const std::invalid_argument& e) { - return std::string("group size input isn't equal to group size in database") - == e.what(); - } - ); -} - -BOOST_AUTO_TEST_CASE(check_not_exist_serial) -{ - auto db = CreateDb(); - SigmaPrivateKey key; - - key.Generate(); - uint256 spendTx; - BOOST_CHECK(!db->HasSpendSerial(1, 1, key.serial, spendTx)); - BOOST_CHECK(uint256() == spendTx); -} - -BOOST_AUTO_TEST_CASE(check_exist_serial) -{ - auto db = CreateDb(); - SigmaPrivateKey key; - - key.Generate(); - auto const spendTx = uint256S("1"); - db->RecordSpendSerial(1, 1, key.serial, 10, spendTx); - - uint256 outTx; - BOOST_CHECK(db->HasSpendSerial(1, 1, key.serial, outTx)); - BOOST_CHECK(spendTx == outTx); -} - -BOOST_AUTO_TEST_CASE(check_exist_serial_with_different_group_and_denom_should_fail) -{ - auto db = CreateDb(); - SigmaPrivateKey key; - - key.Generate(); - auto spendTx = uint256S("1"); - db->RecordSpendSerial(1, 1, key.serial, 10, spendTx); - - uint256 outputSpendTx; - BOOST_CHECK_EQUAL(db->HasSpendSerial(1, 2, key.serial, outputSpendTx), false); - BOOST_CHECK_EQUAL(db->HasSpendSerial(2, 1, key.serial, outputSpendTx), false); - - BOOST_CHECK(uint256() == outputSpendTx); -} - -BOOST_AUTO_TEST_CASE(check_deleted_serial) -{ - auto db = CreateDb(); - SigmaPrivateKey key; - - key.Generate(); - - auto spendTx = uint256S("1"); - db->RecordSpendSerial(1, 1, key.serial, 10, spendTx); - db->DeleteAll(10); - - uint256 outputSpendTx; - BOOST_CHECK_EQUAL(db->HasSpendSerial(1, 1, key.serial, outputSpendTx), false); - - BOOST_CHECK(uint256() == outputSpendTx); -} - -BOOST_AUTO_TEST_CASE(check_deleted_two_serials) -{ - auto spendTx1 = uint256S("1"); - auto spendTx2 = uint256S("2"); - - auto db = CreateDb(); - SigmaPrivateKey key1, key2; - - key1.Generate(); - key2.Generate(); - - db->RecordSpendSerial(1, 1, key1.serial, 10, spendTx1); - db->RecordSpendSerial(1, 1, key2.serial, 10, spendTx2); - - uint256 outputSpendTx1, outputSpendTx2; - BOOST_CHECK(db->HasSpendSerial(1, 1, key1.serial, outputSpendTx1)); - BOOST_CHECK(db->HasSpendSerial(1, 1, key2.serial, outputSpendTx2)); - - BOOST_CHECK(spendTx1 == outputSpendTx1); - BOOST_CHECK(spendTx2 == outputSpendTx2); - - auto spendTx3 = uint256S("3"); - db->RecordSpendSerial(1, 1, key2.serial, 10, spendTx3); - - BOOST_CHECK_EQUAL(db->HasSpendSerial(1, 1, key1.serial, outputSpendTx1), true); - BOOST_CHECK_EQUAL(db->HasSpendSerial(1, 1, key2.serial, outputSpendTx2), true); - - BOOST_CHECK(spendTx1 == outputSpendTx1); - BOOST_CHECK(spendTx3 == outputSpendTx2); - - db->DeleteAll(10); - - uint256 spendTx4; - BOOST_CHECK(!db->HasSpendSerial(1, 1, key1.serial, spendTx4)); - BOOST_CHECK(uint256() == spendTx4); - - BOOST_CHECK(!db->HasSpendSerial(1, 1, key2.serial, spendTx4)); - BOOST_CHECK(uint256() == spendTx4); -} - -BOOST_AUTO_TEST_CASE(try_to_delete_the_block_after) -{ - auto spendTx1 = uint256S("1"); - auto spendTx2 = uint256S("2"); - - auto db = CreateDb(); - SigmaPrivateKey key1, key2; - - key1.Generate(); - key2.Generate(); - db->RecordSpendSerial(1, 1, key1.serial, 10, spendTx1); - db->RecordSpendSerial(1, 1, key2.serial, 11, spendTx2); - - db->DeleteAll(11); - - uint256 outputSpendTx1, outputSpendTx2; - BOOST_CHECK(db->HasSpendSerial(1, 1, key1.serial, outputSpendTx1)); - BOOST_CHECK(!db->HasSpendSerial(1, 1, key2.serial, outputSpendTx2)); - - BOOST_CHECK(spendTx1 == outputSpendTx1); - BOOST_CHECK(uint256() == outputSpendTx2); -} - -BOOST_AUTO_TEST_CASE(delete_both_mint_and_spend) -{ - auto spendTx1 = uint256S("1"); - auto spendTx2 = uint256S("2"); - - auto db = CreateDb(); - SigmaPrivateKey key1, key2; - - key1.Generate(); - key2.Generate(); - - // block 10 - // 10 mints, 1 serial - for (auto& mint : CreateMints(10)) { - db->RecordMint(1, 1, mint, 10); - } - - db->RecordSpendSerial(1, 1, key1.serial, 10, spendTx1); - BOOST_CHECK_EQUAL(11, db->GetNextSequence()); - BOOST_CHECK_EQUAL(10, db->GetMintCount(1, 1, 0)); - - // block 11 - // 10 mints, 1 serial - for (auto& mint : CreateMints(10)) { - db->RecordMint(1, 1, mint, 11); - } - - db->RecordSpendSerial(1, 1, key2.serial, 11, spendTx2); - BOOST_CHECK_EQUAL(22, db->GetNextSequence()); - BOOST_CHECK_EQUAL(20, db->GetMintCount(1, 1, 0)); - - // delete all in block 11 - db->DeleteAll(11); - - BOOST_CHECK_EQUAL(11, db->GetNextSequence()); - BOOST_CHECK_EQUAL(10, db->GetMintCount(1, 1, 0)); - - uint256 outSpendTx1, outSpendTx2; - BOOST_CHECK(db->HasSpendSerial(1, 1, key1.serial, outSpendTx1)); - BOOST_CHECK(!db->HasSpendSerial(1, 1, key2.serial, outSpendTx2)); - - BOOST_CHECK(spendTx1 == outSpendTx1); - BOOST_CHECK(uint256() == outSpendTx2); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/sigmaprimitives_tests.cpp b/src/elysium/test/sigmaprimitives_tests.cpp deleted file mode 100644 index 7503d0ceee..0000000000 --- a/src/elysium/test/sigmaprimitives_tests.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "../sigmaprimitives.h" - -#include "../../test/test_bitcoin.h" - -#include - -#include -#include - -namespace elysium { - -BOOST_FIXTURE_TEST_SUITE(elysium_sigmaprimitives_tests, TestingSetup) - -BOOST_AUTO_TEST_CASE(params) -{ - auto g = secp_primitives::GroupElement().set_base_g(); - SigmaParams params(g, 7, 4); - - BOOST_CHECK_EQUAL(params.g, g); - BOOST_CHECK_EQUAL(params.m, 7); - BOOST_CHECK_EQUAL(params.n, 4); - BOOST_CHECK_EQUAL(params.h.size(), 7 * 4); -} - -BOOST_AUTO_TEST_CASE(params_validation) -{ - BOOST_CHECK_THROW(SigmaParams(secp_primitives::GroupElement().set_base_g(), 0, 1), std::invalid_argument); - BOOST_CHECK_THROW(SigmaParams(secp_primitives::GroupElement().set_base_g(), 1, 0), std::invalid_argument); -} - -BOOST_AUTO_TEST_CASE(private_key) -{ - SigmaPrivateKey key; - - auto serial = key.serial; - auto randomness = key.randomness; - - key.Generate(); - - BOOST_CHECK(key.IsValid()); - BOOST_CHECK_NE(key.serial, serial); - BOOST_CHECK_NE(key.randomness, randomness); -} - -BOOST_AUTO_TEST_CASE(private_key_validation) -{ - secp_primitives::Scalar zero(uint64_t(0)); - secp_primitives::Scalar s(1), r(2); - - SigmaPrivateKey validCoin(s, r); - BOOST_CHECK(validCoin.IsMember()); - BOOST_CHECK(validCoin.IsValid()); - - SigmaPrivateKey zeroAsRandomness(s, zero); - BOOST_CHECK(zeroAsRandomness.IsMember()); - BOOST_CHECK(!zeroAsRandomness.IsValid()); - - SigmaPrivateKey zeroAsSerial(zero, r); - BOOST_CHECK(zeroAsSerial.IsMember()); - BOOST_CHECK(!zeroAsSerial.IsValid()); -} - -BOOST_AUTO_TEST_CASE(private_key_hash) -{ - SigmaPrivateKey key1, key2; - std::hash hasher; - - key1.Generate(); - key2.Generate(); - - BOOST_CHECK_EQUAL(hasher(key1), hasher(key1)); - BOOST_CHECK_NE(hasher(key1), hasher(key2)); -} - -BOOST_AUTO_TEST_CASE(public_key) -{ - auto& params = DefaultSigmaParams; - SigmaPrivateKey priv; - SigmaPublicKey pub; - - auto commit = pub.commitment; - - priv.Generate(); - pub.Generate(priv, params); - - BOOST_CHECK(pub.IsValid()); - BOOST_CHECK_NE(pub.commitment, commit); - - // Try a second time to see if we still get the same result. - commit = pub.commitment; - pub.Generate(priv, params); - - BOOST_CHECK_EQUAL(pub.commitment, commit); -} - -BOOST_AUTO_TEST_CASE(public_key_validation) -{ - auto& params = DefaultSigmaParams; - SigmaPrivateKey k; - k.Generate(); - - SigmaPublicKey invalidKey, validKey(k, params); - - BOOST_CHECK(invalidKey.IsMember()); - BOOST_CHECK(!invalidKey.IsValid()); - - BOOST_CHECK(validKey.IsMember()); - BOOST_CHECK(validKey.IsValid()); -} - -BOOST_AUTO_TEST_CASE(public_key_hash) -{ - auto& params = DefaultSigmaParams; - SigmaPrivateKey key1, key2; - std::hash hasher; - - key1.Generate(); - key2.Generate(); - - BOOST_CHECK_EQUAL(hasher(SigmaPublicKey(key1, params)), hasher(SigmaPublicKey(key1, params))); - BOOST_CHECK_NE(hasher(SigmaPublicKey(key1, params)), hasher(SigmaPublicKey(key2, params))); -} - -BOOST_AUTO_TEST_CASE(proof) -{ - auto& params = DefaultSigmaParams; - - // Create keys. - SigmaPrivateKey key1, key2, key3; - - key1.Generate(); - key2.Generate(); - key3.Generate(); - - // Crete proof. - SigmaProof proof(params); - std::vector pubs({ - SigmaPublicKey(key1, params), - SigmaPublicKey(key2, params), - SigmaPublicKey(key3, params) - }); - - proof.Generate(key2, pubs.begin(), pubs.end(), false); - - BOOST_CHECK_EQUAL(proof.Verify(key2.serial, pubs.begin(), pubs.end(), false), true); - BOOST_CHECK_EQUAL(proof.Verify(key2.serial, pubs.begin(), pubs.end() - 1, false), false); -} - -BOOST_AUTO_TEST_CASE(spend_with_large_anonimity_group) -{ - auto& params = DefaultSigmaParams; - std::vector pubs; - - // 2 ^ 14 coins - int limit = 1 << 14; - - // generate 2 ^ 14 + 1 coins - SigmaPrivateKey key; - for (int i = 0; i < limit + 1; i++) { - key.Generate(); - pubs.push_back(SigmaPublicKey(key, params)); - } - - SigmaProof validProof(params), invalidProof(params); - validProof.Generate(key, pubs.begin() + 1, pubs.end(), false); // prove with 2 ^ 14 coins - invalidProof.Generate(key, pubs.begin(), pubs.end(), false); // prove with 2 ^ 14 + 1 coins - - BOOST_CHECK_EQUAL(validProof.Verify(key.serial, pubs.begin() + 1, pubs.end(), false), true); - BOOST_CHECK_EQUAL(invalidProof.Verify(key.serial, pubs.begin(), pubs.end(), false), false); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/sigmawallet_tests.cpp b/src/elysium/test/sigmawallet_tests.cpp deleted file mode 100644 index ec40505e58..0000000000 --- a/src/elysium/test/sigmawallet_tests.cpp +++ /dev/null @@ -1,607 +0,0 @@ -// Copyright (c) 2019 The Firo Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "../sigmadb.h" -#include "../sigmawallet.h" -#include "../walletmodels.h" - -#include "../../key.h" -#include "../../validation.h" -#include "../../utiltime.h" -#include "../../validationinterface.h" - -#include "../../rpc/server.h" - -#include "../../wallet/db.h" -#include "../../wallet/rpcwallet.h" -#include "../../wallet/wallet.h" -#include "../../wallet/walletdb.h" - -#include "../../wallet/test/wallet_test_fixture.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace std { - -template -basic_ostream& operator<<(basic_ostream& os, const vector& mints) -{ - vector> strings; - - for (auto& m : mints) { - basic_stringstream s; - s << m; - strings.push_back(s.str()); - } - - return os << '[' << boost::algorithm::join(strings, ", ") << ']'; -} - -} // namespace std - -namespace elysium { - -using MintPoolEntry = SigmaWallet::MintPoolEntry; - -namespace { - -class TestSigmaWallet : public SigmaWallet -{ -public: - TestSigmaWallet() : SigmaWallet(new TestSigmaWallet::Database()) - { - } - -public: - - uint32_t BIP44ChangeIndex() const - { - return BIP44_ELYSIUM_MINT_INDEX_V0; - } - - SigmaPrivateKey GeneratePrivateKeyFromSeed(uint512 const &seed) - { - return GeneratePrivateKey(seed); - } - - void LoadMintPool() - { - SigmaWallet::LoadMintPool(); - } - - void SaveMintPool() - { - SigmaWallet::SaveMintPool(); - } - - bool RemoveFromMintPool(SigmaPublicKey const &publicKey) - { - return SigmaWallet::RemoveFromMintPool(publicKey); - } - - size_t FillMintPool() - { - return SigmaWallet::FillMintPool(); - } - - MintPool& GetMintPool() - { - return mintPool; - } - - std::vector GetMintPoolEntry() - { - std::vector r; - for (auto const & e : mintPool) { - r.push_back(e); - } - - return r; - } - -protected: - SigmaPrivateKey GeneratePrivateKey(uint512 const &seed) - { - SigmaPrivateKey priv; - - // first 32 bytes as seed - uint256 serialSeed; - std::copy(seed.begin(), seed.begin() + 32, serialSeed.begin()); - priv.serial.memberFromSeed(serialSeed.begin()); - - // last 32 bytes as seed - uint256 randomnessSeed; - std::copy(seed.begin() + 32, seed.end(), randomnessSeed.begin()); - priv.randomness.memberFromSeed(randomnessSeed.begin()); - - return priv; - } - - class Database : public SigmaWallet::Database { - public: - Database() - { - } - - public: - bool WriteMint(SigmaMintId const &id, SigmaMint const &mint, CWalletDB *db = nullptr) - { - auto local = Connection(db); - return local->WriteElysiumMintV0(id, mint); - } - - bool ReadMint(SigmaMintId const &id, SigmaMint &mint, CWalletDB *db = nullptr) const - { - auto local = Connection(db); - return local->ReadElysiumMintV0(id, mint); - } - - bool EraseMint(SigmaMintId const &id, CWalletDB *db = nullptr) - { - auto local = Connection(db); - return local->EraseElysiumMintV0(id); - } - - bool HasMint(SigmaMintId const &id, CWalletDB *db = nullptr) const - { - auto local = Connection(db); - return local->HasElysiumMintV0(id); - } - - bool WriteMintId(uint160 const &hash, SigmaMintId const &mintId, CWalletDB *db = nullptr) - { - auto local = Connection(db); - return local->WriteElysiumMintIdV0(hash, mintId); - } - - bool ReadMintId(uint160 const &hash, SigmaMintId &mintId, CWalletDB *db = nullptr) const - { - auto local = Connection(db); - return local->ReadElysiumMintIdV0(hash, mintId); - } - - bool EraseMintId(uint160 const &hash, CWalletDB *db = nullptr) - { - auto local = Connection(db); - return local->EraseElysiumMintIdV0(hash); - } - - bool HasMintId(uint160 const &hash, CWalletDB *db = nullptr) const - { - auto local = Connection(db); - return local->HasElysiumMintIdV0(hash); - } - - bool WriteMintPool(std::vector const &mints, CWalletDB *db = nullptr) - { - auto local = Connection(db); - return local->WriteElysiumMintPoolV0(mints); - } - - bool ReadMintPool(std::vector &mints, CWalletDB *db = nullptr) - { - auto local = Connection(db); - return local->ReadElysiumMintPoolV0(mints); - } - - void ListMints(std::function const &inserter, CWalletDB *db = nullptr) - { - auto local = Connection(db); - local->ListElysiumMintsV0(inserter); - } - }; -}; - -struct SigmaWalletTestingSetup : WalletTestingSetup -{ - std::unique_ptr wallet; - - SigmaWalletTestingSetup() : wallet(new TestSigmaWallet()) - { - wallet->ReloadMasterKey(); - } -}; - -} // unnamed namespace - -BOOST_FIXTURE_TEST_SUITE(elysium_sigmawallet_tests, SigmaWalletTestingSetup) - -BOOST_AUTO_TEST_CASE(verify_mint_pool_have_been_generened) -{ - auto mintPool = wallet->GetMintPoolEntry(); - BOOST_CHECK_EQUAL(20, mintPool.size()); -} - -BOOST_AUTO_TEST_CASE(save_and_load_mintpool) -{ - auto mints = wallet->GetMintPoolEntry(); - - // delete last mint from pool and save - auto &pool = wallet->GetMintPool(); - pool.erase(pool.find(19), pool.end()); - wallet->SaveMintPool(); - - // delete more 9 mints - pool.erase(pool.find(10), pool.end()); - auto mutatedMintPools = wallet->GetMintPoolEntry(); - BOOST_CHECK_EQUAL(10, mutatedMintPools.size()); - BOOST_CHECK_EQUAL( - true, - std::equal( - mutatedMintPools.begin(), - mutatedMintPools.end(), - mints.begin() - ) - ); - - // load mint pool back - wallet->LoadMintPool(); - - auto loadedMintPools = wallet->GetMintPoolEntry(); - BOOST_CHECK_EQUAL(19, loadedMintPools.size()); - BOOST_CHECK_EQUAL( - true, - std::equal( - loadedMintPools.begin(), - loadedMintPools.end(), - mints.begin() - ) - ); -} - -BOOST_AUTO_TEST_CASE(verify_mintpool_on_fresh_startup) -{ - // get sequence - auto mints = wallet->GetMintPoolEntry(); - - std::vector mintPoolIndexs; - for (auto const &mint : mints) { - mintPoolIndexs.push_back(mint.index); - } - - // generate sequence - std::vector seq; - seq.resize(mintPoolIndexs.size()); - - std::generate(seq.begin(), seq.end(), [n = 0] () mutable { return n++; }); - - BOOST_CHECK(seq == mintPoolIndexs); -} - -BOOST_AUTO_TEST_CASE(tryrecover_random_coin) -{ - SigmaPrivateKey priv; - priv.Generate(); - - SigmaPublicKey pub(priv, DefaultSigmaParams); - SigmaMintId id(1, 0, pub); - - - auto mintPool = wallet->GetMintPoolEntry(); - - // verify state before - BOOST_CHECK_EQUAL(false, wallet->HasMint(id)); - - // `false` should be returned - BOOST_CHECK_EQUAL(false, wallet->TryRecoverMint( - id, SigmaMintChainState(1000, 0, 1000) - )); - - // verify after, mint wallet should not change - auto mintPoolAfter = wallet->GetMintPoolEntry(); - - BOOST_CHECK(mintPool == mintPoolAfter); - BOOST_CHECK_EQUAL(false, wallet->HasMint(id)); -} - -BOOST_AUTO_TEST_CASE(tryrecover_mintpool_coin) -{ - auto mintPool = wallet->GetMintPoolEntry(); - SigmaMintId id(1, 0, mintPool.front().key); - - // verify state before - BOOST_CHECK_EQUAL(false, wallet->HasMint(id)); - - BOOST_CHECK_EQUAL(true, wallet->TryRecoverMint( - id, - SigmaMintChainState(1000, 0, 1000) - )); - - // verify state after, mint wallet should be updated - auto mintPoolAfter = wallet->GetMintPoolEntry(); - - BOOST_CHECK(mintPool != mintPoolAfter); - - // mintPool[1:] == mintPoolAfter[:size - 1] - BOOST_CHECK_EQUAL(true, - std::equal(mintPool.begin() + 1, mintPool.end(), mintPoolAfter.begin())); - - BOOST_CHECK_EQUAL(20, mintPoolAfter.size()); // ensure mint pool is refilled - BOOST_CHECK_EQUAL(20, mintPoolAfter.back().index); // make sure new coin contain next index - BOOST_CHECK_EQUAL(true, wallet->HasMint(id)); -} - -BOOST_AUTO_TEST_CASE(tryrecover_already_in_wallet_coin) -{ - auto id = wallet->GenerateMint(3, 0); - auto mintPool = wallet->GetMintPoolEntry(); - - // verify state before - BOOST_CHECK_EQUAL(true, wallet->HasMint(id)); - - BOOST_CHECK_EQUAL(false, wallet->TryRecoverMint( - id, - SigmaMintChainState(1000, 0, 1000) - )); - - // verify state after, mint wallet should not be changed - auto mintPoolAfter = wallet->GetMintPoolEntry(); - - BOOST_CHECK(mintPool == mintPoolAfter); - - BOOST_CHECK_EQUAL(true, wallet->HasMint(id)); -} - -BOOST_AUTO_TEST_CASE(listmints_empty_wallet) -{ - std::vector> mints; - wallet->ListMints(std::back_inserter(mints)); - BOOST_CHECK_EQUAL(0, mints.size()); -} - -BOOST_AUTO_TEST_CASE(listmints_non_empty_wallet) -{ - auto unconfirmed = wallet->GenerateMint(10, 0); - auto unspend = wallet->GenerateMint(10, 0); - auto spend = wallet->GenerateMint(10, 0); - - wallet->UpdateMintChainstate(unspend, SigmaMintChainState(100, 0, 1000)); - wallet->UpdateMintChainstate(spend, SigmaMintChainState(100, 0, 1001)); - wallet->UpdateMintSpendTx(spend, uint256S("766a4af4a36df1cd40e60f049f14d8a10fc9f9f20f7f88d89cafd415725d9415")); - - std::vector result; - - wallet->ListMints(boost::make_function_output_iterator([&] (const std::pair& m) { - result.push_back(m.first); - })); - - BOOST_CHECK_EQUAL( - true, - std::is_permutation(result.begin(), result.end(), std::begin({ unconfirmed, unspend, spend })) - ); -} - -BOOST_AUTO_TEST_CASE(delete_out_wallet_mint) -{ - SigmaPrivateKey privKey; - privKey.Generate(); - SigmaPublicKey pubKey(privKey, DefaultSigmaParams); - - SigmaMintId id(10, 0, pubKey); - - BOOST_CHECK_EXCEPTION( - wallet->DeleteUnconfirmedMint(id), - std::runtime_error, - [](std::runtime_error const &e) -> bool{ - return std::string("no mint data in wallet") == e.what(); - } - ); -} - -BOOST_AUTO_TEST_CASE(push_mint_back) -{ - auto id = wallet->GenerateMint(1, 0); - auto mint = wallet->GetMint(id); - - BOOST_CHECK(wallet->HasMint(id)); - BOOST_CHECK(!wallet->IsMintInPool(id.pubKey)); - wallet->DeleteUnconfirmedMint(id); - BOOST_CHECK(!wallet->HasMint(id)); - BOOST_CHECK(wallet->IsMintInPool(id.pubKey)); - - auto mintPoolAfter = wallet->GetMintPoolEntry(); - - BOOST_CHECK_EQUAL(21, mintPoolAfter.size()); - BOOST_CHECK(mint.seedId == mintPoolAfter.front().seedId); -} - -BOOST_AUTO_TEST_CASE(clear_chain_state) -{ - // generate 10 coins and set state - std::vector generatedMints; - for (size_t i = 0; i < 10; i++) { - auto id = wallet->GenerateMint(1, 0); - auto mint = wallet->GetMint(id); - - SigmaMintChainState state(100, 0, i); - wallet->UpdateMintChainstate(id, state); - - if (i % 2) { - wallet->UpdateMintSpendTx(id, uint256S(std::to_string(i))); - mint.spendTx = uint256S(std::to_string(i)); - } - - mint.chainState = state; - generatedMints.push_back(mint); - } - - std::vector mints; - wallet->ListMints(boost::make_function_output_iterator( - [&mints](std::pair const &idAndMint){ - mints.push_back(idAndMint.second); - }) - ); - - BOOST_CHECK_EQUAL( - true, - std::is_permutation( - generatedMints.begin(), generatedMints.end(), - mints.begin() - ) - ); - - // clear state and check - wallet->ClearMintsChainState(); - - std::vector clearedMints; - wallet->ListMints(boost::make_function_output_iterator( - [&clearedMints](std::pair const &idAndMint){ - clearedMints.push_back(idAndMint.second); - }) - ); - - BOOST_CHECK_EQUAL(10, clearedMints.size()); - BOOST_CHECK_EQUAL( - true, - std::is_permutation( - mints.begin(), mints.end(), - clearedMints.begin(), - [](SigmaMint const &a, SigmaMint const &b) -> bool { - return a.seedId == b.seedId; - } - ) - ); - - for (auto const &m : clearedMints) { - BOOST_CHECK_EQUAL(false, m.IsOnChain()); - BOOST_CHECK_EQUAL(false, m.IsSpent()); - } -} - -BOOST_AUTO_TEST_CASE(fill_mint_pool) -{ - auto &mintPool = wallet->GetMintPool(); - - auto indexLess = []( - MintPoolEntry const &a, MintPoolEntry const &b) -> bool { - return a.index < b.index; - }; - - // last coin should be 19 - BOOST_CHECK_EQUAL( - 19, - std::max_element(mintPool.begin(), mintPool.end(), indexLess)->index - ); - - // erase index 0, 10 and 15 - mintPool.erase(mintPool.find(0)); - mintPool.erase(mintPool.find(10)); - mintPool.erase(mintPool.find(15)); - - // filled, 3 coins should be added - wallet->FillMintPool(); - - mintPool = wallet->GetMintPool(); - BOOST_CHECK_EQUAL(20, mintPool.size()); - - // verify - BOOST_CHECK(mintPool.find(0) == mintPool.end()); - BOOST_CHECK(mintPool.find(10) == mintPool.end()); - BOOST_CHECK(mintPool.find(15) == mintPool.end()); - - // last coin should be 22 - BOOST_CHECK_EQUAL( - 22, - std::max_element(mintPool.begin(), mintPool.end(), indexLess)->index - ); - - // 20, 21, 22 should be added - BOOST_CHECK(mintPool.find(20) != mintPool.end()); - BOOST_CHECK(mintPool.find(21) != mintPool.end()); - BOOST_CHECK(mintPool.find(22) != mintPool.end()); -} - -BOOST_AUTO_TEST_CASE(remove_from_mintpool) -{ - auto &mintPool = wallet->GetMintPool(); - - // remove indice 0, 10 and 15 by pubkey - wallet->RemoveFromMintPool(mintPool.find(0)->key); - BOOST_CHECK_EQUAL(19, mintPool.size()); - - wallet->RemoveFromMintPool(mintPool.find(10)->key); - BOOST_CHECK_EQUAL(18, mintPool.size()); - - wallet->RemoveFromMintPool(mintPool.find(15)->key); - BOOST_CHECK_EQUAL(17, mintPool.size()); - - // coins should be deleted - BOOST_CHECK(mintPool.find(0) == mintPool.end()); - BOOST_CHECK(mintPool.find(10) == mintPool.end()); - BOOST_CHECK(mintPool.find(15) == mintPool.end()); -} - -BOOST_AUTO_TEST_CASE(restore_wallet) -{ - // Generate mints before reset wallet. - std::vector before; - - before.push_back(wallet->GenerateMint(3, 0)); - before.push_back(wallet->GenerateMint(3, 1)); - before.push_back(wallet->GenerateMint(4, 2)); - - // Delete current wallet. - auto file = pwalletMain->strWalletFile; - CKey masterPriv; - - BOOST_CHECK_EQUAL(pwalletMain->GetKey(pwalletMain->GetHDChain().masterKeyID, masterPriv), true); - - delete wallet.release(); - UnregisterValidationInterface(pwalletMain); - delete pwalletMain; - bitdb.RemoveDb(file); - - BOOST_CHECK_EQUAL(boost::filesystem::exists(pathTemp / file), false); - - // Create a new fresh wallet with the same master key as previous wallet. - auto masterPub = masterPriv.GetPubKey(); - auto masterId = masterPub.GetID(); - bool firstRun; - - pwalletMain = new CWallet(file); - - LOCK(pwalletMain->cs_wallet); - - BOOST_CHECK_EQUAL(pwalletMain->LoadWallet(firstRun), DB_LOAD_OK); - BOOST_CHECK_EQUAL(firstRun, true); - - auto& meta = pwalletMain->mapKeyMetadata[masterId]; - meta.nCreateTime = GetTime(); - meta.hdKeypath = "m"; - meta.hdMasterKeyID = masterId; - - BOOST_CHECK_EQUAL(pwalletMain->AddKeyPubKey(masterPriv, masterPub), true); - BOOST_CHECK_EQUAL(pwalletMain->SetHDMasterKey(masterPub), true); - pwalletMain->SetBestChain(chainActive.GetLocator()); - - RegisterValidationInterface(pwalletMain); - RegisterWalletRPCCommands(tableRPC); - - wallet.reset(new TestSigmaWallet()); - wallet->ReloadMasterKey(); - - // Generate mints again and it should have exactly the same as before. - std::vector after; - - for (auto& id : before) { - after.push_back(wallet->GenerateMint(id.property, id.denomination)); - } - - BOOST_CHECK_EQUAL(after, before); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/sigmawalletv0_tests.cpp b/src/elysium/test/sigmawalletv0_tests.cpp deleted file mode 100644 index b30891e8c7..0000000000 --- a/src/elysium/test/sigmawalletv0_tests.cpp +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright (c) 2019 The Firo Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "../sigmadb.h" -#include "../sigmawalletv0.h" -#include "../walletmodels.h" - -#include "../../key.h" -#include "../../validation.h" -#include "../../utiltime.h" -#include "../../validationinterface.h" - -#include "../../rpc/server.h" - -#include "../../wallet/db.h" -#include "../../wallet/rpcwallet.h" -#include "../../wallet/wallet.h" -#include "../../wallet/walletdb.h" - -#include "../../wallet/test/wallet_test_fixture.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace std { - -template -basic_ostream& operator<<(basic_ostream& os, const vector& mints) -{ - vector> strings; - - for (auto& m : mints) { - basic_stringstream s; - s << m; - strings.push_back(s.str()); - } - - return os << '[' << boost::algorithm::join(strings, ", ") << ']'; -} - -} // namespace std - -namespace elysium { - -using MintPoolEntry = SigmaWallet::MintPoolEntry; - -namespace { - -class TestSigmaWalletV0 : public SigmaWalletV0 -{ - -public: - TestSigmaWalletV0() - { - } - -public: - // Proxy - using SigmaWalletV0::GeneratePrivateKey; - - SigmaPrivateKey GeneratePrivateKey(uint512 const &seed) - { - return SigmaWalletV0::GeneratePrivateKey(seed); - } - - SigmaWallet::Database* GetDB() - { - return this->database.get(); - } -}; - -struct SigmaWalletV0TestingSetup : WalletTestingSetup -{ - std::unique_ptr wallet; - - SigmaWalletV0TestingSetup() : wallet(new TestSigmaWalletV0()) - { - wallet->ReloadMasterKey(); - } - - std::pair GenerateMint(elysium::PropertyId id, elysium::SigmaDenomination denom) - { - LOCK(pwalletMain->cs_wallet); - auto seedId = pwalletMain->GenerateNewKey(BIP44_ELYSIUM_MINT_INDEX_V0).GetID(); - - auto priv = wallet->GeneratePrivateKey(seedId); - SigmaPublicKey pub(priv, DefaultSigmaParams); - - auto serialId = GetSerialId(priv.serial); - - return std::make_pair( - SigmaMintId(id, denom, pub), - SigmaMint(id, denom, seedId, serialId)); - } - - std::pair GetKey(CKeyID const &id) - { - LOCK(pwalletMain->cs_wallet); - auto priv = wallet->GeneratePrivateKey(id); - SigmaPublicKey pub(priv, DefaultSigmaParams); - - return std::make_pair(priv, pub); - } - - template - void PopulateMintEntries(PropertyId propId, SigmaDenomination denom, size_t amount, Output output) - { - for (size_t i = 0; i < amount; i++) { - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(propId, denom); - - auto key = GetKey(mint.seedId); - - *output++ = MintPoolEntry(key.second, mint.seedId, i); - } - } -}; - -} // unnamed namespace - -BOOST_FIXTURE_TEST_SUITE(elysium_sigmawalletv0_tests, SigmaWalletV0TestingSetup) - -BOOST_AUTO_TEST_CASE(generate_private_key) -{ - uint512 seed; - seed.SetHex( - "5ead609e466f37c92b671e3725da4cd98adafdb23496369c09196f30f8d716dc9f67" - "9026b2f94984f94a289208a2941579ef321dee63d8fd6346ef665c6f60df" - ); - - auto key = wallet->GeneratePrivateKey(seed); - - BOOST_CHECK_EQUAL( - std::string("cb30cc143888ef4e09bb4cfd6d0a699e3c089f42419a8a200132e3190e0e5951"), - key.serial.GetHex()); - - BOOST_CHECK_EQUAL( - std::string("d2e5b830ab1fa8235a9af7db4fd554de5757a0e594acbfc1a4526c3fb26bcbbd"), - key.randomness.GetHex()); -} - -BOOST_AUTO_TEST_CASE(writemint) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - BOOST_CHECK_EQUAL(true, db->WriteMint(id, mint)); -} - -BOOST_AUTO_TEST_CASE(read_nonexistmint) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - SigmaMint data; - - BOOST_CHECK_EQUAL(false, db->HasMint(id)); - BOOST_CHECK_EQUAL(false, db->ReadMint(id, data)); -} - -BOOST_AUTO_TEST_CASE(read_existmint) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - SigmaMint data; - - db->WriteMint(id, mint); - - BOOST_CHECK_EQUAL(true, db->HasMint(id)); - BOOST_CHECK_EQUAL(true, db->ReadMint(id, data)); - BOOST_CHECK_EQUAL(mint, data); -} - -BOOST_AUTO_TEST_CASE(read_erasedmint) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - SigmaMint data; - - db->WriteMint(id, mint); - db->EraseMint(id); - - BOOST_CHECK_EQUAL(false, db->HasMint(id)); - BOOST_CHECK_EQUAL(false, db->ReadMint(id, data)); -} - -BOOST_AUTO_TEST_CASE(write_mintid) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - BOOST_CHECK_EQUAL(true, db->WriteMintId(mint.serialId, id)); -} - -BOOST_AUTO_TEST_CASE(read_nonexistmintid) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - SigmaMintId data; - - BOOST_CHECK_EQUAL(false, db->HasMintId(mint.seedId)); - BOOST_CHECK_EQUAL(false, db->ReadMintId(mint.seedId, data)); -} - -BOOST_AUTO_TEST_CASE(read_existmintid) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - SigmaMintId data; - - db->WriteMintId(mint.serialId, id); - - BOOST_CHECK_EQUAL(true, db->HasMintId(mint.serialId)); - BOOST_CHECK_EQUAL(true, db->ReadMintId(mint.serialId, data)); - BOOST_CHECK_EQUAL(id, data); -} - -BOOST_AUTO_TEST_CASE(read_erasedmintid) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - SigmaMintId data; - - db->WriteMintId(mint.serialId, id); - db->EraseMintId(mint.serialId); - - BOOST_CHECK_EQUAL(false, db->HasMintId(mint.serialId)); - BOOST_CHECK_EQUAL(false, db->ReadMintId(mint.serialId, data)); -} - -BOOST_AUTO_TEST_CASE(writemintpool) -{ - auto db = wallet->GetDB(); - - std::vector mintPool; - - PopulateMintEntries(3, 0, 10, std::back_inserter(mintPool)); - - BOOST_CHECK_EQUAL(true, db->WriteMintPool(mintPool)); -} - -BOOST_AUTO_TEST_CASE(readmintpool) -{ - auto db = wallet->GetDB(); - - std::vector mintPool; - - PopulateMintEntries(3, 0, 10, std::back_inserter(mintPool)); - - db->WriteMintPool(mintPool); - - std::vector data; - BOOST_CHECK_EQUAL(true, db->ReadMintPool(data)); - BOOST_CHECK(mintPool == data); -} - -BOOST_AUTO_TEST_CASE(listmints_nomints) -{ - auto db = wallet->GetDB(); - - size_t counter = 0; - db->ListMints([&](SigmaMintId const&, SigmaMint const&) { - counter++; - }); - - BOOST_CHECK_EQUAL(0, counter); -} - -BOOST_AUTO_TEST_CASE(listmints_withsomemints) -{ - auto db = wallet->GetDB(); - - std::vector> mints; - for (size_t i = 0; i < 10; i++) { - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - mints.push_back(std::make_pair(id, mint)); - - db->WriteMint(id, mint); - } - - std::vector> data; - db->ListMints([&](SigmaMintId &id, SigmaMint &mint) { - data.push_back(std::make_pair(id, mint)); - }); - - BOOST_CHECK(std::is_permutation(mints.begin(), mints.end(), data.begin(), data.end())); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/sigmawalletv1_tests.cpp b/src/elysium/test/sigmawalletv1_tests.cpp deleted file mode 100644 index b497d84a38..0000000000 --- a/src/elysium/test/sigmawalletv1_tests.cpp +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright (c) 2019 The Firo Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "../ecdsa_context.h" -#include "../sigmadb.h" -#include "../sigmawalletv1.h" -#include "../walletmodels.h" - -#include "../../key.h" -#include "../../validation.h" -#include "../../utiltime.h" -#include "../../validationinterface.h" - -#include "../../rpc/server.h" - -#include "../../wallet/db.h" -#include "../../wallet/rpcwallet.h" -#include "../../wallet/wallet.h" -#include "../../wallet/walletdb.h" - -#include "../../wallet/test/wallet_test_fixture.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace std { - -template -basic_ostream& operator<<(basic_ostream& os, const vector& mints) -{ - vector> strings; - - for (auto& m : mints) { - basic_stringstream s; - s << m; - strings.push_back(s.str()); - } - - return os << '[' << boost::algorithm::join(strings, ", ") << ']'; -} - -} // namespace std - -namespace elysium { - -using MintPoolEntry = SigmaWallet::MintPoolEntry; - -namespace { - -class TestSigmaWalletV1 : public SigmaWalletV1 -{ - -public: - TestSigmaWalletV1() - { - } - -public: - // Proxy - bool GetPublicKey(ECDSAPrivateKey const &priv, secp256k1_pubkey &out) - { - return SigmaWalletV1::GetPublicKey(priv, out); - } - - secp_primitives::Scalar GenerateSerial(secp256k1_pubkey const &pubkey) - { - return SigmaWalletV1::GenerateSerial(pubkey); - } - - using SigmaWalletV1::GeneratePrivateKey; - - SigmaPrivateKey GeneratePrivateKey(uint512 const &seed) - { - return SigmaWalletV1::GeneratePrivateKey(seed); - } - - SigmaWallet::Database* GetDB() - { - return database.get(); - } -}; - -struct SigmaWalletV1TestingSetup : WalletTestingSetup -{ - std::unique_ptr wallet; - ECDSAContext context; - - SigmaWalletV1TestingSetup() : - wallet(new TestSigmaWalletV1()), - context(ECDSAContext::CreateSignContext()) - { - wallet->ReloadMasterKey(); - } - - std::pair GenerateMint(elysium::PropertyId id, elysium::SigmaDenomination denom) - { - LOCK(pwalletMain->cs_wallet); - auto seedId = pwalletMain->GenerateNewKey(BIP44_ELYSIUM_MINT_INDEX_V1).GetID(); - - auto priv = wallet->GeneratePrivateKey(seedId); - SigmaPublicKey pub(priv, DefaultSigmaParams); - - auto serialId = GetSerialId(priv.serial); - - return std::make_pair( - SigmaMintId(id, denom, pub), - SigmaMint(id, denom, seedId, serialId)); - } - - std::pair GetKey(CKeyID const &id) - { - LOCK(pwalletMain->cs_wallet); - auto priv = wallet->GeneratePrivateKey(id); - SigmaPublicKey pub(priv, DefaultSigmaParams); - - return std::make_pair(priv, pub); - } - - template - void PopulateMintEntries(PropertyId propId, SigmaDenomination denom, size_t amount, Output output) - { - for (size_t i = 0; i < amount; i++) { - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(propId, denom); - - auto key = GetKey(mint.seedId); - - *output++ = MintPoolEntry(key.second, mint.seedId, i); - } - } -}; - -} // unnamed namespace - -BOOST_FIXTURE_TEST_SUITE(elysium_sigmawalletv1_tests, SigmaWalletV1TestingSetup) - -BOOST_AUTO_TEST_CASE(generate_private_key) -{ - uint512 seed; - seed.SetHex( - "5ead609e466f37c92b671e3725da4cd98adafdb23496369c09196f30f8d716dc9f67" - "9026b2f94984f94a289208a2941579ef321dee63d8fd6346ef665c6f60df" - ); - - auto key = wallet->GeneratePrivateKey(seed); - - auto expectedSecret = ParseHex("cb30cc143888ef4e09bb4cfd6d0a699e3c089f42419a8a200132e3190e0e5951"); - - BOOST_CHECK_EQUAL( - std::string("afffcf7021f53224acb46ac82e71013149cd736ee12f6821802f52f9e92b73dd"), - key.serial.GetHex()); - - BOOST_CHECK_EQUAL( - std::string("d2e5b830ab1fa8235a9af7db4fd554de5757a0e594acbfc1a4526c3fb26bcbbd"), - key.randomness.GetHex()); -} - -BOOST_AUTO_TEST_CASE(get_pubkey) -{ - std::array priv; - auto rawSecret = ParseHex("c634aba3ff562690db4a52cb869d38a43e8d817eddbf68dfb9983af5e9c3e505"); - std::copy(rawSecret.begin(), rawSecret.end(), priv.begin()); - - secp256k1_pubkey pubkey; - wallet->GetPublicKey(priv, pubkey); - - std::array compressedPub; - - size_t outSize = compressedPub.size(); - secp256k1_ec_pubkey_serialize( - context.Get(), - compressedPub.begin(), - &outSize, - &pubkey, - SECP256K1_EC_COMPRESSED); - - BOOST_CHECK_EQUAL( - std::string("02dce8866a065822ede68f54040342dafb55328fc666e2cbe5b37c56ebe5195ca1"), - HexStr(compressedPub)); -} - -BOOST_AUTO_TEST_CASE(generate_serial) -{ - auto rawPubkey = ParseHex("02dce8866a065822ede68f54040342dafb55328fc666e2cbe5b37c56ebe5195ca1"); - - secp256k1_pubkey pubkey; - BOOST_CHECK(secp256k1_ec_pubkey_parse( - context.Get(), - &pubkey, - rawPubkey.data(), - rawPubkey.size() - )); - - auto serial = wallet->GenerateSerial(pubkey); - - BOOST_CHECK_EQUAL( - std::string("b8394f96f9aedc8a00091bf2e4dc639eb54af823477afac4dd89db23657c5576"), - serial.GetHex()); -} - -BOOST_AUTO_TEST_CASE(writemint) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - BOOST_CHECK_EQUAL(true, db->WriteMint(id, mint)); -} - -BOOST_AUTO_TEST_CASE(read_nonexistmint) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - SigmaMint data; - - BOOST_CHECK_EQUAL(false, db->HasMint(id)); - BOOST_CHECK_EQUAL(false, db->ReadMint(id, data)); -} - -BOOST_AUTO_TEST_CASE(read_existmint) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - SigmaMint data; - - db->WriteMint(id, mint); - - BOOST_CHECK_EQUAL(true, db->HasMint(id)); - BOOST_CHECK_EQUAL(true, db->ReadMint(id, data)); - BOOST_CHECK_EQUAL(mint, data); -} - -BOOST_AUTO_TEST_CASE(read_erasedmint) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - SigmaMint data; - - db->WriteMint(id, mint); - db->EraseMint(id); - - BOOST_CHECK_EQUAL(false, db->HasMint(id)); - BOOST_CHECK_EQUAL(false, db->ReadMint(id, data)); -} - -BOOST_AUTO_TEST_CASE(write_mintid) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - BOOST_CHECK_EQUAL(true, db->WriteMintId(mint.serialId, id)); -} - -BOOST_AUTO_TEST_CASE(read_nonexistmintid) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - SigmaMintId data; - - BOOST_CHECK_EQUAL(false, db->HasMintId(mint.seedId)); - BOOST_CHECK_EQUAL(false, db->ReadMintId(mint.seedId, data)); -} - -BOOST_AUTO_TEST_CASE(read_existmintid) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - SigmaMintId data; - - db->WriteMintId(mint.serialId, id); - - BOOST_CHECK_EQUAL(true, db->HasMintId(mint.serialId)); - BOOST_CHECK_EQUAL(true, db->ReadMintId(mint.serialId, data)); - BOOST_CHECK_EQUAL(id, data); -} - -BOOST_AUTO_TEST_CASE(read_erasedmintid) -{ - auto db = wallet->GetDB(); - - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - SigmaMintId data; - - db->WriteMintId(mint.serialId, id); - db->EraseMintId(mint.serialId); - - BOOST_CHECK_EQUAL(false, db->HasMintId(mint.serialId)); - BOOST_CHECK_EQUAL(false, db->ReadMintId(mint.serialId, data)); -} - -BOOST_AUTO_TEST_CASE(writemintpool) -{ - auto db = wallet->GetDB(); - - std::vector mintPool; - - PopulateMintEntries(3, 0, 10, std::back_inserter(mintPool)); - - BOOST_CHECK_EQUAL(true, db->WriteMintPool(mintPool)); -} - -BOOST_AUTO_TEST_CASE(readmintpool) -{ - auto db = wallet->GetDB(); - - std::vector mintPool; - - PopulateMintEntries(3, 0, 10, std::back_inserter(mintPool)); - - db->WriteMintPool(mintPool); - - std::vector data; - BOOST_CHECK_EQUAL(true, db->ReadMintPool(data)); - BOOST_CHECK(mintPool == data); -} - -BOOST_AUTO_TEST_CASE(listmints_nomints) -{ - auto db = wallet->GetDB(); - - size_t counter = 0; - db->ListMints([&](SigmaMintId const&, SigmaMint const&) { - counter++; - }); - - BOOST_CHECK_EQUAL(0, counter); -} - -BOOST_AUTO_TEST_CASE(listmints_withsomemints) -{ - auto db = wallet->GetDB(); - - std::vector> mints; - for (size_t i = 0; i < 10; i++) { - SigmaMintId id; - SigmaMint mint; - std::tie(id, mint) = GenerateMint(3, 0); - - mints.push_back(std::make_pair(id, mint)); - - db->WriteMint(id, mint); - } - - std::vector> data; - db->ListMints([&](SigmaMintId &id, SigmaMint &mint) { - data.push_back(std::make_pair(id, mint)); - }); - - BOOST_CHECK(std::is_permutation(mints.begin(), mints.end(), data.begin(), data.end())); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/test/signaturebuilder_sigmav1_tests.cpp b/src/elysium/test/signaturebuilder_sigmav1_tests.cpp deleted file mode 100644 index dee15c85ea..0000000000 --- a/src/elysium/test/signaturebuilder_sigmav1_tests.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "../sigmaprimitives.h" -#include "../signaturebuilder.h" - -#include "../../test/test_bitcoin.h" - -#include "../../wallet/test/wallet_test_fixture.h" - -#include - -namespace elysium { - -class TestSignatureSigmaV1Builder : public SigmaV1SignatureBuilder -{ -public: - TestSignatureSigmaV1Builder( - CBitcoinAddress const &receiver, - int64_t referenceAmount, - SigmaProof const &proof) - : SigmaV1SignatureBuilder(receiver, referenceAmount, proof) - { - } - -public: - uint256 GetHash() - { - return hash; - } -}; - -struct SignatureBuilderSigmaV1Setup : BasicTestingSetup -{ -public: - CBitcoinAddress address; - SigmaProof proof; - - CKey secret; - CPubKey publicKey; - -public: - SignatureBuilderSigmaV1Setup() - : address("a8ULhhDgfdSiXJhSZVdhb8EuDc6R3ogsaM"), proof(DefaultSigmaParams) - { - auto rawProof = ParseHex("0881ac0a8392734a66179ed5f06b0fcc90804776e2194e2537c83abab1b0a8cf01007fa57fdf9caecf435ad51f8fdd5062a3360063954098026efea1041d51843d7700005785485b9c61950299f98850894ee101497ff0c5e60f70ca6468dc05a2f6757c010045b2e2575c32363fdc7eb4c0fcfd925f4ca196b2e1a5e8bea76b34e819e4fcc7000015f0c997162cf54ca1ca376e5b417fe04c2900888fb50c70598ca5f11229afbdb1faa42ca7c5734730f9e733b010556592619f29730159d79985798db97d268f1a882c8947a0e2da27534490efa2021e51f8b398d2e3e7d07debd17fc76e599ce4f9ea28886054d00103f0764ad193c89eecdce65f53e4603db2bffe0c9beae474afa96fb8d23f17eef92b32b56bd44716b8393443c63b78f93ed42fb2a1b6df0e0eb5c799ba2cc8dfe4b92cbd98cc98e7d0f7b4370413b442b8421b8de820dafae6271b51ab8f923eead1f81e32f85ea9075d905523e25fa6bd64dbf5cfcf5fe3bdaa663c762179aeda6361edf17424c3d0e96ebd5d628d52fbcd6df294e178fd9a1ab33b36e66e294f551de6d0dda865b6556ce72eac65b31a96d30d0c2225e7491830ab8aae2d7323efebe503b6cd9b0f7a3c6780dc446c2a198d88d0f805fc7e0fef6bf04ba413360ed73a6957be311269aabe4a5193182a7e0fc7b332e5320faa7ec20ea29ac7d348f6c3fb997e0c916c2e249ba6a1677f7a464eb5db817a9a063e85f0a0017b6e90e2e9e5b668360d49420429750043cee9f2f4be8c89c9f3daa6e353e2b800f8ca530e924df891d6eb6a33897d4551440d721e808757eaa83747003479e6b1f19e5f7a1cc8bd4bf54008cad7ff49f8d53e232772a2fd30576115c3d10f941cb8a49fe4d144dc0977e6f7f197f25d39ebfd5333cdfd71bad101637e8470470dc1d59b21ef16b5bf3150473bc5736cff706c59c82363acadd0b6d311c12944692825ae6eded3b0ac92d333862f85a516b59dbdab6dcd858322907412b8301fd3e5a1a737e86734abb363cc1fdc33635776bcf5adb69e16fc02b00ccbd90e37178375934740a8daa986294a2f0f4f44a7a73ad57611dce568c1a4b51542c202019527b77d4231869c26f7b44e6190933ed372391dd7cf09c3c6a522cb7dcf09a1344b64c597ab887e3840c642a07e3561b8ead98f152eee2a120912e31eb75c337e16a57adfc6b48ceb4c887473756aeba1ca94040c9546b20756551df2f116695e9b1a00eb28ce357a3beaeb62006241fde992aa33b2fbfec20000bf44451073162633dd4c690b75aaf6fd796c5dea3f29e775e3739673e529abc90100ad4907d4dfb26812b29def0167b1234fcbfcbdbb4f6dda8e45322d4a32e0555a010091f92a2ae22c5a9e1c3bbd3a9ff1c4a5aec7718080cbe06601021e0a082e07970000d57157ea9edfc6165cb40d122b9967fc64fbd74c7b7edfa75d990475040e67f40000fb32e10c853f44b877693ddf55be4cca53a54209956f68dbfb77034f16348281000008515c1f54a4cfe87cc7d06c548cc0119b5c9e0e04b8b604cd35d069ebadf6ca000004a805cb321df988b32acda8d5c8e60b0d17e0df5fe3c577990eb873f47d46b7"); - CDataStream ss(rawProof, SER_NETWORK, PROTOCOL_VERSION); - - proof.Unserialize(ss); - - std::array rawSecret; - std::fill(rawSecret.begin(), rawSecret.end(), 0x11); - secret.Set(rawSecret.begin(), rawSecret.end(), true); - - auto rawPublicKey = ParseHex("034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa"); - publicKey.Set(rawPublicKey.begin(), rawPublicKey.end()); - } - -public: - CKey GetKey() - { - return secret; - } -}; - -BOOST_FIXTURE_TEST_SUITE(elysium_signaturebuilder_sigmav1_tests, SignatureBuilderSigmaV1Setup) - -BOOST_AUTO_TEST_CASE(construct_withvalidkey_verify_hash) -{ - std::unique_ptr builder; - - BOOST_CHECK_NO_THROW( - builder.reset(new TestSignatureSigmaV1Builder(address, 10, proof))); - - auto hash = builder->GetHash(); - BOOST_CHECK_EQUAL( - "e8ab0af8c1d15d5ff2ced260b4082ac01ade457da4c29dc2b8a97144b6b9c4c0", - HexStr(hash.begin(), hash.end())); -} - -BOOST_AUTO_TEST_CASE(sign) -{ - TestSignatureSigmaV1Builder builder(address, 10, proof); - auto signer = GetKey(); - - auto signature = builder.Sign(signer); - - BOOST_CHECK_EQUAL( - "181dad1d268f03d0a38beb34f6efa4ed12cbd6d00b62fc1d6094fa33746cdd0f73b3baa4d9cf699886fd448c0cd0ae7d1447e533fd6b5394f8f4fcd3c009de37", - HexStr(signature.GetCompact(ECDSAContext::CreateSignContext()))); -} - -BOOST_AUTO_TEST_CASE(verify) -{ - auto context = ECDSAContext::CreateVerifyContext(); - - TestSignatureSigmaV1Builder builder(address, 10, proof); - ECDSASignature signature; - auto validSig = ParseHex("181dad1d268f03d0a38beb34f6efa4ed12cbd6d00b62fc1d6094fa33746cdd0f73b3baa4d9cf699886fd448c0cd0ae7d1447e533fd6b5394f8f4fcd3c009de37"); - auto invalidSig = ParseHex("181dad1d268f03d0a38beb34f6efa4ed12cbd6d00b62fc1d6094fa33746cdd0f73b3baa4d9cf699886fd448c0cd0ae7d1447e533fd6b5394f8f4fcd3c009de38"); - - signature = ECDSASignature::ParseCompact(context, validSig.data()); - BOOST_CHECK_EQUAL(true, builder.Verify(publicKey, signature)); - - // invalid signature - builder = TestSignatureSigmaV1Builder(address, 10, proof); - signature = ECDSASignature::ParseCompact(context, invalidSig.data()); - BOOST_CHECK_EQUAL(false, builder.Verify(publicKey, signature)); - - // invalid content - signature = ECDSASignature::ParseCompact(context, validSig.data()); - builder = TestSignatureSigmaV1Builder(CBitcoinAddress("aGXhTgKqDgdH9kHNTyg47TbwGfs54k2cQF"), 10, proof); - BOOST_CHECK_EQUAL(false, builder.Verify(publicKey, signature)); - - builder = TestSignatureSigmaV1Builder(address, 11, proof); - BOOST_CHECK_EQUAL(false, builder.Verify(publicKey, signature)); - - auto rawPublicKey = ParseHex("0277d283f21eb4b02d8d0d39494821b8684fc7c9507d81485847f15ed92311e66e"); - CPubKey otherPublicKey(rawPublicKey); - builder = TestSignatureSigmaV1Builder(address, 11, proof); - BOOST_CHECK_EQUAL(false, builder.Verify(otherPublicKey, signature)); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium \ No newline at end of file diff --git a/src/elysium/test/sp_tests.cpp b/src/elysium/test/sp_tests.cpp deleted file mode 100644 index 5016602e00..0000000000 --- a/src/elysium/test/sp_tests.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "../sp.h" - -#include "../../test/test_bitcoin.h" -#include "../../validation.h" -#include "../../miner.h" -#include "../../wallet/wallet.h" - -#include - -struct SpTestingSetup : public TestChain100Setup -{ - SpTestingSetup() - : db(pathTemp / "MP_spinfo_test", false) - { - } - - int GenerateEmptyBlock(size_t blocks) - { - int blockCount = 0; - CReserveKey reserveKey(pwalletMain); - while (blocks--) { - CreateAndProcessBlock({}, reserveKey.reserveScript); - } - - return blockCount; - } - - CMPSPInfo db; -}; - -BOOST_FIXTURE_TEST_SUITE(elysium_sp_tests, SpTestingSetup) - -BOOST_AUTO_TEST_CASE(not_exist_sp) -{ - BOOST_CHECK_EXCEPTION( - db.getDenominationRemainingConfirmation(0, 0, 10), - std::invalid_argument, - [](std::invalid_argument const &e) -> bool { - return std::string("property notfound") == e.what(); - } - ); -} - -BOOST_AUTO_TEST_CASE(not_exist_denomination) -{ - CMPSPInfo::Entry sp; - db.putSP(0, sp); - BOOST_CHECK_EQUAL( - 100, - db.getDenominationRemainingConfirmation(0, 0, 100) - ); -} - -BOOST_AUTO_TEST_CASE(exist_denomination) -{ - CMPSPInfo::Entry sp; - sp.creation_block = chainActive.Tip()->GetBlockHash(); - sp.update_block = sp.creation_block; - auto property = db.putSP(0, sp); - - // add new denom - GenerateEmptyBlock(5); - BOOST_CHECK(db.getSP(property, sp)); - sp.update_block = chainActive.Tip()->GetBlockHash(); - sp.denominations = {1}; - BOOST_CHECK(db.updateSP(property, sp)); - - // 1 confirmation - BOOST_CHECK_EQUAL(0, db.getDenominationRemainingConfirmation(property, 0, 0)); - BOOST_CHECK_EQUAL(1, db.getDenominationRemainingConfirmation(property, 0, 2)); - BOOST_CHECK_EQUAL(0, db.getDenominationRemainingConfirmation(property, 0, 1)); - - GenerateEmptyBlock(5); - - // 6 confimations - BOOST_CHECK_EQUAL(0, db.getDenominationRemainingConfirmation(property, 0, 0)); - BOOST_CHECK_EQUAL(1, db.getDenominationRemainingConfirmation(property, 0, 7)); - BOOST_CHECK_EQUAL(0, db.getDenominationRemainingConfirmation(property, 0, 6)); - - // require 2 confirmations must return 0 - BOOST_CHECK_EQUAL(0, db.getDenominationRemainingConfirmation(property, 0, 2)); -} - -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/src/elysium/test/strtoint64_tests.cpp b/src/elysium/test/strtoint64_tests.cpp deleted file mode 100644 index a8a08ec2b2..0000000000 --- a/src/elysium/test/strtoint64_tests.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "elysium/parse_string.h" - -#include "test/test_bitcoin.h" - -#include - -#include -#include - -using namespace elysium; - -BOOST_FIXTURE_TEST_SUITE(elysium_strtoint64_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(strtoint64_invidisible) -{ - // zero amount - BOOST_CHECK(StrToInt64("0", false) == 0); - // big num - BOOST_CHECK(StrToInt64("4000000000000000", false) == static_cast(4000000000000000LL)); - // max int64 - BOOST_CHECK(StrToInt64("9223372036854775807", false) == static_cast(9223372036854775807LL)); -} - -BOOST_AUTO_TEST_CASE(strtoint64_invidisible_truncate) -{ - // ignore any char after decimal mark - BOOST_CHECK(StrToInt64("8.76543210123456878901", false) == 8); - BOOST_CHECK(StrToInt64("8.765432101.2345687890", false) == 8); - BOOST_CHECK(StrToInt64("2345.AbCdEhf71z1.23", false) == 2345); -} - -BOOST_AUTO_TEST_CASE(strtoint64_invidisible_invalid) -{ - // invalid, number is negative - BOOST_CHECK(StrToInt64("-4", false) == 0); - // invalid, number is over max int64 - BOOST_CHECK(StrToInt64("9223372036854775808", false) == 0); - // invalid, minus sign in string - BOOST_CHECK(StrToInt64("2345.AbCdEFG71z88-1.23", false) == 0); -} - -BOOST_AUTO_TEST_CASE(strtoint64_divisible) -{ - // range 0 to max int64 - BOOST_CHECK(StrToInt64("0.000", true) == 0); - BOOST_CHECK(StrToInt64("92233720368.54775807", true) == static_cast(9223372036854775807LL)); - // check padding - BOOST_CHECK(StrToInt64("0.00000004", true) == 4); - BOOST_CHECK(StrToInt64("0.0000004", true) == 40); - BOOST_CHECK(StrToInt64("0.0004", true) == 40000); - BOOST_CHECK(StrToInt64("0.4", true) == 40000000); - BOOST_CHECK(StrToInt64("4.0", true) == 400000000); - // truncate after 8 digits - BOOST_CHECK(StrToInt64("40.00000000000099", true) == static_cast(4000000000LL)); - BOOST_CHECK(StrToInt64("92233720368.54775807000", true) == static_cast(9223372036854775807LL)); -} - -BOOST_AUTO_TEST_CASE(strtoint64_divisible_truncate) -{ - // truncate after 8 digits - BOOST_CHECK(StrToInt64("40.00000000000099", true) == static_cast(4000000000LL)); - BOOST_CHECK(StrToInt64("92233720368.54775807000", true) == static_cast(9223372036854775807LL)); - BOOST_CHECK(StrToInt64("92233720368.54775807000", true) == static_cast(9223372036854775807LL)); -} - -BOOST_AUTO_TEST_CASE(strtoint64_divisible_invalid) -{ - // invalid, number is over max int64 - BOOST_CHECK(StrToInt64("92233720368.54775808", true) == 0); - // invalid, more than one decimal mark in string - BOOST_CHECK(StrToInt64("1234..12345678", true) == 0); - // invalid, alpha chars in string - BOOST_CHECK(StrToInt64("1234.12345A", true) == 0); - // invalid, number is negative - BOOST_CHECK(StrToInt64("-4.0", true) == 0); - // invalid, minus sign in string - BOOST_CHECK(StrToInt64("4.1234-5678", true) == 0); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/swapbyteorder_tests.cpp b/src/elysium/test/swapbyteorder_tests.cpp deleted file mode 100644 index 25c3d87e70..0000000000 --- a/src/elysium/test/swapbyteorder_tests.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "elysium/convert.h" - -#include "test/test_bitcoin.h" - -#include - -#include - -using namespace elysium; - -BOOST_FIXTURE_TEST_SUITE(elysium_swapbyteorder_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(swapbyteorder_cycle) -{ - uint16_t a1 = 41959U, a2 = a1; - - swapByteOrder16(a2); - swapByteOrder16(a2); - BOOST_CHECK_EQUAL(a1, a2); // Should be equal, swapping twice brings us back to the original value - - uint32_t b1 = 16909060U, b2 = b1; - swapByteOrder32(b2); - swapByteOrder32(b2); - BOOST_CHECK_EQUAL(b1, b2); // Should be equal, swapping twice brings us back to the original value - - uint64_t c1 = 722385979038285U, c2 = c1; - swapByteOrder64(c2); - swapByteOrder64(c2); - BOOST_CHECK_EQUAL(c1, c2); // Should be equal, swapping twice brings us back to the original value -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/tally_tests.cpp b/src/elysium/test/tally_tests.cpp deleted file mode 100644 index 1f95d8b5ea..0000000000 --- a/src/elysium/test/tally_tests.cpp +++ /dev/null @@ -1,322 +0,0 @@ -#include "elysium/tally.h" - -#include "test/test_bitcoin.h" - -#include - -#include - -BOOST_FIXTURE_TEST_SUITE(elysium_tally_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(empty_tally) -{ - CMPTally tally; - BOOST_CHECK_EQUAL(0, tally.getMoney(0, BALANCE)); - BOOST_CHECK_EQUAL(0, tally.getMoney(0, SELLOFFER_RESERVE)); - BOOST_CHECK_EQUAL(0, tally.getMoney(0, ACCEPT_RESERVE)); - BOOST_CHECK_EQUAL(0, tally.getMoney(0, PENDING)); - BOOST_CHECK_EQUAL(0, tally.getMoney(0, METADEX_RESERVE)); - // TallyType out of range: - BOOST_CHECK_EQUAL(0, tally.getMoney(0, static_cast(5))); - BOOST_CHECK_EQUAL(0, tally.getMoney(0, static_cast(6))); - // TallyType out of range: - BOOST_CHECK(!tally.updateMoney(0, 1, static_cast(5))); - BOOST_CHECK(!tally.updateMoney(0, 1, static_cast(6))); - - BOOST_CHECK_EQUAL(0, tally.init()); - BOOST_CHECK_EQUAL(0, tally.next()); - - BOOST_CHECK_EQUAL(0, tally.getMoneyAvailable(0)); - BOOST_CHECK_EQUAL(0, tally.getMoneyReserved(0)); - BOOST_CHECK_EQUAL(0, tally.getMoneyAvailable(55)); - BOOST_CHECK_EQUAL(0, tally.getMoneyReserved(55)); -} - -BOOST_AUTO_TEST_CASE(filled_tally) -{ - CMPTally tally; - BOOST_CHECK(!tally.updateMoney(0, 0, BALANCE)); - BOOST_CHECK(!tally.updateMoney(0, 0, SELLOFFER_RESERVE)); - BOOST_CHECK(!tally.updateMoney(0, 0, ACCEPT_RESERVE)); - BOOST_CHECK(!tally.updateMoney(0, 0, PENDING)); - BOOST_CHECK(!tally.updateMoney(0, 0, METADEX_RESERVE)); - - BOOST_CHECK_EQUAL(0, tally.getMoney(0, BALANCE)); - BOOST_CHECK_EQUAL(0, tally.getMoney(0, SELLOFFER_RESERVE)); - BOOST_CHECK_EQUAL(0, tally.getMoney(0, ACCEPT_RESERVE)); - BOOST_CHECK_EQUAL(0, tally.getMoney(0, PENDING)); - BOOST_CHECK_EQUAL(0, tally.getMoney(0, METADEX_RESERVE)); - - BOOST_CHECK_EQUAL(0, tally.getMoneyAvailable(0)); - BOOST_CHECK_EQUAL(0, tally.getMoneyReserved(0)); - - BOOST_CHECK(tally.updateMoney(0, 1, BALANCE)); - BOOST_CHECK(tally.updateMoney(0, 100, SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(1, int64_t(9223372036854775807LL), ACCEPT_RESERVE)); - BOOST_CHECK(tally.updateMoney(2, (-int64_t(9223372036854775807LL)-1), PENDING)); - BOOST_CHECK(tally.updateMoney(5, int64_t(4294967296L), METADEX_RESERVE)); - - BOOST_CHECK_EQUAL(tally.getMoney(0, BALANCE), 1); - BOOST_CHECK_EQUAL(tally.getMoney(0, SELLOFFER_RESERVE), 100); - BOOST_CHECK_EQUAL(tally.getMoney(0, ACCEPT_RESERVE), 0); - BOOST_CHECK_EQUAL(tally.getMoney(0, PENDING), 0); - BOOST_CHECK_EQUAL(tally.getMoney(0, METADEX_RESERVE), 0); - - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(0), 1); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(0), 100); - - BOOST_CHECK_EQUAL(tally.getMoney(1, BALANCE), 0); - BOOST_CHECK_EQUAL(tally.getMoney(1, SELLOFFER_RESERVE), 0); - BOOST_CHECK_EQUAL(tally.getMoney(1, ACCEPT_RESERVE), int64_t(9223372036854775807LL)); - BOOST_CHECK_EQUAL(tally.getMoney(1, PENDING), 0); - BOOST_CHECK_EQUAL(tally.getMoney(1, METADEX_RESERVE), 0); - - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(1), 0); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(1), int64_t(9223372036854775807LL)); - - BOOST_CHECK_EQUAL(tally.getMoney(2, BALANCE), 0); - BOOST_CHECK_EQUAL(tally.getMoney(2, SELLOFFER_RESERVE), 0); - BOOST_CHECK_EQUAL(tally.getMoney(2, ACCEPT_RESERVE), 0); - BOOST_CHECK_EQUAL(tally.getMoney(2, PENDING), (-int64_t(9223372036854775807LL)-1)); - BOOST_CHECK_EQUAL(tally.getMoney(2, METADEX_RESERVE), 0); - - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(2), (-int64_t(9223372036854775807LL)-1)); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(2), 0); - - BOOST_CHECK_EQUAL(tally.getMoney(5, BALANCE), 0); - BOOST_CHECK_EQUAL(tally.getMoney(5, SELLOFFER_RESERVE), 0); - BOOST_CHECK_EQUAL(tally.getMoney(5, ACCEPT_RESERVE), 0); - BOOST_CHECK_EQUAL(tally.getMoney(5, PENDING), 0); - BOOST_CHECK_EQUAL(tally.getMoney(5, METADEX_RESERVE), int64_t(4294967296L)); - - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(5), 0); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(5), int64_t(4294967296L)); - - /** - * Note: - * The internal iterator must be replaced via init(), - * after inserting a new entry via updateMoney(). - */ - BOOST_CHECK_EQUAL(0, tally.init()); - BOOST_CHECK_EQUAL(0, tally.next()); - BOOST_CHECK_EQUAL(1, tally.next()); - BOOST_CHECK_EQUAL(2, tally.next()); - BOOST_CHECK_EQUAL(5, tally.next()); - BOOST_CHECK_EQUAL(0, tally.init()); - BOOST_CHECK_EQUAL(0, tally.next()); - BOOST_CHECK_EQUAL(1, tally.next()); -} - -BOOST_AUTO_TEST_CASE(tally_entry_order) -{ - CMPTally tally; - - BOOST_CHECK(tally.updateMoney(1, 1, BALANCE)); - BOOST_CHECK(tally.updateMoney(4, 1, SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(3, 1, ACCEPT_RESERVE)); - BOOST_CHECK(tally.updateMoney(9, 1, BALANCE)); - BOOST_CHECK(tally.updateMoney(2, -1, PENDING)); - BOOST_CHECK(tally.updateMoney(5, 1, METADEX_RESERVE)); - BOOST_CHECK(tally.updateMoney(9, 3, BALANCE)); - BOOST_CHECK(tally.updateMoney(9, -6, PENDING)); - BOOST_CHECK(tally.updateMoney(8, 1, SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(7, 1, ACCEPT_RESERVE)); - BOOST_CHECK(tally.updateMoney(6, 3, BALANCE)); - BOOST_CHECK(tally.updateMoney(9, 1, SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(9, 2, ACCEPT_RESERVE)); - BOOST_CHECK(tally.updateMoney(9, 3, METADEX_RESERVE)); - BOOST_CHECK(tally.updateMoney(9, 4, METADEX_RESERVE)); - BOOST_CHECK(tally.updateMoney(8, 1, BALANCE)); - BOOST_CHECK(tally.updateMoney(70, 1, BALANCE)); - BOOST_CHECK(tally.updateMoney(4, 1, SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(5, 1, BALANCE)); - BOOST_CHECK(tally.updateMoney(1, 1, BALANCE)); - BOOST_CHECK(tally.updateMoney(6, -2, PENDING)); - BOOST_CHECK(tally.updateMoney(3, 1, ACCEPT_RESERVE)); - BOOST_CHECK(tally.updateMoney(2, 1, METADEX_RESERVE)); - BOOST_CHECK(tally.updateMoney(4, -1, PENDING)); - BOOST_CHECK(tally.updateMoney(2, -1, PENDING)); - - BOOST_CHECK_EQUAL(1, tally.init()); - // Begin iterations: - BOOST_CHECK_EQUAL(1, tally.next()); - BOOST_CHECK_EQUAL(2, tally.next()); - BOOST_CHECK_EQUAL(3, tally.next()); - BOOST_CHECK_EQUAL(4, tally.next()); - BOOST_CHECK_EQUAL(5, tally.next()); - BOOST_CHECK_EQUAL(6, tally.next()); - BOOST_CHECK_EQUAL(7, tally.next()); - BOOST_CHECK_EQUAL(8, tally.next()); - BOOST_CHECK_EQUAL(9, tally.next()); - BOOST_CHECK_EQUAL(70, tally.next()); - // End of tally reached: - BOOST_CHECK_EQUAL(0, tally.next()); - - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(1), 2); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(1), 0); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(2), -2); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(2), 1); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(3), 0); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(3), 2); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(4), -1); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(4), 2); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(5), 1); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(5), 1); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(6), 1); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(6), 0); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(7), 0); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(7), 1); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(8), 1); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(8), 1); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(9), -2); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(9), 10); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(70), 1); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(70), 0); -} - -BOOST_AUTO_TEST_CASE(tally_equality) -{ - CMPTally tally1; - CMPTally tally2; - - BOOST_CHECK(tally1 == tally2); - BOOST_CHECK(tally2 == tally1); - - BOOST_CHECK(tally1.updateMoney(4, 5, ACCEPT_RESERVE)); - BOOST_CHECK(tally1.updateMoney(3, 3, METADEX_RESERVE)); - BOOST_CHECK(tally1.updateMoney(3, 7, SELLOFFER_RESERVE)); - BOOST_CHECK(tally1.updateMoney(1, 5, BALANCE)); - BOOST_CHECK(tally1.updateMoney(9, 4, BALANCE)); - BOOST_CHECK(tally1.updateMoney(1, 50, BALANCE)); - BOOST_CHECK(tally1.updateMoney(1, -3, BALANCE)); - BOOST_CHECK(tally1.updateMoney(1, -3, PENDING)); - - BOOST_CHECK(tally2.updateMoney(3, 4, SELLOFFER_RESERVE)); - BOOST_CHECK(tally2.updateMoney(1, 20, BALANCE)); - BOOST_CHECK(tally2.updateMoney(4, 5, ACCEPT_RESERVE)); - BOOST_CHECK(tally2.updateMoney(9, 4, BALANCE)); - BOOST_CHECK(tally2.updateMoney(3, 3, SELLOFFER_RESERVE)); - BOOST_CHECK(tally2.updateMoney(1, 5, BALANCE)); - BOOST_CHECK(tally2.updateMoney(3, 3, METADEX_RESERVE)); - BOOST_CHECK(tally2.updateMoney(1, 5, BALANCE)); - BOOST_CHECK(tally2.updateMoney(1, 28, BALANCE)); - BOOST_CHECK(tally2.updateMoney(1, -6, BALANCE)); - BOOST_CHECK(tally2.updateMoney(1, -3, PENDING)); - - BOOST_CHECK(tally1 == tally2); - BOOST_CHECK(tally2 == tally1); - - BOOST_CHECK(tally1.getMoneyAvailable(1) == tally2.getMoneyAvailable(1)); - BOOST_CHECK(tally1.getMoneyAvailable(3) == tally2.getMoneyAvailable(3)); - BOOST_CHECK(tally1.getMoneyAvailable(4) == tally2.getMoneyAvailable(4)); - BOOST_CHECK(tally1.getMoneyAvailable(9) == tally2.getMoneyAvailable(9)); - BOOST_CHECK(tally1.getMoneyAvailable(0) == tally2.getMoneyAvailable(0)); - - BOOST_CHECK(tally2.getMoneyReserved(1) == tally1.getMoneyReserved(1)); - BOOST_CHECK(tally2.getMoneyReserved(3) == tally1.getMoneyReserved(3)); - BOOST_CHECK(tally2.getMoneyReserved(4) == tally1.getMoneyReserved(4)); - BOOST_CHECK(tally2.getMoneyReserved(9) == tally1.getMoneyReserved(9)); - BOOST_CHECK(tally2.getMoneyReserved(0) == tally1.getMoneyReserved(0)); - - BOOST_CHECK_EQUAL(1, tally1.init()); - BOOST_CHECK_EQUAL(1, tally1.next()); - BOOST_CHECK_EQUAL(3, tally1.next()); - BOOST_CHECK_EQUAL(4, tally1.next()); - BOOST_CHECK_EQUAL(9, tally1.next()); - BOOST_CHECK_EQUAL(0, tally1.next()); - BOOST_CHECK_EQUAL(1, tally2.init()); - BOOST_CHECK_EQUAL(1, tally2.next()); - BOOST_CHECK_EQUAL(3, tally2.next()); - BOOST_CHECK_EQUAL(4, tally2.next()); - - BOOST_CHECK(tally1 == tally2); - - BOOST_CHECK(tally1.updateMoney(9, -2, BALANCE)); - BOOST_CHECK(tally1.updateMoney(9, -2, BALANCE)); - BOOST_CHECK(tally2.updateMoney(9, -4, BALANCE)); - BOOST_CHECK(tally1 == tally2); - BOOST_CHECK(tally1.getMoneyAvailable(9) == 0); - - BOOST_CHECK(tally1.updateMoney(8, 3, METADEX_RESERVE)); - BOOST_CHECK(tally1 != tally2); - BOOST_CHECK(tally1.getMoneyReserved(8) == 3); - - BOOST_CHECK(tally2.updateMoney(8, 4, METADEX_RESERVE)); - BOOST_CHECK(tally1 != tally2); - BOOST_CHECK(tally2.getMoneyReserved(8) == 4); - - BOOST_CHECK(tally2.updateMoney(8, -1, METADEX_RESERVE)); - BOOST_CHECK(tally1 == tally2); - BOOST_CHECK(tally1.getMoneyReserved(8) == 3); - - BOOST_CHECK(tally1.updateMoney(7, 1, BALANCE)); - BOOST_CHECK(tally2.updateMoney(5, 1, BALANCE)); - BOOST_CHECK(tally1 != tally2); - - BOOST_CHECK(tally1.updateMoney(5, 1, BALANCE)); - BOOST_CHECK(tally2.updateMoney(7, 1, BALANCE)); - BOOST_CHECK(tally1 == tally2); - - BOOST_CHECK(tally1.getMoneyAvailable(5) == 1); - BOOST_CHECK(tally1.getMoneyAvailable(7) == 1); - BOOST_CHECK(tally2.getMoneyAvailable(5) == 1); - BOOST_CHECK(tally2.getMoneyAvailable(7) == 1); -} - -BOOST_AUTO_TEST_CASE(tally_overflow) -{ - CMPTally tally; - - BOOST_CHECK(!tally.updateMoney(1, -1, BALANCE)); - BOOST_CHECK(!tally.updateMoney(2, -34242, SELLOFFER_RESERVE)); - BOOST_CHECK(!tally.updateMoney(2, (-int64_t(9223372036854775807LL)-1), ACCEPT_RESERVE)); - BOOST_CHECK(!tally.updateMoney(3, -int64_t(1099511627777L), METADEX_RESERVE)); - - BOOST_CHECK(tally.updateMoney(1, int64_t(9223372036854775807LL), BALANCE)); - BOOST_CHECK_EQUAL(tally.getMoney(1, BALANCE), int64_t(9223372036854775807LL)); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(1), int64_t(9223372036854775807LL)); - - BOOST_CHECK(!tally.updateMoney(1, 1, BALANCE)); - BOOST_CHECK_EQUAL(tally.getMoney(1, BALANCE), int64_t(9223372036854775807LL)); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(1), int64_t(9223372036854775807LL)); - - BOOST_CHECK(tally.updateMoney(1, (-int64_t(9223372036854775807LL)-1), PENDING)); - BOOST_CHECK_EQUAL(tally.getMoney(1, BALANCE), int64_t(9223372036854775807LL)); - BOOST_CHECK_EQUAL(tally.getMoney(1, PENDING), (-int64_t(9223372036854775807LL)-1)); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(1), -1); - - BOOST_CHECK(!tally.updateMoney(1, -1, PENDING)); - BOOST_CHECK_EQUAL(tally.getMoney(1, BALANCE), int64_t(9223372036854775807LL)); - BOOST_CHECK_EQUAL(tally.getMoney(1, PENDING), (-int64_t(9223372036854775807LL)-1)); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(1), -1); - - BOOST_CHECK(tally.updateMoney(1, int64_t(9223372036854775807LL), ACCEPT_RESERVE)); - BOOST_CHECK(tally.updateMoney(2, int64_t(9223372036854775807LL), SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(3, int64_t(9223372036854775807LL), SELLOFFER_RESERVE)); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(1), int64_t(9223372036854775807LL)); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(2), int64_t(9223372036854775807LL)); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(3), int64_t(9223372036854775807LL)); - - BOOST_CHECK(!tally.updateMoney(3, int64_t(9223372036854775807LL), SELLOFFER_RESERVE)); - BOOST_CHECK(!tally.updateMoney(3, (-int64_t(9223372036854775807LL)-1), SELLOFFER_RESERVE)); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(3), int64_t(9223372036854775807LL)); - - BOOST_CHECK(tally.updateMoney(1, -int64_t(9223372036854775807), ACCEPT_RESERVE)); - BOOST_CHECK(tally.updateMoney(1, 10000001, ACCEPT_RESERVE)); - BOOST_CHECK(tally.updateMoney(1, 20000001, SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(1, 30000001, SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(1, 40000001, SELLOFFER_RESERVE)); - BOOST_CHECK(tally.updateMoney(1, 50000001, METADEX_RESERVE)); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(1), 150000005); - - BOOST_CHECK(!tally.updateMoney(1, 1, BALANCE)); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(1), -1); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(2), 0); - BOOST_CHECK_EQUAL(tally.getMoneyAvailable(3), 0); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(1), 150000005); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(2), int64_t(9223372036854775807LL)); - BOOST_CHECK_EQUAL(tally.getMoneyReserved(3), int64_t(9223372036854775807LL)); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/test_clientexpiry.sh b/src/elysium/test/test_clientexpiry.sh deleted file mode 100755 index ef2c0e638d..0000000000 --- a/src/elysium/test/test_clientexpiry.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -SRCDIR=./src/ -NUL=/dev/null -PASS=0 -FAIL=0 -clear -printf "Preparing a test environment...\n" -printf " * Starting a fresh regtest daemon\n" -rm -r ~/.bitcoin/regtest -$SRCDIR/omnicored --regtest --server --daemon --omnialertallowsender=any >$NUL -sleep 10 -printf " * Preparing some mature testnet BTC\n" -$SRCDIR/omnicore-cli --regtest generate 102 >$NUL -printf " * Obtaining a master address to work with\n" -ADDR=$($SRCDIR/omnicore-cli --regtest getnewaddress OMNIAccount) -printf " * Funding the address with some testnet BTC for fees\n" -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 20 >$NUL -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " * Sending an alert with client expiry version of 999999999\n" -$SRCDIR/omnicore-cli --regtest omni_sendalert $ADDR 3 999999999 "Client version out of date test." >$NUL -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " * The client should now be shutting down, sleeping 5 seconds and then attempting to get block height - this should FAIL.\n" -sleep 5 -printf "\nWe should have shut down now, if we can still query the block height, something is wrong.\n" -BLOCKFINAL=$($SRCDIR/omnicore-cli --regtest getblockcount) -printf " * The current block height is %d\n" $BLOCKFINAL diff --git a/src/elysium/test/test_deactivation.sh b/src/elysium/test/test_deactivation.sh deleted file mode 100755 index e48ccedf22..0000000000 --- a/src/elysium/test/test_deactivation.sh +++ /dev/null @@ -1,310 +0,0 @@ -#!/bin/bash - -SRCDIR=./src/ -NUL=/dev/null -PASS=0 -FAIL=0 -clear -printf "Preparing a test environment...\n\n" -printf " * Starting a fresh regtest daemon\n" -rm -r ~/.bitcoin/regtest -$SRCDIR/omnicored --regtest --server --daemon --omniactivationallowsender=any >$NUL -sleep 10 -printf " * Preparing some mature testnet BTC\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 102 >$NUL -printf " * Obtaining a master address to work with\n" -ADDR=$($SRCDIR/omnicore-cli --regtest getnewaddress OMNIAccount) -printf " * Funding the address with some testnet BTC for fees\n" -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 20 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Participating in the Elysium crowdsale to obtain some OMNI\n" -JSON="{\"moneyqMan7uh8FqdCA2BV5yZ8qVrc9ikLP\":10,\""$ADDR"\":4}" -$SRCDIR/omnicore-cli --regtest sendmany OMNIAccount $JSON >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating test properties\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 1 0 "Z_TestCat" "Z_TestSubCat" "Z_IndivisTestProperty" "Z_TestURL" "Z_TestData" 10000000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 2 0 "Z_TestCat" "Z_TestSubCat" "Z_DivisTestProperty" "Z_TestURL" "Z_TestData" 10000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf "\nActivating the fee system & all pair trading, and testing they went live:\n\n" -printf " * Sending the all pair activation & checking it was valid... " -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendactivation $ADDR 8 $(($BLOCKS + 8)) 999) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending the fee system activation & checking it was valid... " -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXIDA=$($SRCDIR/omnicore-cli --regtest omni_sendactivation $ADDR 9 $(($BLOCKS + 8)) 999) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDA | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Mining 10 blocks to forward past the activation block\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 10 >$NUL -printf " * Sending a trade of #3 for #4 & checking it was valid... " -TXIDB=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 2000 4 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDB | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a matching trade of #4 for #3 & checking it was valid... " -TXIDC=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 4 1.0 3 2000) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDC | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Checking the fee cache now has 1 fee cached for property 3..." -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 3 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "1" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf "\nDeactivating the fee system & testing it's now disabled...\n\n" -printf " * Sending the deactivation & checking it was valid... " -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXIDD=$($SRCDIR/omnicore-cli --regtest omni_senddeactivation $ADDR 9) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDD | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a new trade of #3 for #4 & checking it was valid... " -TXIDE=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 2000 4 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDE | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending another matching trade of #4 for #3 & checking it was valid... " -TXIDF=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 4 1.0 3 2000) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDF | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Checking the fee cache did not increase and still has 1 fee cached for property 3..." -CACHEDFEEA=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 3 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEEA == "1" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEEA - FAIL=$((FAIL+1)) -fi -printf "\nDeactivating all pair trading & testing it's now disabled...\n\n" -printf " * Sending a new trade of #3 for #4 & checking it was valid... " -TXIDG=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 2000 4 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDG | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending the deactivation & checking it was valid... " -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXIDH=$($SRCDIR/omnicore-cli --regtest omni_senddeactivation $ADDR 8) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDH | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Making sure the orderbook for #3/#4 is now empty... " -ORDERS=$($SRCDIR/omnicore-cli --regtest omni_getorderbook 3 4 | grep -vF "[" | grep -vF "]" | wc -l) -if [ $ORDERS == "0" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $ORDERS - FAIL=$((FAIL+1)) -fi -printf " * Checking the first trade was refunded... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 3 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999999" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Sending a trade of #3 for #4 & checking it was invalid... " -TXIDI=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 2000 4 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDI | grep valid | cut -c15-) -if [ $RESULT == "false," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf "\nDeactivating the MetaDEx completely & testing it's now disabled...\n\n" -printf " * Sending a trade of #3 for #1 & checking it was valid... " -TXIDJ=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 2000 1 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDJ | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a trade of #4 for #1 & checking it was valid... " -TXIDK=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 4 2000 1 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDK | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending the deactivation & checking it was valid... " -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXIDL=$($SRCDIR/omnicore-cli --regtest omni_senddeactivation $ADDR 2) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDL | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Making sure the orderbook for #3/#1 is now empty... " -ORDERSB=$($SRCDIR/omnicore-cli --regtest omni_getorderbook 3 1 | grep -vF "[" | grep -vF "]" | wc -l) -if [ $ORDERSB == "0" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Making sure the orderbook for #4/#1 is now empty... " -ORDERSC=$($SRCDIR/omnicore-cli --regtest omni_getorderbook 4 1 | grep -vF "[" | grep -vF "]" | wc -l) -if [ $ORDERSC == "0" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Checking the trade for #3/#1 was refunded... " -BALANCEA=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 3 | grep balance | cut -d '"' -f4) -if [ $BALANCEA == "9999999" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCEA - FAIL=$((FAIL+1)) -fi -printf " * Checking the trade for #4/#1 was refunded... " -BALANCEB=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 4 | grep balance | cut -d '"' -f4) -if [ $BALANCEB == "10000.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCEB - FAIL=$((FAIL+1)) -fi -printf " * Sending a trade of #3 for #1 & checking it was invalid... " -TXIDM=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 2000 1 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDM | grep valid | cut -c15-) -if [ $RESULT == "false," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a trade of #1 for #4 & checking it was invalid... " -TXIDG=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 1 1.0 4 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXIDG | grep valid | cut -c15-) -if [ $RESULT == "false," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi - -printf "\n" -printf "####################\n" -printf "# Summary: #\n" -printf "# Passed = %d #\n" $PASS -printf "# Failed = %d #\n" $FAIL -printf "####################\n" -printf "\n" - -$SRCDIR/omnicore-cli --regtest stop - diff --git a/src/elysium/test/test_fees.sh b/src/elysium/test/test_fees.sh deleted file mode 100755 index 258953fffa..0000000000 --- a/src/elysium/test/test_fees.sh +++ /dev/null @@ -1,890 +0,0 @@ -#!/bin/bash - -################################################################################################ -## PLEASE DISABLE DEV OMNI FOR THESE TESTS!!! ## -## ## -## The fee distribution tests require an exact amount of Omni in each address. Dev Omni will ## -## skew these tests by increasing the amount of Omni in the Elysium Address. ## -## To use this script in regtest mode, temporarily disable Dev Omni and recompile by adding: ## -## return 0; ## -## as the first line of the function calculate_and_update_devmsc in omnicore.cpp. This line ## -## must be removed and Omni Core recompiled to use on mainnet. ## -################################################################################################ - -SRCDIR=./src/ -NUL=/dev/null -PASS=0 -FAIL=0 -clear -printf "Preparing a test environment...\n" -printf " * Starting a fresh regtest daemon\n" -rm -r ~/.bitcoin/regtest -$SRCDIR/omnicored --regtest --server --daemon --omniactivationallowsender=any >$NUL -sleep 3 -printf " * Preparing some mature testnet BTC\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 102 >$NUL -printf " * Obtaining a master address to work with\n" -ADDR=$($SRCDIR/omnicore-cli --regtest getnewaddress OMNIAccount) -printf " * Funding the address with some testnet BTC for fees\n" -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 20 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Participating in the Elysium crowdsale to obtain some OMNI\n" -JSON="{\"moneyqMan7uh8FqdCA2BV5yZ8qVrc9ikLP\":10,\""$ADDR"\":4}" -$SRCDIR/omnicore-cli --regtest sendmany OMNIAccount $JSON >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating an indivisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 1 0 "Z_TestCat" "Z_TestSubCat" "Z_IndivisTestProperty" "Z_TestURL" "Z_TestData" 10000000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating a second indivisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 1 0 "Z_TestCat" "Z_TestSubCat" "Z_IndivisTestProperty" "Z_TestURL" "Z_TestData" 10000000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating a divisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 2 0 "Z_TestCat" "Z_TestSubCat" "Z_DivisTestProperty" "Z_TestURL" "Z_TestData" 10000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating a second divisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 2 0 "Z_TestCat" "Z_TestSubCat" "Z_DivisTestProperty" "Z_TestURL" "Z_TestData" 10000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating an indivisible test property in the test ecosystem\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 2 1 0 "Z_TestCat" "Z_TestSubCat" "Z_IndivisTestProperty" "Z_TestURL" "Z_TestData" 10000000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating a divisible test property in the test ecosystem\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 2 2 0 "Z_TestCat" "Z_TestSubCat" "Z_DivisTestProperty" "Z_TestURL" "Z_TestData" 10000000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Generating addresses to use as fee recipients (OMNI holders)\n" -ADDRESS=() -for i in {1..6} -do - ADDRESS=("${ADDRESS[@]}" $($SRCDIR/omnicore-cli --regtest getnewaddress)) -done -printf " * Using a total of 1000 OMNI\n" -printf " * Seeding %s with 50.00 OMNI\n" ${ADDRESS[1]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[1]} 1 50.0 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Seeding %s with 100.00 OMNI\n" ${ADDRESS[2]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[2]} 1 100.0 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Seeding %s with 150.00 OMNI\n" ${ADDRESS[3]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[3]} 1 150.0 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Seeding %s with 200.00 OMNI\n" ${ADDRESS[4]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[4]} 1 200.0 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf "\nActivating the fee system...\n" -printf " * Sending the activation\n" -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendactivation $ADDR 9 $(($BLOCKS + 8)) 999) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " # Checking the activation transaction was valid... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Mining 10 blocks to forward past the activation block\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 10 >$NUL -printf " # Checking the activation went live as expected... " -FEATUREID=$($SRCDIR/omnicore-cli --regtest omni_getactivations | grep -A 10 completed | grep featureid | cut -c27) -if [ $FEATUREID == "9" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $FEATUREID - FAIL=$((FAIL+1)) -fi -printf "\nChecking share of fees for recipients...\n" -printf " * Checking %s has a 5 percent share of fees... " ${ADDRESS[1]} -FEESHARE=$($SRCDIR/omnicore-cli --regtest omni_getfeeshare ${ADDRESS[1]} | grep feeshare | cut -d '"' -f4) -if [ $FEESHARE == "5.0000%" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $FEESHARE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s has a 10 percent share of fees... " ${ADDRESS[2]} -FEESHARE=$($SRCDIR/omnicore-cli --regtest omni_getfeeshare ${ADDRESS[2]} | grep feeshare | cut -d '"' -f4) -if [ $FEESHARE == "10.0000%" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $FEESHARE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s has a 15 percent share of fees... " ${ADDRESS[3]} -FEESHARE=$($SRCDIR/omnicore-cli --regtest omni_getfeeshare ${ADDRESS[3]} | grep feeshare | cut -d '"' -f4) -if [ $FEESHARE == "15.0000%" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $FEESHARE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s has a 20 percent share of fees... " ${ADDRESS[4]} -FEESHARE=$($SRCDIR/omnicore-cli --regtest omni_getfeeshare ${ADDRESS[4]} | grep feeshare | cut -d '"' -f4) -if [ $FEESHARE == "20.0000%" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $FEESHARE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s has a 50 percent share of fees... " $ADDR -FEESHARE=$($SRCDIR/omnicore-cli --regtest omni_getfeeshare $ADDR | grep feeshare | cut -d '"' -f4) -if [ $FEESHARE == "50.0000%" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $FEESHARE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s has a 100 percent share of fees in the test ecosystem... " $ADDR -FEESHARE=$($SRCDIR/omnicore-cli --regtest omni_getfeeshare $ADDR 2 | grep feeshare | cut -d '"' -f4) -if [ $FEESHARE == "100.0000%" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $FEESHARE - FAIL=$((FAIL+1)) -fi -printf "\nTesting a trade against self where the first token is OMNI\n" -printf " * Executing the trade\n" -TXIDA=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 2000 1 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -TXIDB=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 1 1.0 3 2000) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking no fee was taken...\n" -printf " * Checking the original trade matches to confirm trading fee was 0... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDA | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -printf " * Checking the new trade matches to confirm trading fee was 0... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDB | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "0" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 1 | grep cachedfee | cut -d '"' -f4) -printf " * Checking the fee cache is empty for property 1... " -if [ $CACHEDFEE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " * Checking the fee cache is empty for property 3... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 3 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " * Checking the trading address didn't lose any #1 tokens after trade... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 1 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "500.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Checking the trading address didn't lose any #3 tokens after trade... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 3 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "10000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf "\nActivating all pair trading...\n" -printf " * Sending the activation\n" -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendactivation $ADDR 8 $(($BLOCKS + 8)) 999) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " # Checking the activation transaction was valid... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Mining 10 blocks to forward past the activation block\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 10 >$NUL -printf "\nTesting a trade against self that results in a 1 willet fee for property 3 (1.0 #5 for 2000 #3)\n" -printf " * Executing the trade\n" -TXIDA=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 2000 5 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -TXIDB=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 1.0 3 2000) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the original trade matches to confirm trading fee was 0... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDA | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the new trade matches to confirm trading fee was 1... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDB | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "1" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the fee cache now has 1 fee cached for property 3... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 3 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "1" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the trading address now owns 9999999 of property 3... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 3 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999999" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi - -printf "\nTesting another trade against self that results in a 5 willet fee for property 3 (1.0 #5 for 10000 #3)\n" -printf " * Executing the trade\n" -TXIDA=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 10000 5 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -TXIDB=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 1.0 3 10000) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the original trade matches to confirm trading fee was 0... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDA | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the new trade matches to confirm trading fee was 5... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDB | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "5" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the fee cache now has 6 fee cached for property 3... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 3 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "6" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the trading address now owns 9999994 instead of property 3... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 3 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999994" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf "\nTesting a trade against self that results in a 1 willet fee for property 6 (1.0 #5 for 0.00002 #6)\n" -printf " * Executing the trade\n" -TXIDA=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 6 0.00002000 5 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -TXIDB=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 1.0 6 0.00002000) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the original trade matches to confirm trading fee was 0... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDA | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the new trade matches to confirm trading fee was 0.00000001... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDB | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "0.00000001" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the fee cache now has 0.00000001 fee cached for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00000001" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the trading address now owns 9999.99999999 of property 6... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999.99999999" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf "\nTesting a trade against self that results in a 5000 willet fee for property 6 (1.0 #5 for 0.1 #6)\n" -printf " * Executing the trade\n" -TXIDA=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 6 0.1 5 1.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -TXIDB=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 1.0 6 0.1) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the original trade matches to confirm trading fee was 0... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDA | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the new trade matches to confirm trading fee was 0.00005000... " -TRADEFEE=$($SRCDIR/omnicore-cli --regtest omni_gettrade $TXIDB | grep tradingfee | cut -d '"' -f4) -if [ $TRADEFEE == "0.00005000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $TRADEFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the fee cache now has 0.00005001 fee cached for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00005001" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the trading address now owns 9999.99994999 of property 6... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999.99994999" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf "\nIncreasing volume to get close to 10000000 fee trigger point for property 6\n" -printf " * Executing the trades\n" -for i in {1..5} -do - $SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 6 39.96 5 1.0 >$NUL - $SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL - $SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 1.0 6 39.96 >$NUL - $SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -done -printf " * Verifiying the results\n" -printf " # Checking the fee cache now has 0.09995001 fee cached for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.09995001" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the trading address now owns 9999.90004999 of property 6... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999.90004999" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf "\nPerforming a small trade to take fee cache to 0.1 and trigger distribution for property 6\n" -printf " * Executing the trade\n" -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 6 0.09999999 5 0.8 >$NUL -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 0.8 6 0.09999999 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking distribution was triggered and the fee cache is now empty for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 0.00500000 fee share... " ${ADDRESS[1]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[1]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.00500000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 0.01000000 fee share... " ${ADDRESS[2]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[2]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.01000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 0.01500000 fee share... " ${ADDRESS[3]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[3]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.01500000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 0.02000000 fee share... " ${ADDRESS[4]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[4]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.02000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 0.05000000 fee share... " $ADDR -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999.95000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf "\nRolling back the chain to test ability to roll back a distribution during reorg (disconnecting 1 block from tip and mining a replacement)\n" -printf " * Executing the rollback\n" -BLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -BLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -$SRCDIR/omnicore-cli --regtest invalidateblock $BLOCKHASH >$NUL -PREVBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -printf " * Clearing the mempool\n" -$SRCDIR/omnicore-cli --regtest clearmempool >$NUL -printf " * Verifiying the results\n" -printf " # Checking the block count has been reduced by 1... " -EXPBLOCK=$((BLOCK-1)) -if [ $EXPBLOCK == $PREVBLOCK ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $PREVBLOCK - FAIL=$((FAIL+1)) -fi -printf " * Mining a replacement block\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -NEWBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -NEWBLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -printf " # Checking the block count is the same as before the rollback... " -if [ $BLOCK == $NEWBLOCK ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $NEWBLOCK - FAIL=$((FAIL+1)) -fi -printf " # Checking the block hash is different from before the rollback... " -if [ $BLOCKHASH == $NEWBLOCKHASH ] - then - printf "FAIL (result:%s)\n" $NEWBLOCKHASH - FAIL=$((FAIL+1)) - else - printf "PASS\n" - PASS=$((PASS+1)) -fi -printf " # Checking the fee cache now again has 0.09995001 fee cached for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.09995001" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s balance has been rolled back to 0... " ${ADDRESS[1]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[1]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s balance has been rolled back to 0... " ${ADDRESS[2]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[2]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s balance has been rolled back to 0... " ${ADDRESS[3]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[3]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s balance has been rolled back to 0... " ${ADDRESS[4]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[4]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s balance has been rolled back to 9999.90004999... " $ADDR -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999.90004999" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Performing a small trade to take fee cache to 0.1 and retrigger distribution for property 6\n" -printf " # Executing the trade\n" -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 6 0.09999999 5 0.8 >$NUL -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 0.8 6 0.09999999 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " # Verifiying the results\n" -printf " * Checking distribution was triggered again and the fee cache is now empty for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s received 0.00500000 fee share... " ${ADDRESS[1]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[1]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.00500000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s received 0.01000000 fee share... " ${ADDRESS[2]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[2]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.01000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s received 0.01500000 fee share... " ${ADDRESS[3]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[3]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.01500000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s received 0.02000000 fee share... " ${ADDRESS[4]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[4]} 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "0.02000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Checking %s received 0.05000000 fee share... " $ADDR -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 6 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999.95000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf "\nRolling back the chain to test ability to roll back a fee cache change during reorg\n" -printf " # Testing a trade against self that results in a 1 willet fee for property 6 (1.0 #6 for 0.00002 #5)\n" -printf " * Executing the trade\n" -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 6 0.00002000 5 1.0 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 1.0 6 0.00002000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the fee cache now has 0.00000001 fee cached for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00000001" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Testing another trade against self that results in a 1 willet fee for property 6 (1.0 #6 for 0.00002 #5)\n" -printf " * Executing the trade\n" -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 6 0.00002000 5 1.0 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 1.0 6 0.00002000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the fee cache now has 0.00000002 fee cached for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00000002" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Rolling back the chain to orphan a block (disconnecting 1 block from tip and mining a replacement)\n" -printf " * Executing the rollback\n" -BLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -BLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -$SRCDIR/omnicore-cli --regtest invalidateblock $BLOCKHASH >$NUL -PREVBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -printf " * Clearing the mempool\n" -$SRCDIR/omnicore-cli --regtest clearmempool >$NUL -printf " * Verifiying the results\n" -printf " # Checking the block count has been reduced by 1... " -EXPBLOCK=$((BLOCK-1)) -if [ $EXPBLOCK == $PREVBLOCK ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $PREVBLOCK - FAIL=$((FAIL+1)) -fi -printf " * Mining a replacement block\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -NEWBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -NEWBLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -printf " # Checking the block count is the same as before the rollback... " -if [ $BLOCK == $NEWBLOCK ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $NEWBLOCK - FAIL=$((FAIL+1)) -fi -printf " # Checking the block hash is different from before the rollback... " -if [ $BLOCKHASH == $NEWBLOCKHASH ] - then - printf "FAIL (result:%s)\n" $NEWBLOCKHASH - FAIL=$((FAIL+1)) - else - printf "PASS\n" - PASS=$((PASS+1)) -fi -printf " # Checking the fee cache has been rolled back to 0.00000001 for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00000001" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf "\nMining 51 blocks to test that fee cache is not affected by fee pruning\n" -printf " * Verifiying the results\n" -printf " # Checking the fee cache is 0.00000001 for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00000001" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " * Mining the blocks...\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 51 >$NUL -printf " # Checking the fee cache is still 0.00000001 for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00000001" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " * Executing a trade to generate 1 willet fee\n" -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 6 0.00002000 5 1.0 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 1.0 6 0.00002000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " # Checking the fee cache now has 0.00000002 fee cached for property 6... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 6 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00000002" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf "\nAdding some test ecosystem volume to trigger distribution\n" -printf " * Executing the trades\n" -for i in {1..9} -do - $SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 2147483651 20000 2147483652 10.0 >$NUL - $SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL - $SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 2147483652 10.0 2147483651 20000 >$NUL - $SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -done -printf " * Verifiying the results\n" -printf " # Checking the fee cache now has 90 fee cached for property 2147483651... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 2147483651 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "90" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking the trading address now owns 9999910 of property 2147483651... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 2147483651 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "9999910" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf "\nTriggering distribution in the test ecosystem for property 2147483651\n" -printf " * Executing the trade\n" -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 2147483651 20000 2147483652 10.0 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -$SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 2147483652 10.0 2147483651 20000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking distribution was triggered and the fee cache is now empty for property 2147483651... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 2147483651 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 100 fee share... " $ADDR -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $ADDR 2147483651 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "10000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf "\n" -printf "####################\n" -printf "# Summary: #\n" -printf "# Passed = %d #\n" $PASS -printf "# Failed = %d #\n" $FAIL -printf "####################\n" -printf "\n" - -$SRCDIR/omnicore-cli --regtest stop - diff --git a/src/elysium/test/test_freeze.sh b/src/elysium/test/test_freeze.sh deleted file mode 100755 index 76df78d936..0000000000 --- a/src/elysium/test/test_freeze.sh +++ /dev/null @@ -1,622 +0,0 @@ -#!/bin/bash - -SRCDIR=./src/ -NUL=/dev/null -PASS=0 -FAIL=0 -clear -printf "Preparing a test environment...\n" -printf " * Starting a fresh regtest daemon\n" -rm -r ~/.bitcoin/regtest -$SRCDIR/omnicored --regtest --server --daemon --omniactivationallowsender=any --omnidebug=verbose >$NUL -sleep 10 -printf " * Preparing some mature testnet BTC\n" -$SRCDIR/omnicore-cli --regtest generate 105 >$NUL -printf " * Obtaining addresses to work with\n" -ADDR=$($SRCDIR/omnicore-cli --regtest getnewaddress OMNIAccount) -FADDR=$($SRCDIR/omnicore-cli --regtest getnewaddress) -printf " * Master address is %s\n" $ADDR -printf " * Funding the addresses with some testnet BTC for fees\n" -JSON="{\""$ADDR"\":5,\""$FADDR"\":4}" -$SRCDIR/omnicore-cli --regtest sendmany "" $JSON >$NUL -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 6 >$NUL -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 7 >$NUL -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 8 >$NUL -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 9 >$NUL -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " * Creating a test (managed) property and granting 1000 tokens to the test address\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancemanaged $ADDR 1 1 0 "TestCat" "TestSubCat" "TestProperty" "TestURL" "TestData" >$NUL -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -$SRCDIR/omnicore-cli --regtest omni_sendgrant $ADDR $FADDR 3 1000 >$NUL -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf "\nRunning the test scenario...\n" -printf " * Sending a 'freeze' tranasction for the test address prior to enabling freezing\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'freeze' transaction was INVALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking that freezing is currently disabled... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a 'enable freezing' transaction to ENABLE freezing\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendenablefreezing $ADDR 3) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'enable freezing' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking that freezing is now enabled... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending another 'freeze' tranasction for the test address\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'freeze' transaction was now VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Testing a send from the test address (should now be frozen)\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_send $FADDR $ADDR 3 50) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'send' transaction was INVALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking the test address balance has not changed... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $FADDR 3 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "1000" ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Sending an 'unfreeze' tranasction for the test address\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendunfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'unfreeze' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Testing a send from the test address (should now be unfrozen)\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_send $FADDR $ADDR 3 50) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'send' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking the test address balance has reduced by the amount of the send... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $FADDR 3 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "950" ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Sending another 'freeze' tranasction for the test address\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'freeze' transaction was now VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a 'disable freezing' transaction to DISABLE freezing\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_senddisablefreezing $ADDR 3) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'disable freezing' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking that freezing is now disabled... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Testing a send from the test address (unfrozen when freezing was disabled)\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_send $FADDR $ADDR 3 30) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'send' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking the test address balance has reduced by the amount of the send... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $FADDR 3 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "920" ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Sending a 'freeze' tranasction for the test address to test that freezing is now disabled\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'freeze' transaction was INVALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a feature 14 activation to activate the notice period\n" -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendactivation $ADDR 14 $(($BLOCKS + 8)) 999) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the activation transaction was valid... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Mining 10 blocks to forward past the activation block\n" -$SRCDIR/omnicore-cli --regtest generate 10 >$NUL -printf " - Checking the activation went live as expected... " -FEATUREID=$($SRCDIR/omnicore-cli --regtest omni_getactivations | grep -A 10 completed | grep featureid | cut -c20-21) -if [ $FEATUREID == "14" ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $FEATUREID - FAIL=$((FAIL+1)) -fi -printf " * Sending a 'enable freezing' transaction to ENABLE freezing\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendenablefreezing $ADDR 3) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'enable freezing' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking that freezing is still disabled (due to wait period)... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a 'freeze' tranasction for the test address before waiting period expiry\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'freeze' transaction was INVALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Mining 30 blocks to forward past the waiting period\n" -$SRCDIR/omnicore-cli --regtest generate 10 >$NUL -printf " - Checking that freezing is now enabled... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a 'freeze' tranasction for the test address after waiting period expiry\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'freeze' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Testing a Send All from the test address (now frozen))\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendall $FADDR $ADDR 1) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'Send All' transaction was INVALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking the test address balance has not changed... " -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance $FADDR 3 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "920" ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " * Sending an 'unfreeze' tranasction for the test address\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendunfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'unfreeze' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf "\nRunning reorg test scenarios\n" -printf " * Rolling back the chain to test reversing the last UNFREEZE tx\n" -BLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -BLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -$SRCDIR/omnicore-cli --regtest invalidateblock $BLOCKHASH >$NUL -PREVBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -$SRCDIR/omnicore-cli --regtest clearmempool >$NUL -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -NEWBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -NEWBLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -printf " - Checking the block count is the same as before the rollback... " -if [ $BLOCK == $NEWBLOCK ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $NEWBLOCK - FAIL=$((FAIL+1)) -fi -printf " - Checking the block hash is different from before the rollback... " -if [ $BLOCKHASH == $NEWBLOCKHASH ] - then - printf "FAIL (result:%s)\n" $NEWBLOCKHASH - FAIL=$((FAIL+1)) - else - printf "PASS\n" - PASS=$((PASS+1)) -fi -printf " * Testing a send from the test address (should now be frozen again as the block that unfroze the address was dc'd)\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_send $FADDR $ADDR 3 30) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'send' transaction was INVALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending an 'unfreeze' tranasction for the test address\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendunfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'unfreeze' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -$SRCDIR/omnicore-cli --regtest generate 3 >$NUL -printf " * Sending an 'freeze' tranasction for the test address\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'freeze' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Rolling back the chain to test reversing the last FREEZE tx\n" -BLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -BLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -$SRCDIR/omnicore-cli --regtest invalidateblock $BLOCKHASH >$NUL -PREVBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -$SRCDIR/omnicore-cli --regtest clearmempool >$NUL -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -NEWBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -NEWBLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -printf " - Checking the block count is the same as before the rollback... " -if [ $BLOCK == $NEWBLOCK ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $NEWBLOCK - FAIL=$((FAIL+1)) -fi -printf " - Checking the block hash is different from before the rollback... " -if [ $BLOCKHASH == $NEWBLOCKHASH ] - then - printf "FAIL (result:%s)\n" $NEWBLOCKHASH - FAIL=$((FAIL+1)) - else - printf "PASS\n" - PASS=$((PASS+1)) -fi -printf " * Testing a send from the test address (should now be unfrozen again as the block that froze the address was dc'd)\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_send $FADDR $ADDR 3 30) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'send' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a 'freeze' tranasction for the test address\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendfreeze $ADDR $FADDR 3 1234) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'freeze' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a 'disable freezing' transaction to DISABLE freezing\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_senddisablefreezing $ADDR 3) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'disable freezing' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking that freezing is now disabled... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Rolling back the chain to test reversing the last DISABLE FREEZEING tx\n" -BLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -BLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -$SRCDIR/omnicore-cli --regtest invalidateblock $BLOCKHASH >$NUL -PREVBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -$SRCDIR/omnicore-cli --regtest clearmempool >$NUL -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -NEWBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -NEWBLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -printf " - Checking the block count is the same as before the rollback... " -if [ $BLOCK == $NEWBLOCK ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $NEWBLOCK - FAIL=$((FAIL+1)) -fi -printf " - Checking the block hash is different from before the rollback... " -if [ $BLOCKHASH == $NEWBLOCKHASH ] - then - printf "FAIL (result:%s)\n" $NEWBLOCKHASH - FAIL=$((FAIL+1)) - else - printf "PASS\n" - PASS=$((PASS+1)) -fi -printf " - Checking that freezing is now enabled (as the block that disabled it was dc'd)... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Sending a 'disable freezing' transaction to DISABLE freezing\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_senddisablefreezing $ADDR 3) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'disable freezing' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking that freezing is now disabled... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -$SRCDIR/omnicore-cli --regtest generate 3 >$NUL -printf " * Sending a 'enable freezing' transaction to ENABLE freezing\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendenablefreezing $ADDR 3) -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -printf " - Checking the 'enable freezing' transaction was VALID... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep "valid" | grep -v "invalid" | cut -c12-) -if [ $RESULT == "true," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " - Checking that freezing is still disabled (due to waiting period)... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "false," ] - then - printf " PASS\n" - PASS=$((PASS+1)) - else - printf " FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Rolling back the chain to test reversing the last ENABLE FREEZEING tx\n" -BLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -BLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -$SRCDIR/omnicore-cli --regtest invalidateblock $BLOCKHASH >$NUL -PREVBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -$SRCDIR/omnicore-cli --regtest clearmempool >$NUL -$SRCDIR/omnicore-cli --regtest generate 1 >$NUL -NEWBLOCK=$($SRCDIR/omnicore-cli --regtest getblockcount) -NEWBLOCKHASH=$($SRCDIR/omnicore-cli --regtest getblockhash $(($BLOCK))) -printf " - Checking the block count is the same as before the rollback... " -if [ $BLOCK == $NEWBLOCK ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $NEWBLOCK - FAIL=$((FAIL+1)) -fi -printf " - Checking the block hash is different from before the rollback... " -if [ $BLOCKHASH == $NEWBLOCKHASH ] - then - printf "FAIL (result:%s)\n" $NEWBLOCKHASH - FAIL=$((FAIL+1)) - else - printf "PASS\n" - PASS=$((PASS+1)) -fi -printf " - Mining past prior activation period and checking that freezing is still disabled... " -$SRCDIR/omnicore-cli --regtest generate 20 >$NUL -RESULT=$($SRCDIR/omnicore-cli --regtest omni_getproperty 3 | grep "freezingenabled" | cut -c21-) -if [ $RESULT == "false," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi - -printf "\n" -printf "####################\n" -printf "# Summary: #\n" -printf "# Passed = %d #\n" $PASS -printf "# Failed = %d #\n" $FAIL -printf "####################\n" -printf "\n" -$SRCDIR/omnicore-cli --regtest stop - - diff --git a/src/elysium/test/test_metadexphase3.sh b/src/elysium/test/test_metadexphase3.sh deleted file mode 100755 index 7e04d6a11f..0000000000 --- a/src/elysium/test/test_metadexphase3.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash - -SRCDIR=./src/ -NUL=/dev/null -PASS=0 -FAIL=0 -clear -printf "Preparing a test environment...\n" -printf " * Starting a fresh regtest daemon with open activation sender\n" -rm -r ~/.bitcoin/regtest -$SRCDIR/omnicored --regtest --server --daemon --omniactivationallowsender=any >$NUL -sleep 3 -printf " * Preparing some mature testnet BTC\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 102 >$NUL -printf " * Obtaining a master address to work with\n" -ADDR=$($SRCDIR/omnicore-cli --regtest getnewaddress OMNIAccount) -printf " * Funding the address with some testnet BTC for fees\n" -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 20 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Participating in the Elysium crowdsale to obtain some OMNI\n" -JSON="{\"moneyqMan7uh8FqdCA2BV5yZ8qVrc9ikLP\":10,\""$ADDR"\":4}" -$SRCDIR/omnicore-cli --regtest sendmany OMNIAccount $JSON >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating an indivisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 1 0 "Z_TestCat" "Z_TestSubCat" "Z_IndivisTestProperty" "Z_TestURL" "Z_TestData" 10000000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating a divisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 2 0 "Z_TestCat" "Z_TestSubCat" "Z_DivisTestProperty" "Z_TestURL" "Z_TestData" 10000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf "\nTesting a trade against self that uses Omni (1.1 OMNI for 20 #3)\n" -printf " * Executing the trade\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 20 1 1.1) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the trade was valid..." -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf "\nTesting a trade against self that doesn't use Omni to confirm non-Omni pairs are disabled (4.45 #4 for 20 #3)\n" -printf " * Executing the trade\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 20 4 4.45) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the trade was invalid..." -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "false," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf "\nActivating trading on all pairs\n" -printf " * Sending the activation\n" -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendactivation $ADDR 8 $(($BLOCKS + 8)) 999) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " # Checking the activation transaction was valid..." -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Mining 10 blocks to forward past the activation block\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 10 >$NUL -printf " # Checking the activation went live as expected..." -FEATUREID=$($SRCDIR/omnicore-cli --regtest omni_getactivations | grep -A 10 completed | grep featureid | cut -c27) -if [ $FEATUREID == "8" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $FEATUREID - FAIL=$((FAIL+1)) -fi -printf "\nTesting a trade against self that doesn't use Omni to confirm non-Omni pairs are now enabled (4.45 #4 for 20 #3)\n" -printf " * Executing the trade\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 20 4 4.45) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the trade was valid..." -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi - -printf "\n" -printf "####################\n" -printf "# Summary: #\n" -printf "# Passed = %d #\n" $PASS -printf "# Failed = %d #\n" $FAIL -printf "####################\n" -printf "\n" - -$SRCDIR/omnicore-cli --regtest stop - diff --git a/src/elysium/test/test_metadexprices.sh b/src/elysium/test/test_metadexprices.sh deleted file mode 100755 index 37cf4f51b6..0000000000 --- a/src/elysium/test/test_metadexprices.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/bash - -SRCDIR=./src/ -NUL=/dev/null -PASS=0 -FAIL=0 -clear -printf "Preparing a test environment...\n" -printf " * Starting a fresh regtest daemon\n" -rm -r ~/.bitcoin/regtest -$SRCDIR/omnicored --regtest --server --daemon >$NUL -sleep 3 -printf " * Preparing some mature testnet BTC\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 102 >$NUL -printf " * Obtaining a master address to work with\n" -ADDR=$($SRCDIR/omnicore-cli --regtest getnewaddress OMNIAccount) -printf " * Funding the address with some testnet BTC for fees\n" -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 20 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Participating in the Elysium crowdsale to obtain some OMNI\n" -JSON="{\"moneyqMan7uh8FqdCA2BV5yZ8qVrc9ikLP\":10,\""$ADDR"\":4}" -$SRCDIR/omnicore-cli --regtest sendmany OMNIAccount $JSON >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating an indivisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 1 0 "Z_TestCat" "Z_TestSubCat" "Z_IndivisTestProperty" "Z_TestURL" "Z_TestData" 10000000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating a divisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 2 0 "Z_TestCat" "Z_TestSubCat" "Z_DivisTestProperty" "Z_TestURL" "Z_TestData" 10000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating another indivisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 1 0 "Z_TestCat" "Z_TestSubCat" "Z_IndivisTestProperty" "Z_TestURL" "Z_TestData" 10000000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf "\nTesting a trade against self that uses divisible / divisible (10.0 OMNI for 100.0 #4)\n" -printf " * Executing the trade\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 1 10.0 4 100.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the unit price was 10.0..." -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep unitprice | cut -d '"' -f4) -if [ $RESULT == "10.00000000000000000000000000000000000000000000000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf "\nTesting a trade against self that uses divisible / indivisible (10.0 OMNI for 100 #3)\n" -printf " * Executing the trade\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 1 10.0 3 100) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the unit price was 10.0..." -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep unitprice | cut -d '"' -f4) -if [ $RESULT == "10.00000000000000000000000000000000000000000000000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf "\nTesting a trade against self that uses indivisible / divisible (10 #3 for 100.0 OMNI)\n" -printf " * Executing the trade\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 3 10 1 100.0) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the unit price was 10.0..." -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep unitprice | cut -d '"' -f4) -if [ $RESULT == "10.00000000000000000000000000000000000000000000000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf "\nTesting a trade against self that uses indivisible / indivisible (10 #5 for 100 #3)\n" -printf " * Executing the trade\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendtrade $ADDR 5 10 3 100) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the unit price was 10.0..." -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep unitprice | cut -d '"' -f4) -if [ $RESULT == "10.00000000000000000000000000000000000000000000000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi - -printf "\n" -printf "####################\n" -printf "# Summary: #\n" -printf "# Passed = %d #\n" $PASS -printf "# Failed = %d #\n" $FAIL -printf "####################\n" -printf "\n" - -$SRCDIR/omnicore-cli --regtest stop - diff --git a/src/elysium/test/test_stov1.sh b/src/elysium/test/test_stov1.sh deleted file mode 100755 index f05719a77e..0000000000 --- a/src/elysium/test/test_stov1.sh +++ /dev/null @@ -1,192 +0,0 @@ -#!/bin/bash - -SRCDIR=./src/ -NUL=/dev/null -PASS=0 -FAIL=0 -clear -printf "Preparing a test environment...\n" -printf " * Starting a fresh regtest daemon\n" -rm -r ~/.bitcoin/regtest -$SRCDIR/omnicored --regtest --server --daemon --omniactivationallowsender=any >$NUL -sleep 10 -printf " * Preparing some mature testnet BTC\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 102 >$NUL -printf " * Obtaining a master address to work with\n" -ADDR=$($SRCDIR/omnicore-cli --regtest getnewaddress OMNIAccount) -printf " * Funding the address with some testnet BTC for fees\n" -$SRCDIR/omnicore-cli --regtest sendtoaddress $ADDR 20 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Participating in the Elysium crowdsale to obtain some OMNI\n" -JSON="{\"moneyqMan7uh8FqdCA2BV5yZ8qVrc9ikLP\":10,\""$ADDR"\":4}" -$SRCDIR/omnicore-cli --regtest sendmany OMNIAccount $JSON >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating an indivisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 1 0 "Z_TestCat" "Z_TestSubCat" "Z_IndivisTestProperty" "Z_TestURL" "Z_TestData" 100 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Creating a divisible test property\n" -$SRCDIR/omnicore-cli --regtest omni_sendissuancefixed $ADDR 1 2 0 "Z_TestCat" "Z_TestSubCat" "Z_DivisTestProperty" "Z_TestURL" "Z_TestData" 10000 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Generating addresses to use as STO recipients\n" -ADDRESS=() -for i in {1..11} -do - ADDRESS=("${ADDRESS[@]}" $($SRCDIR/omnicore-cli --regtest getnewaddress)) -done -printf " * Seeding a total of 100 SP#3\n" -printf " * Seeding %s with 5%% = 5 SP#3\n" ${ADDRESS[1]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[1]} 3 5 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Seeding %s with 10%% = 10 SP#3\n" ${ADDRESS[2]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[2]} 3 10 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Seeding %s with 15%% = 15 SP#3\n" ${ADDRESS[3]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[3]} 3 15 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Seeding %s with 20%% = 20 SP#3\n" ${ADDRESS[4]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[4]} 3 20 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Seeding %s with 25%% = 25 SP#3\n" ${ADDRESS[5]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[5]} 3 25 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Seeding %s with 25%% = 25 SP#3\n" ${ADDRESS[6]} -$SRCDIR/omnicore-cli --regtest omni_send $ADDR ${ADDRESS[6]} 3 25 >$NUL -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf "\nTesting a cross property (v1) STO, distributing 1000.00 SPT #4 to holders of SPT #3\n" -printf " * Executing the transaction\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendsto $ADDR 4 1000 "" 3) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the STO transaction was invalid (feature not yet activated)... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "false," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf "\nActivating cross property (v1) Send To Owners...\n" -printf " * Sending the activation\n" -BLOCKS=$($SRCDIR/omnicore-cli --regtest getblockcount) -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendactivation $ADDR 10 $(($BLOCKS + 8)) 999) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " # Checking the activation transaction was valid... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " * Mining 10 blocks to forward past the activation block\n" -$SRCDIR/omnicore-cli --regtest setgenerate true 10 >$NUL -printf " # Checking the activation went live as expected... " -FEATUREID=$($SRCDIR/omnicore-cli --regtest omni_getactivations | grep -A 10 completed | grep featureid | cut -c27-28) -if [ $FEATUREID == "10" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $FEATUREID - FAIL=$((FAIL+1)) -fi -printf "\nTesting a cross property (v1) STO, distributing 1000.00 SPT #4 to holders of SPT #3\n" -printf " * Executing the transaction\n" -TXID=$($SRCDIR/omnicore-cli --regtest omni_sendsto $ADDR 4 1000 "" 3) -$SRCDIR/omnicore-cli --regtest setgenerate true 1 >$NUL -printf " * Verifiying the results\n" -printf " # Checking the STO transaction was valid... " -RESULT=$($SRCDIR/omnicore-cli --regtest omni_gettransaction $TXID | grep valid | cut -c15-) -if [ $RESULT == "true," ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $RESULT - FAIL=$((FAIL+1)) -fi -printf " # Checking the fee cache now has 0.00006000 fee cached for OMNI... " -CACHEDFEE=$($SRCDIR/omnicore-cli --regtest omni_getfeecache 1 | grep cachedfee | cut -d '"' -f4) -if [ $CACHEDFEE == "0.00006000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $CACHEDFEE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 5%% of the distribution (50.00 SPT #4)... " ${ADDRESS[1]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[1]} 4 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "50.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 10%% of the distribution (100.00 SPT #4)... " ${ADDRESS[2]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[2]} 4 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "100.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 15%% of the distribution (150.00 SPT #4)... " ${ADDRESS[3]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[3]} 4 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "150.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 20%% of the distribution (200.00 SPT #4)... " ${ADDRESS[4]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[4]} 4 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "200.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 25%% of the distribution (250.00 SPT #4)... " ${ADDRESS[5]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[5]} 4 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "250.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi -printf " # Checking %s received 25%% of the distribution (250.00 SPT #4)... " ${ADDRESS[6]} -BALANCE=$($SRCDIR/omnicore-cli --regtest omni_getbalance ${ADDRESS[6]} 4 | grep balance | cut -d '"' -f4) -if [ $BALANCE == "250.00000000" ] - then - printf "PASS\n" - PASS=$((PASS+1)) - else - printf "FAIL (result:%s)\n" $BALANCE - FAIL=$((FAIL+1)) -fi - -printf "\n" -printf "####################\n" -printf "# Summary: #\n" -printf "# Passed = %d #\n" $PASS -printf "# Failed = %d #\n" $FAIL -printf "####################\n" -printf "\n" - -$SRCDIR/omnicore-cli --regtest stop - diff --git a/src/elysium/test/uint256_extensions_tests.cpp b/src/elysium/test/uint256_extensions_tests.cpp deleted file mode 100644 index 4fa973649a..0000000000 --- a/src/elysium/test/uint256_extensions_tests.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "elysium/uint256_extensions.h" - -#include "arith_uint256.h" -#include "test/test_bitcoin.h" - -#include - -#include -#include - -using namespace elysium; - -BOOST_FIXTURE_TEST_SUITE(elysium_uint256_extensions_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(uint256_from_uint64_t) -{ - uint64_t number = 103242; - - arith_uint256 a(number); - - BOOST_CHECK_EQUAL(number, a.GetLow64()); -} - -BOOST_AUTO_TEST_CASE(uint256_add) -{ - uint64_t number_a = 103242; - uint64_t number_b = 234324; - uint64_t number_c = number_a + number_b; - - arith_uint256 a(number_a); - arith_uint256 b(number_b); - arith_uint256 c = a + b; - - BOOST_CHECK_EQUAL(number_c, c.GetLow64()); -} - -BOOST_AUTO_TEST_CASE(uint256_sub) -{ - uint64_t number_a = 503242; - uint64_t number_b = 234324; - uint64_t number_c = number_a - number_b; - - arith_uint256 a(number_a); - arith_uint256 b(number_b); - arith_uint256 c = a - b; - - BOOST_CHECK_EQUAL(number_c, c.GetLow64()); -} - -BOOST_AUTO_TEST_CASE(uint256_mul) -{ - uint64_t number_a = 503242; - uint64_t number_b = 234324; - uint64_t number_c = number_a * number_b; - - arith_uint256 a(number_a); - arith_uint256 b(number_b); - arith_uint256 c = a * b; - - BOOST_CHECK_EQUAL(number_c, c.GetLow64()); -} - -BOOST_AUTO_TEST_CASE(uint256_div) -{ - uint64_t number_a = 9; - uint64_t number_b = 4; - uint64_t number_c = number_a / number_b; - - arith_uint256 a(number_a); - arith_uint256 b(number_b); - arith_uint256 c = a / b; - - BOOST_CHECK_EQUAL(number_c, c.GetLow64()); -} - -BOOST_AUTO_TEST_CASE(uint256_conversion) -{ - BOOST_CHECK_EQUAL(0, ConvertTo64(ConvertTo256(0))); - BOOST_CHECK_EQUAL(1, ConvertTo64(ConvertTo256(1))); - BOOST_CHECK_EQUAL(1000000000000000000LL, ConvertTo64(ConvertTo256(1000000000000000000LL))); - BOOST_CHECK_EQUAL(9223372036854775807LL, ConvertTo64(ConvertTo256(9223372036854775807LL))); -} - -BOOST_AUTO_TEST_CASE(uint256_modulo) -{ - BOOST_CHECK_EQUAL(1, ConvertTo64(Modulo256(ConvertTo256(9), ConvertTo256(4)))); -} - -BOOST_AUTO_TEST_CASE(uint256_modulo_auto_conversion) -{ - BOOST_CHECK_EQUAL(2, ConvertTo64(Modulo256(17, 3))); -} - -BOOST_AUTO_TEST_CASE(uint256_divide_and_round_up) -{ - BOOST_CHECK_EQUAL(3, ConvertTo64(DivideAndRoundUp(ConvertTo256(5), ConvertTo256(2)))); -} - -BOOST_AUTO_TEST_CASE(uint256_const) -{ - BOOST_CHECK_EQUAL(1, ConvertTo64(elysium::uint256_const::one)); - BOOST_CHECK_EQUAL(std::numeric_limits::max(), ConvertTo64(elysium::uint256_const::max_int64)); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/elysium/test/utils_tx.cpp b/src/elysium/test/utils_tx.cpp deleted file mode 100644 index ac0156406f..0000000000 --- a/src/elysium/test/utils_tx.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "utils_tx.h" - -#include "../elysium.h" -#include "../packetencoder.h" -#include "../script.h" - -#include "../../base58.h" -#include "../../pubkey.h" -#include "../../utilstrencodings.h" - -#include "../../primitives/transaction.h" - -#include "../../script/script.h" -#include "../../script/standard.h" - -#include - -CTxOut PayToPubKeyHash_Elysium() -{ - CScript scriptPubKey = GetScriptForDestination(elysium::GetSystemAddress().Get()); - int64_t amount = GetDustThreshold(scriptPubKey); - - return CTxOut(amount, scriptPubKey); -} - -CTxOut PayToPubKeyHash_Unrelated() -{ - CBitcoinAddress address("a6FFPX9EvcDCtKCzootN4EMwMv2K9xnVcV"); - CScript scriptPubKey = GetScriptForDestination(address.Get()); - int64_t amount = GetDustThreshold(scriptPubKey); - - return CTxOut(amount, scriptPubKey); -} - -CTxOut PayToScriptHash_Unrelated() -{ - CBitcoinAddress address("3MbYQMMmSkC3AgWkj9FMo5LsPTW1zBTwXL"); - CScript scriptPubKey = GetScriptForDestination(address.Get()); - int64_t amount = GetDustThreshold(scriptPubKey); - - return CTxOut(amount, scriptPubKey); -} - -CTxOut PayToPubKey_Unrelated() -{ - std::vector vchPubKey = ParseHex( - "04ad90e5b6bc86b3ec7fac2c5fbda7423fc8ef0d58df594c773fa05e2c281b2bfe" - "877677c668bd13603944e34f4818ee03cadd81a88542b8b4d5431264180e2c28"); - - CPubKey pubKey(vchPubKey.begin(), vchPubKey.end()); - - CScript scriptPubKey; - scriptPubKey << ToByteVector(pubKey) << OP_CHECKSIG; - - int64_t amount = GetDustThreshold(scriptPubKey); - - return CTxOut(amount, scriptPubKey); -} - -CTxOut PayToBareMultisig_1of2() -{ - std::vector vchPayload1 = ParseHex( - "04ad90e5b6bc86b3ec7fac2c5fbda7423fc8ef0d58df594c773fa05e2c281b2bfe" - "877677c668bd13603944e34f4818ee03cadd81a88542b8b4d5431264180e2c28"); - std::vector vchPayload2 = ParseHex( - "026766a63686d2cc5d82c929d339b7975010872aa6bf76f6fac69f28f8e293a914"); - - CPubKey pubKey1(vchPayload1.begin(), vchPayload1.end()); - CPubKey pubKey2(vchPayload2.begin(), vchPayload2.end()); - - // 1-of-2 bare multisig script - CScript scriptPubKey; - scriptPubKey << CScript::EncodeOP_N(1); - scriptPubKey << ToByteVector(pubKey1); - scriptPubKey << ToByteVector(pubKey2); - scriptPubKey << CScript::EncodeOP_N(2); - scriptPubKey << OP_CHECKMULTISIG; - - int64_t amount = GetDustThreshold(scriptPubKey); - - return CTxOut(amount, scriptPubKey); -} - -CTxOut PayToBareMultisig_1of3() -{ - std::vector vchPayload1 = ParseHex( - "04ad90e5b6bc86b3ec7fac2c5fbda7423fc8ef0d58df594c773fa05e2c281b2bfe" - "877677c668bd13603944e34f4818ee03cadd81a88542b8b4d5431264180e2c28"); - std::vector vchPayload2 = ParseHex( - "026766a63686d2cc5d82c929d339b7975010872aa6bf76f6fac69f28f8e293a914"); - std::vector vchPayload3 = ParseHex( - "02959b8e2f2e4fb67952cda291b467a1781641c94c37feaa0733a12782977da23b"); - - CPubKey pubKey1(vchPayload1.begin(), vchPayload1.end()); - CPubKey pubKey2(vchPayload2.begin(), vchPayload2.end()); - CPubKey pubKey3(vchPayload3.begin(), vchPayload3.end()); - - // 1-of-3 bare multisig script - CScript scriptPubKey; - scriptPubKey << CScript::EncodeOP_N(1); - scriptPubKey << ToByteVector(pubKey1); - scriptPubKey << ToByteVector(pubKey2); - scriptPubKey << ToByteVector(pubKey3); - scriptPubKey << CScript::EncodeOP_N(3); - scriptPubKey << OP_CHECKMULTISIG; - - int64_t amount = GetDustThreshold(scriptPubKey); - - return CTxOut(amount, scriptPubKey); -} - -CTxOut PayToBareMultisig_3of5() -{ - std::vector vchPayload1 = ParseHex( - "02619c30f643a4679ec2f690f3d6564df7df2ae23ae4a55393ae0bef22db9dbcaf"); - std::vector vchPayload2 = ParseHex( - "026766a63686d2cc5d82c929d339b7975010872aa6bf76f6fac69f28f8e293a914"); - std::vector vchPayload3 = ParseHex( - "02959b8e2f2e4fb67952cda291b467a1781641c94c37feaa0733a12782977da23b"); - std::vector vchPayload4 = ParseHex( - "0261a017029ec4688ec9bf33c44ad2e595f83aaf3ed4f3032d1955715f5ffaf6b8"); - std::vector vchPayload5 = ParseHex( - "02dc1a0afc933d703557d9f5e86423a5cec9fee4bfa850b3d02ceae72117178802"); - - CPubKey pubKey1(vchPayload1.begin(), vchPayload1.end()); - CPubKey pubKey2(vchPayload2.begin(), vchPayload2.end()); - CPubKey pubKey3(vchPayload3.begin(), vchPayload3.end()); - CPubKey pubKey4(vchPayload4.begin(), vchPayload4.end()); - CPubKey pubKey5(vchPayload5.begin(), vchPayload5.end()); - - // 3-of-5 bare multisig script - CScript scriptPubKey; - scriptPubKey << CScript::EncodeOP_N(3); - scriptPubKey << ToByteVector(pubKey1); - scriptPubKey << ToByteVector(pubKey2) << ToByteVector(pubKey3); - scriptPubKey << ToByteVector(pubKey4) << ToByteVector(pubKey5); - scriptPubKey << CScript::EncodeOP_N(5); - scriptPubKey << OP_CHECKMULTISIG; - - int64_t amount = GetDustThreshold(scriptPubKey); - - return CTxOut(amount, scriptPubKey); -} - -CTxOut OpReturn_Empty() -{ - CScript scriptPubKey; - scriptPubKey << OP_RETURN; - - return CTxOut(0, scriptPubKey); -} - -CTxOut OpReturn_UnrelatedShort() -{ - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("b9"); - - return CTxOut(0, scriptPubKey); -} - -CTxOut OpReturn_Unrelated() -{ - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("7468697320697320646578782028323031352d30362d313129"); - - return CTxOut(0, scriptPubKey); -} - -CTxOut OpReturn_PlainMarker() -{ - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("65786f647573"); - - return CTxOut(0, scriptPubKey); -} - -CTxOut OpReturn_SimpleSend() -{ - CScript scriptPubKey; - scriptPubKey << OP_RETURN << ParseHex("65786f64757300000000000000070000000006dac2c0"); - - return CTxOut(0, scriptPubKey); -} - - -CTxOut OpReturn_MultiSimpleSend() -{ - CScript scriptPubKey; - scriptPubKey << OP_RETURN; - scriptPubKey << ParseHex("65786f647573"); - scriptPubKey << ParseHex("00000000000000070000000000002329"); - scriptPubKey << ParseHex("0062e907b15cbf27d5425399ebf6f0fb50ebb88f18"); - scriptPubKey << ParseHex("000000000000001f0000000001406f40"); - scriptPubKey << ParseHex("05da59767e81f4b019fe9f5984dbaa4f61bf197967"); - - return CTxOut(0, scriptPubKey); -} - -CTxOut NonStandardOutput() -{ - CScript scriptPubKey; - scriptPubKey << ParseHex("decafbad") << OP_DROP << OP_TRUE; - int64_t amount = GetDustThreshold(scriptPubKey); - - return CTxOut(amount, scriptPubKey); -} diff --git a/src/elysium/test/utils_tx.h b/src/elysium/test/utils_tx.h deleted file mode 100644 index 4401620b3a..0000000000 --- a/src/elysium/test/utils_tx.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ELYSIUM_TEST_UTILS_TX_H -#define ELYSIUM_TEST_UTILS_TX_H - -class CTxOut; - -CTxOut PayToPubKeyHash_Elysium(); -CTxOut PayToPubKeyHash_Unrelated(); -CTxOut PayToScriptHash_Unrelated(); -CTxOut PayToPubKey_Unrelated(); -CTxOut PayToBareMultisig_1of2(); -CTxOut PayToBareMultisig_1of3(); -CTxOut PayToBareMultisig_3of5(); -CTxOut OpReturn_Empty(); -CTxOut OpReturn_UnrelatedShort(); -CTxOut OpReturn_Unrelated(); -CTxOut OpReturn_PlainMarker(); -CTxOut OpReturn_SimpleSend(); -CTxOut OpReturn_MultiSimpleSend(); -CTxOut NonStandardOutput(); - - -#endif // ELYSIUM_TEST_UTILS_TX_H diff --git a/src/elysium/test/wallet_tests.cpp b/src/elysium/test/wallet_tests.cpp deleted file mode 100644 index 861969fda6..0000000000 --- a/src/elysium/test/wallet_tests.cpp +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (c) 2019 The Firo Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "../property.h" -#include "../sigmadb.h" -#include "../sigmaprimitives.h" -#include "../wallet.h" -#include "../walletmodels.h" - -#include "../../wallet/wallet.h" -#include "../../wallet/walletexcept.h" - -#include "../../wallet/test/wallet_test_fixture.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace std { - -template -basic_ostream& operator<<(basic_ostream& os, const base_blob& v) -{ - return os << v.GetHex(); -} - -} // namespace std - -namespace elysium { - -struct WalletTestingSetup : ::WalletTestingSetup -{ - WalletTestingSetup() - { - sigmaDb = new SigmaDatabase(pathTemp / "elysium_sigma_tests", true, 10); - wallet = new Wallet(pwalletMain->strWalletFile); - wallet->ReloadMasterKey(); - } - - ~WalletTestingSetup() - { - delete wallet; wallet = nullptr; - delete sigmaDb; sigmaDb = nullptr; - } - - SigmaMint CreateSigmaMint(PropertyId property, SigmaDenomination denomination) - { - auto id = wallet->CreateSigmaMint(property, denomination); - return wallet->GetSigmaMint(id); - } -}; - -BOOST_FIXTURE_TEST_SUITE(elysium_wallet_tests, WalletTestingSetup) - -BOOST_AUTO_TEST_CASE(sigma_mint_create_one) -{ - auto id = wallet->CreateSigmaMint(1, 2); - auto mint = wallet->GetSigmaMint(id); - - BOOST_CHECK(id.pubKey.IsValid()); - BOOST_CHECK_EQUAL(1, id.property); - BOOST_CHECK_EQUAL(2, id.denomination); - BOOST_CHECK_EQUAL(id.property, mint.property); - BOOST_CHECK_EQUAL(id.denomination, mint.denomination); - - BOOST_CHECK(!mint.IsSpent()); - BOOST_CHECK_EQUAL(mint.chainState, SigmaMintChainState()); - - auto priv = wallet->GetKey(mint); - SigmaPublicKey pub(priv, DefaultSigmaParams); - BOOST_CHECK_EQUAL(id.pubKey, pub); - - auto another = CreateSigmaMint(1, 2); - - BOOST_CHECK_NE(another, mint); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_create_multi) -{ - std::vector denominations = {0, 1, 0, 2}; - std::vector ids(5); - std::unordered_set mints; - - auto next = wallet->CreateSigmaMints(1, denominations.begin(), denominations.end(), ids.begin()); - - BOOST_CHECK_EQUAL(std::distance(ids.begin(), next), 4); - - BOOST_CHECK_EQUAL(ids[0].denomination, 0); - BOOST_CHECK_EQUAL(ids[1].denomination, 1); - BOOST_CHECK_EQUAL(ids[2].denomination, 0); - BOOST_CHECK_EQUAL(ids[3].denomination, 2); - - for (auto it = ids.begin(); it != next; it++) { - auto& id = *it; - auto mint = wallet->GetSigmaMint(id); - - BOOST_CHECK_EQUAL(id.property, 1); - BOOST_CHECK_EQUAL(mint.property, id.property); - BOOST_CHECK_EQUAL(id.denomination, mint.denomination); - BOOST_CHECK(id.pubKey.IsValid()); - - BOOST_CHECK_NE(id.pubKey, SigmaPublicKey()); - - BOOST_CHECK(!mint.IsSpent()); - BOOST_CHECK_EQUAL(mint.chainState, SigmaMintChainState()); - - BOOST_CHECK(mints.insert(std::move(mint)).second); - - auto priv = wallet->GetKey(mint); - SigmaPublicKey pub(priv, DefaultSigmaParams); - BOOST_CHECK_EQUAL(pub, id.pubKey); - } -} - -BOOST_AUTO_TEST_CASE(sigma_spend_create_no_spendable_mint) -{ - // No any mints. - BOOST_CHECK_THROW(wallet->CreateSigmaSpendV1(3, 0, false), InsufficientFunds); - - // Different denomination and property type. - auto mintId = wallet->CreateSigmaMint(3, 0); - - BOOST_CHECK_THROW(wallet->CreateSigmaSpendV1(3, 1, false), InsufficientFunds); - BOOST_CHECK_THROW(wallet->CreateSigmaSpendV1(4, 0, false), InsufficientFunds); - - // Pending mint. - BOOST_CHECK_THROW(wallet->CreateSigmaSpendV1(3, 0, false), InsufficientFunds); - - // Already spent. - sigmaDb->RecordMint(3, 0, mintId.pubKey, 100); - wallet->SetSigmaMintUsedTransaction(mintId, uint256S("890e968f9b65dbacd576100c9b1c446f06471ed27df845ab7a24931cb640b388")); - - BOOST_CHECK_THROW(wallet->CreateSigmaSpendV1(3, 0, false), InsufficientFunds); -} - -BOOST_AUTO_TEST_CASE(sigma_spend_create_with_spendable_mints) -{ - // Create first full group and one mint in a next group. - auto expectedMintId = wallet->CreateSigmaMint(3, 0); - sigmaDb->RecordMint(3, 0, expectedMintId.pubKey, 100); - - for (unsigned i = 1; i <= sigmaDb->groupSize; i++) { - auto mintid = wallet->CreateSigmaMint(3, 0); - sigmaDb->RecordMint(3, 0, mintid.pubKey, 100 + i); - } - - auto spend = wallet->CreateSigmaSpendV1(3, 0, false); - - BOOST_CHECK_EQUAL(spend.mint, expectedMintId); - BOOST_CHECK_EQUAL(spend.group, 0); - BOOST_CHECK_EQUAL(spend.groupSize, sigmaDb->groupSize); -} - -BOOST_AUTO_TEST_CASE(sigma_spend_create_not_enough_anonimity) -{ - auto mintId = wallet->CreateSigmaMint(3, 0); - sigmaDb->RecordMint(3, 0, mintId.pubKey, 100); - - BOOST_CHECK_EXCEPTION(wallet->CreateSigmaSpendV1(3, 0, false), WalletError, [] (const WalletError& e) { - return e.what() == std::string("Amount of coins in anonimity set is not enough to spend"); - }); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_listing_all) -{ - // Create mints. - std::unordered_set ids; - - ids.insert(wallet->CreateSigmaMint(1, 0)); - ids.insert(wallet->CreateSigmaMint(2, 0)); - ids.insert(wallet->CreateSigmaMint(1, 1)); - ids.insert(wallet->CreateSigmaMint(2, 0)); - - BOOST_CHECK_EQUAL(ids.size(), 4); - - // List mints. - std::unordered_map mints; - - wallet->ListSigmaMintsV1(std::inserter(mints, mints.begin())); - - BOOST_CHECK_EQUAL(mints.size(), ids.size()); - - for (auto& mint : mints) { - auto it = ids.find(mint.first); - - BOOST_CHECK(it != ids.end()); - BOOST_CHECK_EQUAL(mint.second, wallet->GetSigmaMint(*it)); - - ids.erase(it); - } - - BOOST_CHECK_EQUAL(ids.size(), 0); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_check_existence) -{ - auto owned = wallet->CreateSigmaMint(1, 1); - SigmaPrivateKey priv; - SigmaPublicKey pub; - - priv.Generate(); - pub.Generate(priv, DefaultSigmaParams); - - SigmaMintId other(1, 1, pub); - - BOOST_CHECK_EQUAL(wallet->HasSigmaMint(owned), true); - BOOST_CHECK_EQUAL(wallet->HasSigmaMint(other), false); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_get) -{ - // Get existence. - auto owned = wallet->CreateSigmaMint(1, 1); - auto mint = wallet->GetSigmaMint(owned); - - SigmaPublicKey pub(wallet->GetKey(mint), DefaultSigmaParams); - BOOST_CHECK_EQUAL(owned, SigmaMintId(mint.property, mint.denomination, pub)); - - // Get non-existence. - SigmaPrivateKey otherPriv; - SigmaPublicKey otherPub; - - otherPriv.Generate(); - otherPub.Generate(otherPriv, DefaultSigmaParams); - - SigmaMintId other(1, 1, otherPub); - - BOOST_CHECK_THROW(wallet->GetSigmaMint(other), std::invalid_argument); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_set_used) -{ - auto tx = uint256S("64c4c22a45ad449be61c52a431d11e81f7fd0ee2f2235bf02944fb0b3dd07adb"); - auto id = wallet->CreateSigmaMint(1, 1); - SigmaMint mint; - - wallet->SetSigmaMintUsedTransaction(id, tx); - mint = wallet->GetSigmaMint(id); - BOOST_CHECK_EQUAL(mint.spendTx, tx); - - wallet->SetSigmaMintUsedTransaction(id, uint256()); - mint = wallet->GetSigmaMint(id); - BOOST_CHECK(!mint.IsSpent()); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_chainstate_owned) -{ - auto id = wallet->CreateSigmaMint(1, 0); - SigmaMintGroup group; - SigmaMintIndex index; - SigmaMint mint; - - // Add. - std::tie(group, index) = sigmaDb->RecordMint(1, 0, id.pubKey, 100); - mint = wallet->GetSigmaMint(id); - - BOOST_CHECK_EQUAL(mint.chainState.block, 100); - BOOST_CHECK_EQUAL(mint.chainState.group, group); - BOOST_CHECK_EQUAL(mint.chainState.index, index); - - // Remove. - sigmaDb->DeleteAll(100); - mint = wallet->GetSigmaMint(id); - - BOOST_CHECK_EQUAL(mint.chainState, SigmaMintChainState()); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_chainstate_not_owned) -{ - // Add our mint first so we can test if the other mint does not alter our mint state. - auto id = wallet->CreateSigmaMint(1, 0); - SigmaMintGroup group; - SigmaMintIndex index; - - std::tie(group, index) = sigmaDb->RecordMint(1, 0, id.pubKey, 100); - - // Add other mint. - SigmaPrivateKey otherPriv; - SigmaPublicKey otherPub; - - otherPriv.Generate(); - otherPub.Generate(otherPriv, DefaultSigmaParams); - - sigmaDb->RecordMint(1, 0, otherPub, 101); - - // Our chain state should not updated. - SigmaMint mint; - - mint = wallet->GetSigmaMint(id); - - BOOST_CHECK_EQUAL(mint.chainState.block, 100); - BOOST_CHECK_EQUAL(mint.chainState.group, group); - BOOST_CHECK_EQUAL(mint.chainState.index, index); - - // Other mint should not added to our wallet. - BOOST_CHECK_THROW( - wallet->GetSigmaMint(SigmaMintId(1, 0, otherPub)), - std::invalid_argument - ); - - // Remove other mint and our chain state should not updated. - sigmaDb->DeleteAll(101); - - mint = wallet->GetSigmaMint(id); - - BOOST_CHECK_EQUAL(mint.chainState.block, 100); - BOOST_CHECK_EQUAL(mint.chainState.group, group); - BOOST_CHECK_EQUAL(mint.chainState.index, index); -} - -BOOST_AUTO_TEST_SUITE_END() - -} diff --git a/src/elysium/test/walletmodels_tests.cpp b/src/elysium/test/walletmodels_tests.cpp deleted file mode 100644 index 410c014fb2..0000000000 --- a/src/elysium/test/walletmodels_tests.cpp +++ /dev/null @@ -1,351 +0,0 @@ -#include "../walletmodels.h" - -#include "../../clientversion.h" -#include "../../streams.h" -#include "../../test/test_bitcoin.h" - -#include - -#include - -using namespace elysium; - -namespace { - -SigmaMintId GenerateSigmaMintId(PropertyId property, SigmaDenomination denom) -{ - SigmaPrivateKey priv; - priv.Generate(); - SigmaPublicKey pub(priv, DefaultSigmaParams); - - return SigmaMintId(property, denom, pub); -} - -} // unnamed namespace - -namespace std { - -template -basic_ostream& operator<<(basic_ostream& os, const base_blob& v) -{ - return os << v.GetHex(); -} - -} // namespace std - -namespace elysium { - -BOOST_FIXTURE_TEST_SUITE(elysium_walletmodels_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(sigma_mint_chainstate_default) -{ - SigmaMintChainState state; - - BOOST_CHECK_LT(state.block, 0); - BOOST_CHECK_EQUAL(state.group, 0); - BOOST_CHECK_EQUAL(state.index, 0); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_chainstate_init) -{ - SigmaMintChainState state(100000, 1, 50); - - BOOST_CHECK_EQUAL(state.block, 100000); - BOOST_CHECK_EQUAL(state.group, 1); - BOOST_CHECK_EQUAL(state.index, 50); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_chainstate_equality) -{ - SigmaMintChainState state(100, 1, 50); - - BOOST_CHECK_EQUAL(state, SigmaMintChainState(100, 1, 50)); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_chainstate_unequality) -{ - SigmaMintChainState state(100, 1, 50); - - BOOST_CHECK_NE(state, SigmaMintChainState(99, 1, 50)); - BOOST_CHECK_NE(state, SigmaMintChainState(100, 2, 50)); - BOOST_CHECK_NE(state, SigmaMintChainState(100, 1, 60)); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_chainstate_clear) -{ - SigmaMintChainState state(100, 1, 50); - - state.Clear(); - - BOOST_CHECK_EQUAL(state, SigmaMintChainState()); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_chainstate_serialization) -{ - SigmaMintChainState original(100, 1, 50), deserialized; - CDataStream stream(SER_DISK, CLIENT_VERSION); - - stream << original; - stream >> deserialized; - - BOOST_CHECK_EQUAL(deserialized, original); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_chainstate_hash) -{ - SigmaMintChainState state1(100, 0, 0), state2(101, 0, 0); - std::hash hasher; - - BOOST_CHECK_EQUAL(hasher(state1), hasher(state1)); - BOOST_CHECK_NE(hasher(state1), hasher(state2)); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_id_default) -{ - SigmaMintId id; - - BOOST_CHECK_EQUAL(id.property, 0); - BOOST_CHECK_EQUAL(id.denomination, 0); - BOOST_CHECK_EQUAL(id.pubKey, SigmaPublicKey()); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_id_init) -{ - SigmaPrivateKey priv; - SigmaPublicKey pub; - - priv.Generate(); - pub.Generate(priv, DefaultSigmaParams); - - SigmaMintId id(1, 5, pub); - - BOOST_CHECK_EQUAL(id.property, 1); - BOOST_CHECK_EQUAL(id.denomination, 5); - BOOST_CHECK_EQUAL(id.pubKey, pub); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_id_serialization) -{ - SigmaPrivateKey priv; - SigmaPublicKey pub; - - priv.Generate(); - pub.Generate(priv, DefaultSigmaParams); - - SigmaMintId original(1, 5, pub), deserialized; - CDataStream stream(SER_DISK, CLIENT_VERSION); - - stream << original; - stream >> deserialized; - - BOOST_CHECK_EQUAL(deserialized.property, original.property); - BOOST_CHECK_EQUAL(deserialized.denomination, original.denomination); - BOOST_CHECK_EQUAL(deserialized.pubKey, original.pubKey); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_id_hash) -{ - SigmaMintId id1, id2; - id1 = GenerateSigmaMintId(3, 0); - id2 = GenerateSigmaMintId(3, 0); - - std::hash hasher; - - BOOST_CHECK_EQUAL(hasher(id1), hasher(id1)); - BOOST_CHECK_NE(hasher(id1), hasher(id2)); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_default) -{ - SigmaMint mint; - - BOOST_CHECK_EQUAL(mint.property, 0); - BOOST_CHECK_EQUAL(mint.denomination, 0); - BOOST_CHECK_EQUAL(mint.seedId, CKeyID()); - BOOST_CHECK_EQUAL(mint.serialId, uint160()); - BOOST_CHECK_EQUAL(mint.createdTx, uint256()); - BOOST_CHECK_EQUAL(mint.chainState, SigmaMintChainState()); - BOOST_CHECK_EQUAL(mint.spendTx, uint256()); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_init) -{ - CKeyID seed; - uint160 serial; - - seed.SetHex("c20c027ecb57f6bca0e7995f089f2476872ce3c2"); - serial.SetHex("9ef47fe3beb4eca6521644d810f8d82aafa25deb"); - - SigmaMint mint(3, 1, seed, serial); - - BOOST_CHECK_EQUAL(mint.property, 3); - BOOST_CHECK_EQUAL(mint.denomination, 1); - BOOST_CHECK_EQUAL(mint.seedId, seed); - BOOST_CHECK_EQUAL(mint.serialId, serial); - BOOST_CHECK_EQUAL(mint.createdTx, uint256()); - BOOST_CHECK_EQUAL(mint.chainState, SigmaMintChainState()); - BOOST_CHECK_EQUAL(mint.spendTx, uint256()); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_equality) -{ - SigmaMint left, right; - - left.property = 1; - left.denomination = 1; - left.seedId.SetHex("6b9271111f615f2add38ecca577bd8297cdada76"); - left.serialId.SetHex("e452b723bd12bfcc441e675eedcfad5c8a80435d"); - left.createdTx.SetHex("d256b698c4c1caa75fcbeec68e6636119e02526c58eea91088eba71d9e25e768"); - left.chainState = SigmaMintChainState(500, 1, 50); - left.spendTx.SetHex("e84390b1e9af85fed8ef3f95d6f94550e53a8a9214677a4b5cae9e93888537ab"); - - right.property = 1; - right.denomination = 1; - right.seedId.SetHex("6b9271111f615f2add38ecca577bd8297cdada76"); - right.serialId.SetHex("e452b723bd12bfcc441e675eedcfad5c8a80435d"); - right.createdTx.SetHex("d256b698c4c1caa75fcbeec68e6636119e02526c58eea91088eba71d9e25e768"); - right.chainState = SigmaMintChainState(500, 1, 50); - right.spendTx.SetHex("e84390b1e9af85fed8ef3f95d6f94550e53a8a9214677a4b5cae9e93888537ab"); - - BOOST_CHECK_EQUAL(left, right); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_unequality) -{ - SigmaMint left, right; - - left.property = 1; - left.denomination = 1; - left.seedId.SetHex("6b9271111f615f2add38ecca577bd8297cdada76"); - left.serialId.SetHex("e452b723bd12bfcc441e675eedcfad5c8a80435d"); - left.createdTx.SetHex("d256b698c4c1caa75fcbeec68e6636119e02526c58eea91088eba71d9e25e768"); - left.chainState = SigmaMintChainState(500, 1, 50); - left.spendTx.SetHex("e84390b1e9af85fed8ef3f95d6f94550e53a8a9214677a4b5cae9e93888537ab"); - - // Property. - right = left; - right.property = 2; - - BOOST_CHECK_NE(left, right); - - // Denomination. - right = left; - right.denomination = 10; - - BOOST_CHECK_NE(left, right); - - // Seed Id - right = left; - right.seedId.SetHex("aa53d9c19d2a435e586c5539e5696b9e0b49600a"); - - BOOST_CHECK_NE(left, right); - - // Serial Id - right = left; - right.serialId.SetHex("aa53d9c19d2a435e586c5539e5696b9e0b49600a"); - - BOOST_CHECK_NE(left, right); - - // Created TX. - right = left; - right.createdTx.SetHex("4feba033ccba0e98c48359e1974ef3257127cc1794baaa2a66f3773b42a313dd"); - - BOOST_CHECK_NE(left, right); - - // Chain State - right = left; - right.chainState = SigmaMintChainState(1000, 0, 0); - - BOOST_CHECK_NE(left, right); - - // Spend Tx - right = left; - right.spendTx.SetHex("4feba033ccba0e98c48359e1974ef3257127cc1794baaa2a66f3773b42a313dd"); - - BOOST_CHECK_NE(left, right); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_is_on_chain) -{ - SigmaMint mint; - - BOOST_CHECK_EQUAL(mint.IsOnChain(), false); - - mint.chainState.block = 0; - - BOOST_CHECK_EQUAL(mint.IsOnChain(), true); - - mint.chainState.block = 1; - - BOOST_CHECK_EQUAL(mint.IsOnChain(), true); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_is_spent) -{ - SigmaMint mint; - - BOOST_CHECK_EQUAL(mint.IsSpent(), false); - - mint.spendTx.SetHex("4feba033ccba0e98c48359e1974ef3257127cc1794baaa2a66f3773b42a313dd"); - - BOOST_CHECK_EQUAL(mint.IsSpent(), true); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_serialization) -{ - SigmaMint original, deserialized; - - original.property = 1; - original.denomination = 1; - original.seedId.SetHex("d301a80ac8e079cfed60c361004caadc049052dd"); - original.serialId.SetHex("7b05ea12b56e60b28e2d20db6d77a95f56ae13bb"); - original.createdTx.SetHex("ddf5fb2d1124bcff2f2068334de61f6cc8849d7751a64a74900dbbec106ba884"); - original.chainState = SigmaMintChainState(500, 1, 50); - original.spendTx.SetHex("e84390b1e9af85fed8ef3f95d6f94550e53a8a9214677a4b5cae9e93888537ab"); - - CDataStream stream(SER_DISK, CLIENT_VERSION); - - stream << original; - stream >> deserialized; - - BOOST_CHECK_EQUAL(deserialized, original); -} - -BOOST_AUTO_TEST_CASE(sigma_mint_hash) -{ - SigmaMint mint1, mint2; - - mint1.denomination = 0; - mint2.denomination = 1; - - std::hash hasher; - - BOOST_CHECK_EQUAL(hasher(mint1), hasher(mint1)); - BOOST_CHECK_NE(hasher(mint1), hasher(mint2)); -} - -BOOST_AUTO_TEST_CASE(sigma_spend_init) -{ - auto& params = DefaultSigmaParams; - SigmaPrivateKey key1, key2; - key1.Generate(); - key2.Generate(); - - SigmaPublicKey pub1(key1, params), pub2(key2, params); - - SigmaMintId id(3, 0, pub1); - SigmaMint mint(3, 0, Hash160({0x00}), Hash160({0x01})); - - std::vector anonimitySet = { pub1, pub2 }; - SigmaProof proof(params, key1, anonimitySet.begin(), anonimitySet.end(), false); - SigmaSpend spend(id, 1, 100, proof); - - BOOST_CHECK_EQUAL(spend.mint, id); - BOOST_CHECK_EQUAL(spend.group, 1); - BOOST_CHECK_EQUAL(spend.groupSize, 100); - BOOST_CHECK_EQUAL(spend.proof, proof); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // namespace elysium diff --git a/src/elysium/tx.cpp b/src/elysium/tx.cpp deleted file mode 100644 index 84457d8b6d..0000000000 --- a/src/elysium/tx.cpp +++ /dev/null @@ -1,2774 +0,0 @@ -// Elysium Protocol transaction code - -#include "elysium/tx.h" - -#include "elysium/activation.h" -#include "elysium/convert.h" -#include "elysium/dex.h" -#include "elysium/fees.h" -#include "elysium/log.h" -#include "elysium/mdex.h" -#include "elysium/notifications.h" -#include "elysium/elysium.h" -#include "elysium/rules.h" -#include "elysium/sp.h" -#include "elysium/sto.h" -#include "elysium/utils.h" -#include "elysium/utilsbitcoin.h" -#include "elysium/version.h" - -#include "amount.h" -#include "base58.h" -#include "validation.h" -#include "sync.h" -#include "utiltime.h" - -#include -#include - -#include -#include - -#include -#include -#include - -using boost::algorithm::token_compress_on; - -using namespace elysium; - -/** Returns a label for the given transaction type. */ -std::string elysium::strTransactionType(uint16_t txType) -{ - switch (txType) { - case ELYSIUM_TYPE_SIMPLE_SEND: return "Simple Send"; - case ELYSIUM_TYPE_RESTRICTED_SEND: return "Restricted Send"; - case ELYSIUM_TYPE_SEND_TO_OWNERS: return "Send To Owners"; - case ELYSIUM_TYPE_SEND_ALL: return "Send All"; - case ELYSIUM_TYPE_SAVINGS_MARK: return "Savings"; - case ELYSIUM_TYPE_SAVINGS_COMPROMISED: return "Savings COMPROMISED"; - case ELYSIUM_TYPE_RATELIMITED_MARK: return "Rate-Limiting"; - case ELYSIUM_TYPE_AUTOMATIC_DISPENSARY: return "Automatic Dispensary"; - case ELYSIUM_TYPE_TRADE_OFFER: return "DEx Sell Offer"; - case ELYSIUM_TYPE_METADEX_TRADE: return "MetaDEx trade"; - case ELYSIUM_TYPE_METADEX_CANCEL_PRICE: return "MetaDEx cancel-price"; - case ELYSIUM_TYPE_METADEX_CANCEL_PAIR: return "MetaDEx cancel-pair"; - case ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM: return "MetaDEx cancel-ecosystem"; - case ELYSIUM_TYPE_ACCEPT_OFFER_BTC: return "DEx Accept Offer"; - case ELYSIUM_TYPE_CREATE_PROPERTY_FIXED: return "Create Property - Fixed"; - case ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE: return "Create Property - Variable"; - case ELYSIUM_TYPE_PROMOTE_PROPERTY: return "Promote Property"; - case ELYSIUM_TYPE_CLOSE_CROWDSALE: return "Close Crowdsale"; - case ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL: return "Create Property - Manual"; - case ELYSIUM_TYPE_GRANT_PROPERTY_TOKENS: return "Grant Property Tokens"; - case ELYSIUM_TYPE_REVOKE_PROPERTY_TOKENS: return "Revoke Property Tokens"; - case ELYSIUM_TYPE_CHANGE_ISSUER_ADDRESS: return "Change Issuer Address"; - case ELYSIUM_TYPE_ENABLE_FREEZING: return "Enable Freezing"; - case ELYSIUM_TYPE_DISABLE_FREEZING: return "Disable Freezing"; - case ELYSIUM_TYPE_FREEZE_PROPERTY_TOKENS: return "Freeze Property Tokens"; - case ELYSIUM_TYPE_UNFREEZE_PROPERTY_TOKENS: return "Unfreeze Property Tokens"; - case ELYSIUM_TYPE_NOTIFICATION: return "Notification"; - case ELYSIUM_MESSAGE_TYPE_ALERT: return "ALERT"; - case ELYSIUM_MESSAGE_TYPE_DEACTIVATION: return "Feature Deactivation"; - case ELYSIUM_MESSAGE_TYPE_ACTIVATION: return "Feature Activation"; - - default: return "* unknown type *"; - } -} - -void CMPTransaction::Set( - const std::string& s, - const std::string& r, - uint64_t n, - const uint256& t, - int b, - unsigned int idx, - unsigned char *p, - unsigned int size, - const boost::optional& packetClass, - uint64_t txf, - const boost::optional& referenceAmount) -{ - sender = s; - receiver = r; - txid = t; - block = b; - tx_idx = idx; - nValue = n; - nNewValue = n; - this->packetClass = packetClass; - tx_fee_paid = txf; - raw.clear(); - raw.insert(raw.end(), p, p + size); - this->referenceAmount = referenceAmount; -} - -/** Checks whether a pointer to the payload is past it's last position. */ -bool CMPTransaction::isOverrun(const unsigned char *p) -{ - ptrdiff_t pos = p - raw.data(); - assert(pos >= 0); - return (static_cast(pos) > raw.size()); -} - -// -------------------- PACKET PARSING ----------------------- - -/** Parses the packet or payload. */ -bool CMPTransaction::interpret_Transaction() -{ - if (!interpret_TransactionType()) { - PrintToLog("Failed to interpret type and version\n"); - return false; - } - - switch (type) { - case ELYSIUM_TYPE_SIMPLE_SEND: - return interpret_SimpleSend(); - - case ELYSIUM_TYPE_SEND_TO_OWNERS: - return interpret_SendToOwners(); - - case ELYSIUM_TYPE_SEND_ALL: - return interpret_SendAll(); - - case ELYSIUM_TYPE_TRADE_OFFER: - return interpret_TradeOffer(); - - case ELYSIUM_TYPE_ACCEPT_OFFER_BTC: - return interpret_AcceptOfferBTC(); - - case ELYSIUM_TYPE_METADEX_TRADE: - return interpret_MetaDExTrade(); - - case ELYSIUM_TYPE_METADEX_CANCEL_PRICE: - return interpret_MetaDExCancelPrice(); - - case ELYSIUM_TYPE_METADEX_CANCEL_PAIR: - return interpret_MetaDExCancelPair(); - - case ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM: - return interpret_MetaDExCancelEcosystem(); - - case ELYSIUM_TYPE_CREATE_PROPERTY_FIXED: - return interpret_CreatePropertyFixed(); - - case ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE: - return interpret_CreatePropertyVariable(); - - case ELYSIUM_TYPE_CLOSE_CROWDSALE: - return interpret_CloseCrowdsale(); - - case ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL: - return interpret_CreatePropertyManaged(); - - case ELYSIUM_TYPE_GRANT_PROPERTY_TOKENS: - return interpret_GrantTokens(); - - case ELYSIUM_TYPE_REVOKE_PROPERTY_TOKENS: - return interpret_RevokeTokens(); - - case ELYSIUM_TYPE_CHANGE_ISSUER_ADDRESS: - return interpret_ChangeIssuer(); - - case ELYSIUM_TYPE_ENABLE_FREEZING: - return interpret_EnableFreezing(); - - case ELYSIUM_TYPE_DISABLE_FREEZING: - return interpret_DisableFreezing(); - - case ELYSIUM_TYPE_FREEZE_PROPERTY_TOKENS: - return interpret_FreezeTokens(); - - case ELYSIUM_TYPE_UNFREEZE_PROPERTY_TOKENS: - return interpret_UnfreezeTokens(); - - case ELYSIUM_TYPE_CREATE_DENOMINATION: - return interpret_CreateDenomination(); - - case ELYSIUM_TYPE_SIMPLE_MINT: - return interpret_SimpleMint(); - - case ELYSIUM_TYPE_SIMPLE_SPEND: - return interpret_SimpleSpend(); - - case ELYSIUM_MESSAGE_TYPE_DEACTIVATION: - return interpret_Deactivation(); - - case ELYSIUM_MESSAGE_TYPE_ACTIVATION: - return interpret_Activation(); - - case ELYSIUM_MESSAGE_TYPE_ALERT: - return interpret_Alert(); - } - - return false; -} - -/** Version and type */ -bool CMPTransaction::interpret_TransactionType() -{ - if (raw.size() < 4) { - return false; - } - uint16_t txVersion = 0; - uint16_t txType = 0; - memcpy(&txVersion, &raw[0], 2); - swapByteOrder16(txVersion); - memcpy(&txType, &raw[2], 2); - swapByteOrder16(txType); - version = txVersion; - type = txType; - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t------------------------------\n"); - PrintToLog("\t version: %d, class %s\n", txVersion, std::to_string(*packetClass)); - PrintToLog("\t type: %d (%s)\n", txType, strTransactionType(txType)); - } - - return true; -} - -/** Tx 1 */ -bool CMPTransaction::interpret_SimpleSend() -{ - if (raw.size() < 16) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value: %s\n", FormatMP(property, nValue)); - } - - return true; -} - -/** Tx 3 */ -bool CMPTransaction::interpret_SendToOwners() -{ - unsigned expectedSize = (version == MP_TX_PKT_V0) ? 16 : 20; - if (raw.size() < expectedSize) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - if (version > MP_TX_PKT_V0) { - memcpy(&distribution_property, &raw[16], 4); - swapByteOrder32(distribution_property); - } - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value: %s\n", FormatMP(property, nValue)); - if (version > MP_TX_PKT_V1) { - PrintToLog("\t distributionproperty: %d (%s)\n", distribution_property, strMPProperty(distribution_property)); - } - } - - return true; -} - -/** Tx 4 */ -bool CMPTransaction::interpret_SendAll() -{ - if (raw.size() < 5) { - return false; - } - memcpy(&ecosystem, &raw[4], 1); - - property = ecosystem; // provide a hint for the UI, TODO: better handling! - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t ecosystem: %d\n", (int)ecosystem); - } - - return true; -} - -/** Tx 20 */ -bool CMPTransaction::interpret_TradeOffer() -{ - unsigned expectedSize = (version == MP_TX_PKT_V0) ? 33 : 34; - if (raw.size() < expectedSize) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - memcpy(&amount_desired, &raw[16], 8); - memcpy(&blocktimelimit, &raw[24], 1); - memcpy(&min_fee, &raw[25], 8); - if (version > MP_TX_PKT_V0) { - memcpy(&subaction, &raw[33], 1); - } - swapByteOrder64(amount_desired); - swapByteOrder64(min_fee); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value: %s\n", FormatMP(property, nValue)); - PrintToLog("\t amount desired: %s\n", FormatDivisibleMP(amount_desired)); - PrintToLog("\tblock time limit: %d\n", blocktimelimit); - PrintToLog("\t min fee: %s\n", FormatDivisibleMP(min_fee)); - if (version > MP_TX_PKT_V0) { - PrintToLog("\t sub-action: %d\n", subaction); - } - } - - return true; -} - -/** Tx 22 */ -bool CMPTransaction::interpret_AcceptOfferBTC() -{ - if (raw.size() < 16) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value: %s\n", FormatMP(property, nValue)); - } - - return true; -} - -/** Tx 25 */ -bool CMPTransaction::interpret_MetaDExTrade() -{ - if (raw.size() < 28) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - memcpy(&desired_property, &raw[16], 4); - swapByteOrder32(desired_property); - memcpy(&desired_value, &raw[20], 8); - swapByteOrder64(desired_value); - - action = CMPTransaction::ADD; // depreciated - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value: %s\n", FormatMP(property, nValue)); - PrintToLog("\tdesired property: %d (%s)\n", desired_property, strMPProperty(desired_property)); - PrintToLog("\t desired value: %s\n", FormatMP(desired_property, desired_value)); - } - - return true; -} - -/** Tx 26 */ -bool CMPTransaction::interpret_MetaDExCancelPrice() -{ - if (raw.size() < 28) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - memcpy(&desired_property, &raw[16], 4); - swapByteOrder32(desired_property); - memcpy(&desired_value, &raw[20], 8); - swapByteOrder64(desired_value); - - action = CMPTransaction::CANCEL_AT_PRICE; // depreciated - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value: %s\n", FormatMP(property, nValue)); - PrintToLog("\tdesired property: %d (%s)\n", desired_property, strMPProperty(desired_property)); - PrintToLog("\t desired value: %s\n", FormatMP(desired_property, desired_value)); - } - - return true; -} - -/** Tx 27 */ -bool CMPTransaction::interpret_MetaDExCancelPair() -{ - if (raw.size() < 12) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&desired_property, &raw[8], 4); - swapByteOrder32(desired_property); - - nValue = 0; // depreciated - nNewValue = nValue; // depreciated - desired_value = 0; // depreciated - action = CMPTransaction::CANCEL_ALL_FOR_PAIR; // depreciated - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\tdesired property: %d (%s)\n", desired_property, strMPProperty(desired_property)); - } - - return true; -} - -/** Tx 28 */ -bool CMPTransaction::interpret_MetaDExCancelEcosystem() -{ - if (raw.size() < 5) { - return false; - } - memcpy(&ecosystem, &raw[4], 1); - - property = ecosystem; // depreciated - desired_property = ecosystem; // depreciated - nValue = 0; // depreciated - nNewValue = nValue; // depreciated - desired_value = 0; // depreciated - action = CMPTransaction::CANCEL_EVERYTHING; // depreciated - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t ecosystem: %d\n", (int)ecosystem); - } - - return true; -} - -/** Tx 50 */ -bool CMPTransaction::interpret_CreatePropertyFixed() -{ - switch (version) { - case 0: - if (raw.size() < 25) { - return false; - } - break; - case 1: - if (raw.size() < 26) { - return false; - } - break; - default: - return false; - } - - auto p = raw.data() + 11; - auto end = raw.data() + raw.size(); - std::vector spstr; - memcpy(&ecosystem, &raw[4], 1); - memcpy(&prop_type, &raw[5], 2); - swapByteOrder16(prop_type); - memcpy(&prev_prop_id, &raw[7], 4); - swapByteOrder32(prev_prop_id); - for (int i = 0; i < 5; i++) { - auto last = std::find(p, end, 0); - if (last == end) { - return false; - } - spstr.push_back(std::string(p, last)); - p += spstr.back().size() + 1; - } - int i = 0; - memcpy(category, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(category)-1)); i++; - memcpy(subcategory, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(subcategory)-1)); i++; - memcpy(name, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(name)-1)); i++; - memcpy(url, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(url)-1)); i++; - memcpy(data, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(data)-1)); i++; - memcpy(&nValue, p, 8); - swapByteOrder64(nValue); - p += 8; - nNewValue = nValue; - - if (version == 1) { - memcpy(&sigmaStatus, p, 1); - p += 1; - } - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t ecosystem: %d\n", ecosystem); - PrintToLog("\t property type: %d (%s)\n", prop_type, strPropertyType(prop_type)); - PrintToLog("\tprev property id: %d\n", prev_prop_id); - PrintToLog("\t category: %s\n", category); - PrintToLog("\t subcategory: %s\n", subcategory); - PrintToLog("\t name: %s\n", name); - PrintToLog("\t url: %s\n", url); - PrintToLog("\t data: %s\n", data); - PrintToLog("\t value: %s\n", FormatByType(nValue, prop_type)); - PrintToLog("\t sigma status: %u\n", static_cast(sigmaStatus)); - } - - if (isOverrun(p)) { - PrintToLog("%s(): rejected: malformed string value(s)\n", __func__); - return false; - } - - return true; -} - -/** Tx 51 */ -bool CMPTransaction::interpret_CreatePropertyVariable() -{ - if (raw.size() < 39) { - return false; - } - auto p = raw.data() + 11; - auto end = raw.data() + raw.size(); - std::vector spstr; - memcpy(&ecosystem, &raw[4], 1); - memcpy(&prop_type, &raw[5], 2); - swapByteOrder16(prop_type); - memcpy(&prev_prop_id, &raw[7], 4); - swapByteOrder32(prev_prop_id); - for (int i = 0; i < 5; i++) { - auto last = std::find(p, end, 0); - if (last == end) { - return false; - } - spstr.push_back(std::string(p, last)); - p += spstr.back().size() + 1; - } - int i = 0; - memcpy(category, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(category)-1)); i++; - memcpy(subcategory, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(subcategory)-1)); i++; - memcpy(name, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(name)-1)); i++; - memcpy(url, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(url)-1)); i++; - memcpy(data, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(data)-1)); i++; - memcpy(&property, p, 4); - swapByteOrder32(property); - p += 4; - memcpy(&nValue, p, 8); - swapByteOrder64(nValue); - p += 8; - nNewValue = nValue; - memcpy(&deadline, p, 8); - swapByteOrder64(deadline); - p += 8; - memcpy(&early_bird, p++, 1); - memcpy(&percentage, p++, 1); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t ecosystem: %d\n", ecosystem); - PrintToLog("\t property type: %d (%s)\n", prop_type, strPropertyType(prop_type)); - PrintToLog("\tprev property id: %d\n", prev_prop_id); - PrintToLog("\t category: %s\n", category); - PrintToLog("\t subcategory: %s\n", subcategory); - PrintToLog("\t name: %s\n", name); - PrintToLog("\t url: %s\n", url); - PrintToLog("\t data: %s\n", data); - PrintToLog("\tproperty desired: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t tokens per unit: %s\n", FormatByType(nValue, prop_type)); - PrintToLog("\t deadline: %s (%x)\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", deadline), deadline); - PrintToLog("\tearly bird bonus: %d\n", early_bird); - PrintToLog("\t issuer bonus: %d\n", percentage); - } - - if (isOverrun(p)) { - PrintToLog("%s(): rejected: malformed string value(s)\n", __func__); - return false; - } - - return true; -} - -/** Tx 53 */ -bool CMPTransaction::interpret_CloseCrowdsale() -{ - if (raw.size() < 8) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - } - - return true; -} - -/** Tx 54 */ -bool CMPTransaction::interpret_CreatePropertyManaged() -{ - switch (version) { - case 0: - if (raw.size() < 17) { - return false; - } - break; - case 1: - if (raw.size() < 18) { - return false; - } - break; - default: - return false; - } - - auto p = raw.data() + 11; - auto end = raw.data() + raw.size(); - std::vector spstr; - memcpy(&ecosystem, &raw[4], 1); - memcpy(&prop_type, &raw[5], 2); - swapByteOrder16(prop_type); - memcpy(&prev_prop_id, &raw[7], 4); - swapByteOrder32(prev_prop_id); - for (int i = 0; i < 5; i++) { - auto last = std::find(p, end, 0); - if (last == end) { - return false; - } - spstr.push_back(std::string(p, last)); - p += spstr.back().size() + 1; - } - int i = 0; - memcpy(category, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(category)-1)); i++; - memcpy(subcategory, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(subcategory)-1)); i++; - memcpy(name, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(name)-1)); i++; - memcpy(url, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(url)-1)); i++; - memcpy(data, spstr[i].c_str(), std::min(spstr[i].length(), sizeof(data)-1)); i++; - - if (version == 1) { - memcpy(&sigmaStatus, p, 1); - p += 1; - } - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t ecosystem: %d\n", ecosystem); - PrintToLog("\t property type: %d (%s)\n", prop_type, strPropertyType(prop_type)); - PrintToLog("\tprev property id: %d\n", prev_prop_id); - PrintToLog("\t category: %s\n", category); - PrintToLog("\t subcategory: %s\n", subcategory); - PrintToLog("\t name: %s\n", name); - PrintToLog("\t url: %s\n", url); - PrintToLog("\t data: %s\n", data); - PrintToLog("\t sigma status: %u\n", static_cast(sigmaStatus)); - } - - if (isOverrun(p)) { - PrintToLog("%s(): rejected: malformed string value(s)\n", __func__); - return false; - } - - return true; -} - -/** Tx 55 */ -bool CMPTransaction::interpret_GrantTokens() -{ - if (raw.size() < 16) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value: %s\n", FormatMP(property, nValue)); - } - - return true; -} - -/** Tx 56 */ -bool CMPTransaction::interpret_RevokeTokens() -{ - if (raw.size() < 16) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value: %s\n", FormatMP(property, nValue)); - } - - return true; -} - -/** Tx 70 */ -bool CMPTransaction::interpret_ChangeIssuer() -{ - if (raw.size() < 8) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - } - - return true; -} - -/** Tx 71 */ -bool CMPTransaction::interpret_EnableFreezing() -{ - if (raw.size() < 8) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - } - - return true; -} - -/** Tx 72 */ -bool CMPTransaction::interpret_DisableFreezing() -{ - if (raw.size() < 8) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - } - - return true; -} - -/** Tx 185 */ -bool CMPTransaction::interpret_FreezeTokens() -{ - if (raw.size() < 37) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - - /** - Note, TX185 is a virtual reference transaction type. - With virtual reference transactions a hash160 in the payload sets the receiver. - Reference outputs are ignored. - **/ - unsigned char address_version; - uint160 address_hash160; - memcpy(&address_version, &raw[16], 1); - memcpy(&address_hash160, &raw[17], 20); - receiver = HashToAddress(address_version, address_hash160); - if (receiver.empty()) { - return false; - } - CBitcoinAddress recAddress(receiver); - if (!recAddress.IsValid()) { - return false; - } - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value (unused): %s\n", FormatMP(property, nValue)); - PrintToLog("\t address: %s\n", receiver); - } - - return true; -} - -/** Tx 186 */ -bool CMPTransaction::interpret_UnfreezeTokens() -{ - if (raw.size() < 37) { - return false; - } - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - nNewValue = nValue; - - /** - Note, TX186 virtual reference transaction type. - With virtual reference transactions a hash160 in the payload sets the receiver. - Reference outputs are ignored. - **/ - unsigned char address_version; - uint160 address_hash160; - memcpy(&address_version, &raw[16], 1); - memcpy(&address_hash160, &raw[17], 20); - receiver = HashToAddress(address_version, address_hash160); - if (receiver.empty()) { - return false; - } - CBitcoinAddress recAddress(receiver); - if (!recAddress.IsValid()) { - return false; - } - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value (unused): %s\n", FormatMP(property, nValue)); - PrintToLog("\t address: %s\n", receiver); - } - - return true; -} - -/** Tx 1024 */ -bool CMPTransaction::interpret_SimpleSpend() -{ - if (raw.size() < 15) { - return false; - } - - memcpy(&property, &raw[4], 4); - swapByteOrder(property); - memcpy(&denomination, &raw[8], 1); - memcpy(&group, &raw[9], 4); - swapByteOrder(group); - memcpy(&groupSize, &raw[13], 2); - swapByteOrder(groupSize); - - CDataStream serialized( - reinterpret_cast(&raw[15]), - reinterpret_cast(raw.data() + raw.size()), - SER_NETWORK, PROTOCOL_VERSION - ); - - spend.reset(new SigmaProof(DefaultSigmaParams)); - serial.reset(new secp_primitives::Scalar()); - try { - if (version == MP_TX_PKT_V1) { - std::array pubkeyBuffer; - serialized.read(reinterpret_cast(pubkeyBuffer.data()), pubkeyBuffer.size()); - ecdsaPubkey.Set(pubkeyBuffer.begin(), pubkeyBuffer.end()); - - serialized >> *spend; - serialized >> ecdsaSignature; - - // Calculate serial. - uint256 hash; - CSHA256() - .Write(ecdsaPubkey.begin(), ecdsaPubkey.size()) - .Finalize(hash.begin()); - - serial->memberFromSeed(hash.begin()); - } else { - serialized >> *serial; - serialized >> *spend; - } - } catch (std::ios_base::failure&) { - PrintToLog("\tsize of data is less than spend size"); - return false; - } - - if (!serialized.eof()) { - PrintToLog("\tsize of data exceed spend size"); - return false; - } - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t spend: %s\n", std::to_string(denomination)); - } - - return true; -} - -/** Tx 1025 */ -bool CMPTransaction::interpret_CreateDenomination() -{ - if (raw.size() < 16) { - return false; - } - - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - memcpy(&nValue, &raw[8], 8); - swapByteOrder64(nValue); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t value: %s\n", FormatMP(property, nValue)); - } - - return true; -} - -/** Tx 1026 */ -bool CMPTransaction::interpret_SimpleMint() -{ - constexpr unsigned elysiumMintSize = 35; - - if (raw.size() < 9 + elysiumMintSize) { - return false; - } - - memcpy(&property, &raw[4], 4); - swapByteOrder32(property); - - uint8_t mintAmount; - memcpy(&mintAmount, &raw[8], 1); - - if (raw.size() != 9 + elysiumMintSize * mintAmount) { - return false; - } - - mints.resize(mintAmount); - CDataStream deserialized( - reinterpret_cast(&raw[9]), - reinterpret_cast(raw.data() + raw.size()), - SER_NETWORK, CLIENT_VERSION - ); - - for (auto &mint : mints) { - deserialized >> mint; - } - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - std::vector denominations; - denominations.reserve(mints.size()); - for (auto const& mint : mints) { - denominations.push_back(mint.first); - } - std::sort(denominations.begin(), denominations.end()); - - std::stringstream ss; - for (auto const &denom : denominations) { - ss << denom << ", "; - } - auto denomsStr = ss.str(); - denomsStr.resize(denomsStr.size() - 2); - - PrintToLog("\t property: %d (%s)\n", property, strMPProperty(property)); - PrintToLog("\t mints: %s\n", denomsStr); - } - - return true; -} - -/** Tx 65533 */ -bool CMPTransaction::interpret_Deactivation() -{ - if (raw.size() < 6) { - return false; - } - memcpy(&feature_id, &raw[4], 2); - swapByteOrder16(feature_id); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t feature id: %d\n", feature_id); - } - - return true; -} - -/** Tx 65534 */ -bool CMPTransaction::interpret_Activation() -{ - if (raw.size() < 14) { - return false; - } - memcpy(&feature_id, &raw[4], 2); - swapByteOrder16(feature_id); - memcpy(&activation_block, &raw[6], 4); - swapByteOrder32(activation_block); - memcpy(&min_client_version, &raw[10], 4); - swapByteOrder32(min_client_version); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t feature id: %d\n", feature_id); - PrintToLog("\tactivation block: %d\n", activation_block); - PrintToLog("\t minimum version: %d\n", min_client_version); - } - - return true; -} - -/** Tx 65535 */ -bool CMPTransaction::interpret_Alert() -{ - if (raw.size() < 11) { - return false; - } - - memcpy(&alert_type, &raw[4], 2); - swapByteOrder16(alert_type); - memcpy(&alert_expiry, &raw[6], 4); - swapByteOrder32(alert_expiry); - - auto p = raw.data() + 10; - auto end = raw.data() + raw.size(); - auto last = std::find(p, end, 0); - if (last == end) { - return false; - } - std::string spstr(p, last); - memcpy(alert_text, spstr.c_str(), std::min(spstr.length(), sizeof(alert_text)-1)); - - if ((!rpcOnly && elysium_debug_packets) || elysium_debug_packets_readonly) { - PrintToLog("\t alert type: %d\n", alert_type); - PrintToLog("\t expiry value: %d\n", alert_expiry); - PrintToLog("\t alert message: %s\n", alert_text); - } - - if (isOverrun(p)) { - PrintToLog("%s(): rejected: malformed string value(s)\n", __func__); - return false; - } - - return true; -} - -// ---------------------- CORE LOGIC ------------------------- - -/** - * Interprets the payload and executes the logic. - * - * @return 0 if the transaction is fully valid - * <0 if the transaction is invalid - */ -int CMPTransaction::interpretPacket() -{ - if (rpcOnly) { - PrintToLog("%s(): ERROR: attempt to execute logic in RPC mode\n", __func__); - return (PKT_ERROR -1); - } - - if (!interpret_Transaction()) { - return (PKT_ERROR -2); - } - - LOCK(cs_main); - - if (isAddressFrozen(sender, property)) { - PrintToLog("%s(): REJECTED: address %s is frozen for property %d\n", __func__, sender, property); - return (PKT_ERROR -3); - } - - int status; - switch (type) { - case ELYSIUM_TYPE_SIMPLE_SEND: - status = logicMath_SimpleSend(); - break; - - case ELYSIUM_TYPE_SEND_TO_OWNERS: - status = logicMath_SendToOwners(); - break; - - case ELYSIUM_TYPE_SEND_ALL: - status = logicMath_SendAll(); - break; - - case ELYSIUM_TYPE_TRADE_OFFER: - status = logicMath_TradeOffer(); - break; - - case ELYSIUM_TYPE_ACCEPT_OFFER_BTC: - status = logicMath_AcceptOffer_BTC(); - break; - - case ELYSIUM_TYPE_METADEX_TRADE: - status = logicMath_MetaDExTrade(); - break; - - case ELYSIUM_TYPE_METADEX_CANCEL_PRICE: - status = logicMath_MetaDExCancelPrice(); - break; - - case ELYSIUM_TYPE_METADEX_CANCEL_PAIR: - status = logicMath_MetaDExCancelPair(); - break; - - case ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM: - status = logicMath_MetaDExCancelEcosystem(); - break; - - case ELYSIUM_TYPE_CREATE_PROPERTY_FIXED: - status = logicMath_CreatePropertyFixed(); - break; - - case ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE: - status = logicMath_CreatePropertyVariable(); - break; - - case ELYSIUM_TYPE_CLOSE_CROWDSALE: - status = logicMath_CloseCrowdsale(); - break; - - case ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL: - status = logicMath_CreatePropertyManaged(); - break; - - case ELYSIUM_TYPE_GRANT_PROPERTY_TOKENS: - status = logicMath_GrantTokens(); - break; - - case ELYSIUM_TYPE_REVOKE_PROPERTY_TOKENS: - status = logicMath_RevokeTokens(); - break; - - case ELYSIUM_TYPE_CHANGE_ISSUER_ADDRESS: - status = logicMath_ChangeIssuer(); - break; - - case ELYSIUM_TYPE_ENABLE_FREEZING: - status = logicMath_EnableFreezing(); - break; - - case ELYSIUM_TYPE_DISABLE_FREEZING: - status = logicMath_DisableFreezing(); - break; - - case ELYSIUM_TYPE_FREEZE_PROPERTY_TOKENS: - status = logicMath_FreezeTokens(); - break; - - case ELYSIUM_TYPE_UNFREEZE_PROPERTY_TOKENS: - status = logicMath_UnfreezeTokens(); - break; - - case ELYSIUM_TYPE_CREATE_DENOMINATION: - status = logicMath_CreateDenomination(); - break; - - case ELYSIUM_MESSAGE_TYPE_DEACTIVATION: - status = logicMath_Deactivation(); - break; - - case ELYSIUM_MESSAGE_TYPE_ACTIVATION: - status = logicMath_Activation(); - break; - - case ELYSIUM_MESSAGE_TYPE_ALERT: - status = logicMath_Alert(); - break; - - default: - return (PKT_ERROR -100); - } - - return status; -} - -/** Passive effect of crowdsale participation. */ -int CMPTransaction::logicHelper_CrowdsaleParticipation() -{ - CMPCrowd* pcrowdsale = getCrowd(receiver); - - // No active crowdsale - if (pcrowdsale == NULL) { - return (PKT_ERROR_CROWD -1); - } - // Active crowdsale, but not for this property - if (pcrowdsale->getCurrDes() != property) { - return (PKT_ERROR_CROWD -2); - } - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(pcrowdsale->getPropertyId(), sp)); - PrintToLog("INVESTMENT SEND to Crowdsale Issuer: %s\n", receiver); - - // Holds the tokens to be credited to the sender and issuer - std::pair tokens; - - // Passed by reference to determine, if max_tokens has been reached - bool close_crowdsale = false; - - // Units going into the calculateFundraiser function must match the unit of - // the fundraiser's property_type. By default this means satoshis in and - // satoshis out. In the condition that the fundraiser is divisible, but - // indivisible tokens are accepted, it must account for .0 Div != 1 Indiv, - // but actually 1.0 Div == 100000000 Indiv. The unit must be shifted or the - // values will be incorrect, which is what is checked below. - bool inflateAmount = isPropertyDivisible(property) ? false : true; - - // Calculate the amounts to credit for this fundraiser - calculateFundraiser(inflateAmount, nValue, sp.early_bird, sp.deadline, blockTime, - sp.num_tokens, sp.percentage, getTotalTokens(pcrowdsale->getPropertyId()), - tokens, close_crowdsale); - - if (elysium_debug_sp) { - PrintToLog("%s(): granting via crowdsale to user: %s %d (%s)\n", - __func__, FormatMP(property, tokens.first), property, strMPProperty(property)); - PrintToLog("%s(): granting via crowdsale to issuer: %s %d (%s)\n", - __func__, FormatMP(property, tokens.second), property, strMPProperty(property)); - } - - // Update the crowdsale object - pcrowdsale->incTokensUserCreated(tokens.first); - pcrowdsale->incTokensIssuerCreated(tokens.second); - - // Data to pass to txFundraiserData - int64_t txdata[] = {(int64_t) nValue, blockTime, tokens.first, tokens.second}; - std::vector txDataVec(txdata, txdata + sizeof(txdata) / sizeof(txdata[0])); - - // Insert data about crowdsale participation - pcrowdsale->insertDatabase(txid, txDataVec); - - // Credit tokens for this fundraiser - if (tokens.first > 0) { - assert(update_tally_map(sender, pcrowdsale->getPropertyId(), tokens.first, BALANCE)); - } - if (tokens.second > 0) { - assert(update_tally_map(receiver, pcrowdsale->getPropertyId(), tokens.second, BALANCE)); - } - - // Number of tokens has changed, update fee distribution thresholds - NotifyTotalTokensChanged(pcrowdsale->getPropertyId(), block); - - // Close crowdsale, if we hit MAX_TOKENS - if (close_crowdsale) { - eraseMaxedCrowdsale(receiver, blockTime, block); - } - - // Indicate, if no tokens were transferred - if (!tokens.first && !tokens.second) { - return (PKT_ERROR_CROWD -3); - } - - return 0; -} - -/** Tx 0 */ -int CMPTransaction::logicMath_SimpleSend() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_SEND -22); - } - - if (nValue <= 0 || MAX_INT_8_BYTES < nValue) { - PrintToLog("%s(): rejected: value out of range or zero: %d", __func__, nValue); - return (PKT_ERROR_SEND -23); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_SEND -24); - } - - int64_t nBalance = getMPbalance(sender, property, BALANCE); - if (nBalance < (int64_t) nValue) { - PrintToLog("%s(): rejected: sender %s has insufficient balance of property %d [%s < %s]\n", - __func__, - sender, - property, - FormatMP(property, nBalance), - FormatMP(property, nValue)); - return (PKT_ERROR_SEND -25); - } - - // ------------------------------------------ - - // Special case: if can't find the receiver -- assume send to self! - if (receiver.empty()) { - receiver = sender; - } - - // Move the tokens - assert(update_tally_map(sender, property, -nValue, BALANCE)); - assert(update_tally_map(receiver, property, nValue, BALANCE)); - - // Is there an active crowdsale running from this recepient? - logicHelper_CrowdsaleParticipation(); - - return 0; -} - -/** Tx 3 */ -int CMPTransaction::logicMath_SendToOwners() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_STO -22); - } - - if (nValue <= 0 || MAX_INT_8_BYTES < nValue) { - PrintToLog("%s(): rejected: value out of range or zero: %d\n", __func__, nValue); - return (PKT_ERROR_STO -23); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_STO -24); - } - - if (version > MP_TX_PKT_V0) { - if (!IsPropertyIdValid(distribution_property)) { - PrintToLog("%s(): rejected: distribution property %d does not exist\n", __func__, distribution_property); - return (PKT_ERROR_STO -24); - } - } - - int64_t nBalance = getMPbalance(sender, property, BALANCE); - if (nBalance < (int64_t) nValue) { - PrintToLog("%s(): rejected: sender %s has insufficient balance of property %d [%s < %s]\n", - __func__, - sender, - FormatMP(property, nBalance), - FormatMP(property, nValue), - property); - return (PKT_ERROR_STO -25); - } - - // ------------------------------------------ - - uint32_t distributeTo = (version == MP_TX_PKT_V0) ? property : distribution_property; - OwnerAddrType receiversSet = STO_GetReceivers(sender, distributeTo, nValue); - uint64_t numberOfReceivers = receiversSet.size(); - - // make sure we found some owners - if (numberOfReceivers <= 0) { - PrintToLog("%s(): rejected: no other owners of property %d [owners=%d <= 0]\n", __func__, distributeTo, numberOfReceivers); - return (PKT_ERROR_STO -26); - } - - // split up what was taken and distribute between all holders - int64_t sent_so_far = 0; - for (OwnerAddrType::reverse_iterator it = receiversSet.rbegin(); it != receiversSet.rend(); ++it) { - const std::string& address = it->second; - - int64_t will_really_receive = it->first; - sent_so_far += will_really_receive; - - // real execution of the loop - assert(update_tally_map(sender, property, -will_really_receive, BALANCE)); - assert(update_tally_map(address, property, will_really_receive, BALANCE)); - - // add to stodb - s_stolistdb->recordSTOReceive(address, txid, block, property, will_really_receive); - - if (sent_so_far != (int64_t)nValue) { - PrintToLog("sent_so_far= %14d, nValue= %14d, n_owners= %d\n", sent_so_far, nValue, numberOfReceivers); - } else { - PrintToLog("SendToOwners: DONE HERE\n"); - } - } - - // sent_so_far must equal nValue here - assert(sent_so_far == (int64_t)nValue); - - // Number of tokens has changed, update fee distribution thresholds - if (version == MP_TX_PKT_V0) NotifyTotalTokensChanged(ELYSIUM_PROPERTY_ELYSIUM, block); // fee was burned - - return 0; -} - -/** Tx 4 */ -int CMPTransaction::logicMath_SendAll() -{ - if (!IsTransactionTypeAllowed(block, ecosystem, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - ecosystem, - block); - return (PKT_ERROR_SEND_ALL -22); - } - - // ------------------------------------------ - - // Special case: if can't find the receiver -- assume send to self! - if (receiver.empty()) { - receiver = sender; - } - - CMPTally* ptally = getTally(sender); - if (ptally == NULL) { - PrintToLog("%s(): rejected: sender %s has no tokens to send\n", __func__, sender); - return (PKT_ERROR_SEND_ALL -54); - } - - uint32_t propertyId = ptally->init(); - int numberOfPropertiesSent = 0; - - while (0 != (propertyId = ptally->next())) { - // only transfer tokens in the specified ecosystem - if (ecosystem == ELYSIUM_PROPERTY_ELYSIUM && isTestEcosystemProperty(propertyId)) { - continue; - } - if (ecosystem == ELYSIUM_PROPERTY_TELYSIUM && isMainEcosystemProperty(propertyId)) { - continue; - } - - // do not transfer tokens from a frozen property - if (isAddressFrozen(sender, propertyId)) { - PrintToLog("%s(): sender %s is frozen for property %d - the property will not be included in processing.\n", __func__, sender, propertyId); - continue; - } - - int64_t moneyAvailable = ptally->getMoney(propertyId, BALANCE); - if (moneyAvailable > 0) { - ++numberOfPropertiesSent; - assert(update_tally_map(sender, propertyId, -moneyAvailable, BALANCE)); - assert(update_tally_map(receiver, propertyId, moneyAvailable, BALANCE)); - p_txlistdb->recordSendAllSubRecord(txid, numberOfPropertiesSent, propertyId, moneyAvailable); - } - } - - if (!numberOfPropertiesSent) { - PrintToLog("%s(): rejected: sender %s has no tokens to send\n", __func__, sender); - return (PKT_ERROR_SEND_ALL -55); - } - - nNewValue = numberOfPropertiesSent; - - return 0; -} - -/** Tx 20 */ -int CMPTransaction::logicMath_TradeOffer() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_TRADEOFFER -22); - } - - if (MAX_INT_8_BYTES < nValue) { - PrintToLog("%s(): rejected: value out of range or zero: %d\n", __func__, nValue); - return (PKT_ERROR_TRADEOFFER -23); - } - - if (ELYSIUM_PROPERTY_TELYSIUM != property && ELYSIUM_PROPERTY_ELYSIUM != property) { - PrintToLog("%s(): rejected: property for sale %d must be ELYSIUM or TELYSIUM\n", __func__, property); - return (PKT_ERROR_TRADEOFFER -47); - } - - // ------------------------------------------ - - int rc = PKT_ERROR_TRADEOFFER; - - // figure out which Action this is based on amount for sale, version & etc. - switch (version) - { - case MP_TX_PKT_V0: - { - if (0 != nValue) { - if (!DEx_offerExists(sender, property)) { - rc = DEx_offerCreate(sender, property, nValue, block, amount_desired, min_fee, blocktimelimit, txid, &nNewValue); - } else { - rc = DEx_offerUpdate(sender, property, nValue, block, amount_desired, min_fee, blocktimelimit, txid, &nNewValue); - } - } else { - // what happens if nValue is 0 for V0 ? ANSWER: check if exists and it does -- cancel, otherwise invalid - if (DEx_offerExists(sender, property)) { - rc = DEx_offerDestroy(sender, property); - } else { - PrintToLog("%s(): rejected: sender %s has no active sell offer for property: %d\n", __func__, sender, property); - rc = (PKT_ERROR_TRADEOFFER -49); - } - } - - break; - } - - case MP_TX_PKT_V1: - { - if (DEx_offerExists(sender, property)) { - if (CANCEL != subaction && UPDATE != subaction) { - PrintToLog("%s(): rejected: sender %s has an active sell offer for property: %d\n", __func__, sender, property); - rc = (PKT_ERROR_TRADEOFFER -48); - break; - } - } else { - // Offer does not exist - if (NEW != subaction) { - PrintToLog("%s(): rejected: sender %s has no active sell offer for property: %d\n", __func__, sender, property); - rc = (PKT_ERROR_TRADEOFFER -49); - break; - } - } - - switch (subaction) { - case NEW: - rc = DEx_offerCreate(sender, property, nValue, block, amount_desired, min_fee, blocktimelimit, txid, &nNewValue); - break; - - case UPDATE: - rc = DEx_offerUpdate(sender, property, nValue, block, amount_desired, min_fee, blocktimelimit, txid, &nNewValue); - break; - - case CANCEL: - rc = DEx_offerDestroy(sender, property); - break; - - default: - rc = (PKT_ERROR -999); - break; - } - break; - } - - default: - rc = (PKT_ERROR -500); // neither V0 nor V1 - break; - }; - - return rc; -} - -/** Tx 22 */ -int CMPTransaction::logicMath_AcceptOffer_BTC() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (DEX_ERROR_ACCEPT -22); - } - - if (nValue <= 0 || MAX_INT_8_BYTES < nValue) { - PrintToLog("%s(): rejected: value out of range or zero: %d\n", __func__, nValue); - return (DEX_ERROR_ACCEPT -23); - } - - // ------------------------------------------ - - // the min fee spec requirement is checked in the following function - int rc = DEx_acceptCreate(sender, receiver, property, nValue, block, tx_fee_paid, &nNewValue); - - return rc; -} - -/** Tx 25 */ -int CMPTransaction::logicMath_MetaDExTrade() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_METADEX -22); - } - - if (property == desired_property) { - PrintToLog("%s(): rejected: property for sale %d and desired property %d must not be equal\n", - __func__, - property, - desired_property); - return (PKT_ERROR_METADEX -29); - } - - if (isTestEcosystemProperty(property) != isTestEcosystemProperty(desired_property)) { - PrintToLog("%s(): rejected: property for sale %d and desired property %d not in same ecosystem\n", - __func__, - property, - desired_property); - return (PKT_ERROR_METADEX -30); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property for sale %d does not exist\n", __func__, property); - return (PKT_ERROR_METADEX -31); - } - - if (!IsPropertyIdValid(desired_property)) { - PrintToLog("%s(): rejected: desired property %d does not exist\n", __func__, desired_property); - return (PKT_ERROR_METADEX -32); - } - - if (nNewValue <= 0 || MAX_INT_8_BYTES < nNewValue) { - PrintToLog("%s(): rejected: amount for sale out of range or zero: %d\n", __func__, nNewValue); - return (PKT_ERROR_METADEX -33); - } - - if (desired_value <= 0 || MAX_INT_8_BYTES < desired_value) { - PrintToLog("%s(): rejected: desired amount out of range or zero: %d\n", __func__, desired_value); - return (PKT_ERROR_METADEX -34); - } - - if (!IsFeatureActivated(FEATURE_TRADEALLPAIRS, block)) { - // Trading non-Elysium pairs is not allowed before trading all pairs is activated - if ((property != ELYSIUM_PROPERTY_ELYSIUM) && (desired_property != ELYSIUM_PROPERTY_ELYSIUM) && - (property != ELYSIUM_PROPERTY_TELYSIUM) && (desired_property != ELYSIUM_PROPERTY_TELYSIUM)) { - PrintToLog("%s(): rejected: one side of a trade [%d, %d] must be ELYSIUM or TELYSIUM\n", __func__, property, desired_property); - return (PKT_ERROR_METADEX -35); - } - } - - int64_t nBalance = getMPbalance(sender, property, BALANCE); - if (nBalance < (int64_t) nNewValue) { - PrintToLog("%s(): rejected: sender %s has insufficient balance of property %d [%s < %s]\n", - __func__, - sender, - property, - FormatMP(property, nBalance), - FormatMP(property, nNewValue)); - return (PKT_ERROR_METADEX -25); - } - - // ------------------------------------------ - - t_tradelistdb->recordNewTrade(txid, sender, property, desired_property, block, tx_idx); - int rc = MetaDEx_ADD(sender, property, nNewValue, block, desired_property, desired_value, txid, tx_idx); - return rc; -} - -/** Tx 26 */ -int CMPTransaction::logicMath_MetaDExCancelPrice() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_METADEX -22); - } - - if (property == desired_property) { - PrintToLog("%s(): rejected: property for sale %d and desired property %d must not be equal\n", - __func__, - property, - desired_property); - return (PKT_ERROR_METADEX -29); - } - - if (isTestEcosystemProperty(property) != isTestEcosystemProperty(desired_property)) { - PrintToLog("%s(): rejected: property for sale %d and desired property %d not in same ecosystem\n", - __func__, - property, - desired_property); - return (PKT_ERROR_METADEX -30); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property for sale %d does not exist\n", __func__, property); - return (PKT_ERROR_METADEX -31); - } - - if (!IsPropertyIdValid(desired_property)) { - PrintToLog("%s(): rejected: desired property %d does not exist\n", __func__, desired_property); - return (PKT_ERROR_METADEX -32); - } - - if (nNewValue <= 0 || MAX_INT_8_BYTES < nNewValue) { - PrintToLog("%s(): rejected: amount for sale out of range or zero: %d\n", __func__, nNewValue); - return (PKT_ERROR_METADEX -33); - } - - if (desired_value <= 0 || MAX_INT_8_BYTES < desired_value) { - PrintToLog("%s(): rejected: desired amount out of range or zero: %d\n", __func__, desired_value); - return (PKT_ERROR_METADEX -34); - } - - // ------------------------------------------ - - int rc = MetaDEx_CANCEL_AT_PRICE(txid, block, sender, property, nNewValue, desired_property, desired_value); - - return rc; -} - -/** Tx 27 */ -int CMPTransaction::logicMath_MetaDExCancelPair() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_METADEX -22); - } - - if (property == desired_property) { - PrintToLog("%s(): rejected: property for sale %d and desired property %d must not be equal\n", - __func__, - property, - desired_property); - return (PKT_ERROR_METADEX -29); - } - - if (isTestEcosystemProperty(property) != isTestEcosystemProperty(desired_property)) { - PrintToLog("%s(): rejected: property for sale %d and desired property %d not in same ecosystem\n", - __func__, - property, - desired_property); - return (PKT_ERROR_METADEX -30); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property for sale %d does not exist\n", __func__, property); - return (PKT_ERROR_METADEX -31); - } - - if (!IsPropertyIdValid(desired_property)) { - PrintToLog("%s(): rejected: desired property %d does not exist\n", __func__, desired_property); - return (PKT_ERROR_METADEX -32); - } - - // ------------------------------------------ - - int rc = MetaDEx_CANCEL_ALL_FOR_PAIR(txid, block, sender, property, desired_property); - - return rc; -} - -/** Tx 28 */ -int CMPTransaction::logicMath_MetaDExCancelEcosystem() -{ - if (!IsTransactionTypeAllowed(block, ecosystem, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_METADEX -22); - } - - if (ELYSIUM_PROPERTY_ELYSIUM != ecosystem && ELYSIUM_PROPERTY_TELYSIUM != ecosystem) { - PrintToLog("%s(): rejected: invalid ecosystem: %d\n", __func__, ecosystem); - return (PKT_ERROR_METADEX -21); - } - - int rc = MetaDEx_CANCEL_EVERYTHING(txid, block, sender, ecosystem); - - return rc; -} - -/** Tx 50 */ -int CMPTransaction::logicMath_CreatePropertyFixed() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_SP -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (ELYSIUM_PROPERTY_ELYSIUM != ecosystem && ELYSIUM_PROPERTY_TELYSIUM != ecosystem) { - PrintToLog("%s(): rejected: invalid ecosystem: %d\n", __func__, (uint32_t) ecosystem); - return (PKT_ERROR_SP -21); - } - - if (!IsTransactionTypeAllowed(block, ecosystem, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_SP -22); - } - - if (nValue <= 0 || MAX_INT_8_BYTES < nValue) { - PrintToLog("%s(): rejected: value out of range or zero: %d\n", __func__, nValue); - return (PKT_ERROR_SP -23); - } - - if (ELYSIUM_PROPERTY_TYPE_INDIVISIBLE != prop_type && ELYSIUM_PROPERTY_TYPE_DIVISIBLE != prop_type) { - PrintToLog("%s(): rejected: invalid property type: %d\n", __func__, prop_type); - return (PKT_ERROR_SP -36); - } - - if ('\0' == name[0]) { - PrintToLog("%s(): rejected: property name must not be empty\n", __func__); - return (PKT_ERROR_SP -37); - } - - if (IsRequireCreationFee(ecosystem, block) && !CheckPropertyCreationFee()) { - PrintToLog("%s(): rejected: not enough fee for property creation\n", __func__); - return PKT_ERROR_SP - 105; - } - - CMPSPInfo::Entry newSP; - - if (IsFeatureActivated(FEATURE_SIGMA, block)) { - if (!IsSigmaStatusValid(sigmaStatus)) { - PrintToLog("%s(): rejected: sigma status %u is not valid\n", __func__, static_cast(sigmaStatus)); - return PKT_ERROR_SP - 900; - } - - newSP.sigmaStatus = sigmaStatus; - } - - // ------------------------------------------ - - newSP.issuer = sender; - newSP.txid = txid; - newSP.prop_type = prop_type; - newSP.num_tokens = nValue; - newSP.category.assign(category); - newSP.subcategory.assign(subcategory); - newSP.name.assign(name); - newSP.url.assign(url); - newSP.data.assign(data); - newSP.fixed = true; - newSP.creation_block = blockHash; - newSP.update_block = newSP.creation_block; - - const uint32_t propertyId = _my_sps->putSP(ecosystem, newSP); - assert(propertyId > 0); - assert(update_tally_map(sender, propertyId, nValue, BALANCE)); - - NotifyTotalTokensChanged(propertyId, block); - - return 0; -} - -/** Tx 51 */ -int CMPTransaction::logicMath_CreatePropertyVariable() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_SP -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (ELYSIUM_PROPERTY_ELYSIUM != ecosystem && ELYSIUM_PROPERTY_TELYSIUM != ecosystem) { - PrintToLog("%s(): rejected: invalid ecosystem: %d\n", __func__, (uint32_t) ecosystem); - return (PKT_ERROR_SP -21); - } - - if (IsFeatureActivated(FEATURE_SPCROWDCROSSOVER, block)) { - /** - * Ecosystem crossovers shall not be allowed after the feature was enabled. - */ - if (isTestEcosystemProperty(ecosystem) != isTestEcosystemProperty(property)) { - PrintToLog("%s(): rejected: ecosystem %d of tokens to issue and desired property %d not in same ecosystem\n", - __func__, - ecosystem, - property); - return (PKT_ERROR_SP -50); - } - } - - if (!IsTransactionTypeAllowed(block, ecosystem, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_SP -22); - } - - if (nValue <= 0 || MAX_INT_8_BYTES < nValue) { - PrintToLog("%s(): rejected: value out of range or zero: %d\n", __func__, nValue); - return (PKT_ERROR_SP -23); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_SP -24); - } - - if (ELYSIUM_PROPERTY_TYPE_INDIVISIBLE != prop_type && ELYSIUM_PROPERTY_TYPE_DIVISIBLE != prop_type) { - PrintToLog("%s(): rejected: invalid property type: %d\n", __func__, prop_type); - return (PKT_ERROR_SP -36); - } - - if ('\0' == name[0]) { - PrintToLog("%s(): rejected: property name must not be empty\n", __func__); - return (PKT_ERROR_SP -37); - } - - if (!deadline || (int64_t) deadline < blockTime) { - PrintToLog("%s(): rejected: deadline must not be in the past [%d < %d]\n", __func__, deadline, blockTime); - return (PKT_ERROR_SP -38); - } - - if (NULL != getCrowd(sender)) { - PrintToLog("%s(): rejected: sender %s has an active crowdsale\n", __func__, sender); - return (PKT_ERROR_SP -39); - } - - if (IsRequireCreationFee(ecosystem, block) && !CheckPropertyCreationFee()) { - PrintToLog("%s(): rejected: not enough fee for property creation\n", __func__); - return PKT_ERROR_SP - 105; - } - - // ------------------------------------------ - - CMPSPInfo::Entry newSP; - newSP.issuer = sender; - newSP.txid = txid; - newSP.prop_type = prop_type; - newSP.num_tokens = nValue; - newSP.category.assign(category); - newSP.subcategory.assign(subcategory); - newSP.name.assign(name); - newSP.url.assign(url); - newSP.data.assign(data); - newSP.fixed = false; - newSP.property_desired = property; - newSP.deadline = deadline; - newSP.early_bird = early_bird; - newSP.percentage = percentage; - newSP.creation_block = blockHash; - newSP.update_block = newSP.creation_block; - - const uint32_t propertyId = _my_sps->putSP(ecosystem, newSP); - assert(propertyId > 0); - my_crowds.insert(std::make_pair(sender, CMPCrowd(propertyId, nValue, property, deadline, early_bird, percentage, 0, 0))); - - PrintToLog("CREATED CROWDSALE id: %d value: %d property: %d\n", propertyId, nValue, property); - - return 0; -} - -/** Tx 53 */ -int CMPTransaction::logicMath_CloseCrowdsale() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_SP -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_SP -22); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_SP -24); - } - - CrowdMap::iterator it = my_crowds.find(sender); - if (it == my_crowds.end()) { - PrintToLog("%s(): rejected: sender %s has no active crowdsale\n", __func__, sender); - return (PKT_ERROR_SP -40); - } - - const CMPCrowd& crowd = it->second; - if (property != crowd.getPropertyId()) { - PrintToLog("%s(): rejected: property identifier mismatch [%d != %d]\n", __func__, property, crowd.getPropertyId()); - return (PKT_ERROR_SP -41); - } - - // ------------------------------------------ - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(property, sp)); - - int64_t missedTokens = GetMissedIssuerBonus(sp, crowd); - - sp.historicalData = crowd.getDatabase(); - sp.update_block = blockHash; - sp.close_early = true; - sp.timeclosed = blockTime; - sp.txid_close = txid; - sp.missedTokens = missedTokens; - - assert(_my_sps->updateSP(property, sp)); - if (missedTokens > 0) { - assert(update_tally_map(sp.issuer, property, missedTokens, BALANCE)); - } - my_crowds.erase(it); - - if (elysium_debug_sp) PrintToLog("CLOSED CROWDSALE id: %d=%X\n", property, property); - - return 0; -} - -/** Tx 54 */ -int CMPTransaction::logicMath_CreatePropertyManaged() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_SP -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (ELYSIUM_PROPERTY_ELYSIUM != ecosystem && ELYSIUM_PROPERTY_TELYSIUM != ecosystem) { - PrintToLog("%s(): rejected: invalid ecosystem: %d\n", __func__, (uint32_t) ecosystem); - return (PKT_ERROR_SP -21); - } - - if (!IsTransactionTypeAllowed(block, ecosystem, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_SP -22); - } - - if (ELYSIUM_PROPERTY_TYPE_INDIVISIBLE != prop_type && ELYSIUM_PROPERTY_TYPE_DIVISIBLE != prop_type) { - PrintToLog("%s(): rejected: invalid property type: %d\n", __func__, prop_type); - return (PKT_ERROR_SP -36); - } - - if ('\0' == name[0]) { - PrintToLog("%s(): rejected: property name must not be empty\n", __func__); - return (PKT_ERROR_SP -37); - } - - if (IsRequireCreationFee(ecosystem, block) && !CheckPropertyCreationFee()) { - PrintToLog("%s(): rejected: not enough fee for property creation\n", __func__); - return PKT_ERROR_SP - 105; - } - - CMPSPInfo::Entry newSP; - - if (IsFeatureActivated(FEATURE_SIGMA, block)) { - if (!IsSigmaStatusValid(sigmaStatus)) { - PrintToLog("%s(): rejected: sigma status %u is not valid\n", __func__, static_cast(sigmaStatus)); - return PKT_ERROR_SP - 900; - } - - newSP.sigmaStatus = sigmaStatus; - } - - // ------------------------------------------ - - newSP.issuer = sender; - newSP.txid = txid; - newSP.prop_type = prop_type; - newSP.category.assign(category); - newSP.subcategory.assign(subcategory); - newSP.name.assign(name); - newSP.url.assign(url); - newSP.data.assign(data); - newSP.fixed = false; - newSP.manual = true; - newSP.creation_block = blockHash; - newSP.update_block = newSP.creation_block; - - uint32_t propertyId = _my_sps->putSP(ecosystem, newSP); - assert(propertyId > 0); - - PrintToLog("CREATED MANUAL PROPERTY id: %d admin: %s\n", propertyId, sender); - - return 0; -} - -/** Tx 55 */ -int CMPTransaction::logicMath_GrantTokens() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_SP -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_TOKENS -22); - } - - if (nValue <= 0 || MAX_INT_8_BYTES < nValue) { - PrintToLog("%s(): rejected: value out of range or zero: %d\n", __func__, nValue); - return (PKT_ERROR_TOKENS -23); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_TOKENS -24); - } - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(property, sp)); - - if (!sp.manual) { - PrintToLog("%s(): rejected: property %d is not managed\n", __func__, property); - return (PKT_ERROR_TOKENS -42); - } - - if (sender != sp.issuer) { - PrintToLog("%s(): rejected: sender %s is not issuer of property %d [issuer=%s]\n", __func__, sender, property, sp.issuer); - return (PKT_ERROR_TOKENS -43); - } - - int64_t nTotalTokens = getTotalTokens(property); - if (nValue > (MAX_INT_8_BYTES - nTotalTokens)) { - PrintToLog("%s(): rejected: no more than %s tokens can ever exist [%s + %s > %s]\n", - __func__, - FormatMP(property, MAX_INT_8_BYTES), - FormatMP(property, nTotalTokens), - FormatMP(property, nValue), - FormatMP(property, MAX_INT_8_BYTES)); - return (PKT_ERROR_TOKENS -44); - } - - // ------------------------------------------ - - std::vector dataPt; - dataPt.push_back(nValue); - dataPt.push_back(0); - sp.historicalData.insert(std::make_pair(txid, dataPt)); - sp.update_block = blockHash; - - // Persist the number of granted tokens - assert(_my_sps->updateSP(property, sp)); - - // Special case: if can't find the receiver -- assume grant to self! - if (receiver.empty()) { - receiver = sender; - } - - // Move the tokens - assert(update_tally_map(receiver, property, nValue, BALANCE)); - - /** - * As long as the feature to disable the side effects of "granting tokens" - * is not activated, "granting tokens" can trigger crowdsale participations. - */ - if (!IsFeatureActivated(FEATURE_GRANTEFFECTS, block)) { - // Is there an active crowdsale running from this recepient? - logicHelper_CrowdsaleParticipation(); - } - - NotifyTotalTokensChanged(property, block); - - return 0; -} - -/** Tx 56 */ -int CMPTransaction::logicMath_RevokeTokens() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_TOKENS -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_TOKENS -22); - } - - if (nValue <= 0 || MAX_INT_8_BYTES < nValue) { - PrintToLog("%s(): rejected: value out of range or zero: %d\n", __func__, nValue); - return (PKT_ERROR_TOKENS -23); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_TOKENS -24); - } - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(property, sp)); - - if (!sp.manual) { - PrintToLog("%s(): rejected: property %d is not managed\n", __func__, property); - return (PKT_ERROR_TOKENS -42); - } - - int64_t nBalance = getMPbalance(sender, property, BALANCE); - if (nBalance < (int64_t) nValue) { - PrintToLog("%s(): rejected: sender %s has insufficient balance of property %d [%s < %s]\n", - __func__, - sender, - property, - FormatMP(property, nBalance), - FormatMP(property, nValue)); - return (PKT_ERROR_TOKENS -25); - } - - // ------------------------------------------ - - std::vector dataPt; - dataPt.push_back(0); - dataPt.push_back(nValue); - sp.historicalData.insert(std::make_pair(txid, dataPt)); - sp.update_block = blockHash; - - assert(update_tally_map(sender, property, -nValue, BALANCE)); - assert(_my_sps->updateSP(property, sp)); - - NotifyTotalTokensChanged(property, block); - - return 0; -} - -/** Tx 70 */ -int CMPTransaction::logicMath_ChangeIssuer() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_TOKENS -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_TOKENS -22); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_TOKENS -24); - } - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(property, sp)); - - if (sender != sp.issuer) { - PrintToLog("%s(): rejected: sender %s is not issuer of property %d [issuer=%s]\n", __func__, sender, property, sp.issuer); - return (PKT_ERROR_TOKENS -43); - } - - if (NULL != getCrowd(sender)) { - PrintToLog("%s(): rejected: sender %s has an active crowdsale\n", __func__, sender); - return (PKT_ERROR_TOKENS -39); - } - - if (receiver.empty()) { - PrintToLog("%s(): rejected: receiver is empty\n", __func__); - return (PKT_ERROR_TOKENS -45); - } - - if (NULL != getCrowd(receiver)) { - PrintToLog("%s(): rejected: receiver %s has an active crowdsale\n", __func__, receiver); - return (PKT_ERROR_TOKENS -46); - } - - // ------------------------------------------ - - sp.issuer = receiver; - sp.update_block = blockHash; - - assert(_my_sps->updateSP(property, sp)); - - return 0; -} - -/** Tx 71 */ -int CMPTransaction::logicMath_EnableFreezing() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_TOKENS -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_TOKENS -22); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_TOKENS -24); - } - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(property, sp)); - - if (!sp.manual) { - PrintToLog("%s(): rejected: property %d is not managed\n", __func__, property); - return (PKT_ERROR_TOKENS -42); - } - - if (sender != sp.issuer) { - PrintToLog("%s(): rejected: sender %s is not issuer of property %d [issuer=%s]\n", __func__, sender, property, sp.issuer); - return (PKT_ERROR_TOKENS -43); - } - - if (isFreezingEnabled(property, block)) { - PrintToLog("%s(): rejected: freezing is already enabled for property %d\n", __func__, property); - return (PKT_ERROR_TOKENS -49); - } - - int liveBlock = 0; - if (!IsFeatureActivated(FEATURE_FREEZENOTICE, block)) { - liveBlock = block; - } else { - const CConsensusParams& params = ConsensusParams(); - liveBlock = params.ELYSIUM_FREEZE_WAIT_PERIOD + block; - } - - enableFreezing(property, liveBlock); - - return 0; -} - -/** Tx 72 */ -int CMPTransaction::logicMath_DisableFreezing() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_TOKENS -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_TOKENS -22); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_TOKENS -24); - } - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(property, sp)); - - if (!sp.manual) { - PrintToLog("%s(): rejected: property %d is not managed\n", __func__, property); - return (PKT_ERROR_TOKENS -42); - } - - if (sender != sp.issuer) { - PrintToLog("%s(): rejected: sender %s is not issuer of property %d [issuer=%s]\n", __func__, sender, property, sp.issuer); - return (PKT_ERROR_TOKENS -43); - } - - if (!isFreezingEnabled(property, block)) { - PrintToLog("%s(): rejected: freezing is not enabled for property %d\n", __func__, property); - return (PKT_ERROR_TOKENS -47); - } - - disableFreezing(property); - - return 0; -} - -/** Tx 185 */ -int CMPTransaction::logicMath_FreezeTokens() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_TOKENS -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_TOKENS -22); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_TOKENS -24); - } - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(property, sp)); - - if (!sp.manual) { - PrintToLog("%s(): rejected: property %d is not managed\n", __func__, property); - return (PKT_ERROR_TOKENS -42); - } - - if (sender != sp.issuer) { - PrintToLog("%s(): rejected: sender %s is not issuer of property %d [issuer=%s]\n", __func__, sender, property, sp.issuer); - return (PKT_ERROR_TOKENS -43); - } - - if (!isFreezingEnabled(property, block)) { - PrintToLog("%s(): rejected: freezing is not enabled for property %d\n", __func__, property); - return (PKT_ERROR_TOKENS -47); - } - - if (isAddressFrozen(receiver, property)) { - PrintToLog("%s(): rejected: address %s is already frozen for property %d\n", __func__, receiver, property); - return (PKT_ERROR_TOKENS -50); - } - - freezeAddress(receiver, property); - - return 0; -} - -/** Tx 186 */ -int CMPTransaction::logicMath_UnfreezeTokens() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_TOKENS -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR_TOKENS -22); - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return (PKT_ERROR_TOKENS -24); - } - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(property, sp)); - - if (!sp.manual) { - PrintToLog("%s(): rejected: property %d is not managed\n", __func__, property); - return (PKT_ERROR_TOKENS -42); - } - - if (sender != sp.issuer) { - PrintToLog("%s(): rejected: sender %s is not issuer of property %d [issuer=%s]\n", __func__, sender, property, sp.issuer); - return (PKT_ERROR_TOKENS -43); - } - - if (!isFreezingEnabled(property, block)) { - PrintToLog("%s(): rejected: freezing is not enabled for property %d\n", __func__, property); - return (PKT_ERROR_TOKENS -47); - } - - if (!isAddressFrozen(receiver, property)) { - PrintToLog("%s(): rejected: address %s is not frozen for property %d\n", __func__, receiver, property); - return (PKT_ERROR_TOKENS -48); - } - - unfreezeAddress(receiver, property); - - return 0; -} - -/** Tx 1025 */ -int CMPTransaction::logicMath_CreateDenomination() -{ - uint256 blockHash; - { - LOCK(cs_main); - - CBlockIndex* pindex = chainActive[block]; - if (pindex == NULL) { - PrintToLog("%s(): ERROR: block %d not in the active chain\n", __func__, block); - return (PKT_ERROR_TOKENS -20); - } - blockHash = pindex->GetBlockHash(); - } - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return PKT_ERROR_TOKENS - 22; - } - - if (!nValue || nValue > MAX_INT_8_BYTES) { - PrintToLog("%s(): rejected: value out of range or zero: %d", __func__, nValue); - return PKT_ERROR_TOKENS - 23; - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return PKT_ERROR_TOKENS - 24; - } - - CMPSPInfo::Entry sp; - assert(_my_sps->getSP(property, sp)); - - if (sender != sp.issuer) { - PrintToLog("%s(): rejected: sender %s is not issuer of property %d [issuer=%s]\n", __func__, sender, property, sp.issuer); - return PKT_ERROR_TOKENS - 43; - } - - if (sp.sigmaStatus != SigmaStatus::HardEnabled && sp.sigmaStatus != SigmaStatus::SoftEnabled) { - PrintToLog("%s(): rejected: sigma is not enabled for property %d\n", __func__, property); - return PKT_ERROR_TOKENS - 901; - } - - if (sp.denominations.size() >= MAX_DENOMINATIONS) { - PrintToLog("%s(): rejected: no more space for new denomination for property %d\n", __func__, property); - return PKT_ERROR_TOKENS - 902; - } - - if (std::find(sp.denominations.begin(), sp.denominations.end(), nValue) != sp.denominations.end()) { - PrintToLog( - "%s(): rejected: denomination with value %s is already exists for property %d\n", - __func__, - FormatMP(property, nValue), - property - ); - return PKT_ERROR_TOKENS - 903; - } - - sp.denominations.push_back(nValue); - sp.update_block = blockHash; - - assert(_my_sps->updateSP(property, sp)); - - return 0; -} - -/** Tx 65533 */ -int CMPTransaction::logicMath_Deactivation() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR -22); - } - - // is sender authorized - bool authorized = CheckDeactivationAuthorization(sender); - - PrintToLog("\t sender: %s\n", sender); - PrintToLog("\t authorized: %s\n", authorized); - - if (!authorized) { - PrintToLog("%s(): rejected: sender %s is not authorized to deactivate features\n", __func__, sender); - return (PKT_ERROR -51); - } - - // authorized, request feature deactivation - bool DeactivationSuccess = DeactivateFeature(feature_id, block); - - if (!DeactivationSuccess) { - PrintToLog("%s(): DeactivateFeature failed\n", __func__); - return (PKT_ERROR -54); - } - - // successful deactivation - did we deactivate the MetaDEx? If so close out all trades - if (feature_id == FEATURE_METADEX) { - MetaDEx_SHUTDOWN(); - } - if (feature_id == FEATURE_TRADEALLPAIRS) { - MetaDEx_SHUTDOWN_ALLPAIR(); - } - - return 0; -} - -/** Tx 65534 */ -int CMPTransaction::logicMath_Activation() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR -22); - } - - // is sender authorized - temporarily use alert auths but ## TO BE MOVED TO FOUNDATION P2SH KEY ## - bool authorized = CheckActivationAuthorization(sender); - - PrintToLog("\t sender: %s\n", sender); - PrintToLog("\t authorized: %s\n", authorized); - - if (!authorized) { - PrintToLog("%s(): rejected: sender %s is not authorized for feature activations\n", __func__, sender); - return (PKT_ERROR -51); - } - - // authorized, request feature activation - bool activationSuccess = ActivateFeature(feature_id, activation_block, min_client_version, block); - - if (!activationSuccess) { - PrintToLog("%s(): ActivateFeature failed to activate this feature\n", __func__); - return (PKT_ERROR -54); - } - - return 0; -} - -/** Tx 65535 */ -int CMPTransaction::logicMath_Alert() -{ - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return (PKT_ERROR -22); - } - - // is sender authorized? - bool authorized = CheckAlertAuthorization(sender); - - PrintToLog("\t sender: %s\n", sender); - PrintToLog("\t authorized: %s\n", authorized); - - if (!authorized) { - PrintToLog("%s(): rejected: sender %s is not authorized for alerts\n", __func__, sender); - return (PKT_ERROR -51); - } - - if (alert_type == ALERT_CLIENT_VERSION_EXPIRY && ELYSIUM_VERSION < alert_expiry) { - // regular alert keys CANNOT be used to force a client upgrade on mainnet - at least 3 signatures from board/devs are required - if (sender == "48UM25xTXCxPRwnv36YjjJNaAK4whKR8Rd" || isNonMainNet()) { - std::string msgText = "Client upgrade is required! Shutting down due to unsupported consensus state!"; - PrintToLog(msgText); - if (!GetBoolArg("-overrideforcedshutdown", false)) { - boost::filesystem::path persistPath = GetDataDir() / "MP_persist"; - if (boost::filesystem::exists(persistPath)) boost::filesystem::remove_all(persistPath); // prevent the node being restarted without a reparse after forced shutdown - AbortNode(msgText, msgText); - } - } - } - - if (alert_type == 65535) { // set alert type to FFFF to clear previously sent alerts - DeleteAlerts(sender); - } else { - AddAlert(sender, alert_type, alert_expiry, alert_text); - } - - // we have a new alert, fire a notify event if needed - AlertNotify(alert_text); - - return 0; -} - -bool CMPTransaction::CheckPropertyCreationFee() -{ - if (receiver.empty() || !referenceAmount) { - return false; - } - - auto& consensus = ConsensusParams(); - - return receiver == consensus.PROPERTY_CREATION_FEE_RECEIVER.ToString() && *referenceAmount >= consensus.PROPERTY_CREATION_FEE; -} diff --git a/src/elysium/tx.h b/src/elysium/tx.h deleted file mode 100644 index 0899e5dd1c..0000000000 --- a/src/elysium/tx.h +++ /dev/null @@ -1,398 +0,0 @@ -#ifndef FIRO_ELYSIUM_TX_H -#define FIRO_ELYSIUM_TX_H - -class CMPMetaDEx; -class CMPOffer; -class CTransaction; - -#include "ecdsa_signature.h" -#include "elysium.h" -#include "packetencoder.h" -#include "sp.h" - -#include -#include - -#include "../uint256.h" -#include "../utilstrencodings.h" - -#include -#include -#include - -#include - -using elysium::strTransactionType; - -enum TransactionType { - ELYSIUM_TYPE_SIMPLE_SEND = 0, - ELYSIUM_TYPE_RESTRICTED_SEND = 2, - ELYSIUM_TYPE_SEND_TO_OWNERS = 3, - ELYSIUM_TYPE_SEND_ALL = 4, - ELYSIUM_TYPE_SAVINGS_MARK = 10, - ELYSIUM_TYPE_SAVINGS_COMPROMISED = 11, - ELYSIUM_TYPE_RATELIMITED_MARK = 12, - ELYSIUM_TYPE_AUTOMATIC_DISPENSARY = 15, - ELYSIUM_TYPE_TRADE_OFFER = 20, - ELYSIUM_TYPE_ACCEPT_OFFER_BTC = 22, - ELYSIUM_TYPE_METADEX_TRADE = 25, - ELYSIUM_TYPE_METADEX_CANCEL_PRICE = 26, - ELYSIUM_TYPE_METADEX_CANCEL_PAIR = 27, - ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM = 28, - ELYSIUM_TYPE_NOTIFICATION = 31, - ELYSIUM_TYPE_OFFER_ACCEPT_A_BET = 40, - ELYSIUM_TYPE_CREATE_PROPERTY_FIXED = 50, - ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE = 51, - ELYSIUM_TYPE_PROMOTE_PROPERTY = 52, - ELYSIUM_TYPE_CLOSE_CROWDSALE = 53, - ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL = 54, - ELYSIUM_TYPE_GRANT_PROPERTY_TOKENS = 55, - ELYSIUM_TYPE_REVOKE_PROPERTY_TOKENS = 56, - ELYSIUM_TYPE_CHANGE_ISSUER_ADDRESS = 70, - ELYSIUM_TYPE_ENABLE_FREEZING = 71, - ELYSIUM_TYPE_DISABLE_FREEZING = 72, - ELYSIUM_TYPE_FREEZE_PROPERTY_TOKENS = 185, - ELYSIUM_TYPE_UNFREEZE_PROPERTY_TOKENS = 186, - ELYSIUM_TYPE_SIMPLE_SPEND = 1024, - ELYSIUM_TYPE_CREATE_DENOMINATION = 1025, - ELYSIUM_TYPE_SIMPLE_MINT = 1026, - ELYSIUM_MESSAGE_TYPE_DEACTIVATION = 65533, - ELYSIUM_MESSAGE_TYPE_ACTIVATION = 65534, - ELYSIUM_MESSAGE_TYPE_ALERT = 65535 -}; - -/** The class is responsible for transaction interpreting/parsing. - * - * It invokes other classes and methods: offers, accepts, tallies (balances). - */ -class CMPTransaction -{ - friend class CMPMetaDEx; - friend class CMPOffer; - -private: - uint256 txid; - int block; - int64_t blockTime; // internally nTime is still an "unsigned int" - unsigned int tx_idx; // tx # within the block, 0-based - uint64_t tx_fee_paid; - - boost::optional packetClass; - - std::string sender; - std::string receiver; - boost::optional referenceAmount; - - unsigned int type; - unsigned short version; // = MP_TX_PKT_V0; - - // SimpleSend, SendToOwners, TradeOffer, MetaDEx, AcceptOfferBTC, - // CreatePropertyFixed, CreatePropertyVariable, GrantTokens, RevokeTokens - uint64_t nValue; - uint64_t nNewValue; - - // SimpleSend, SendToOwners, TradeOffer, MetaDEx, AcceptOfferBTC, - // CreatePropertyFixed, CreatePropertyVariable, CloseCrowdsale, - // CreatePropertyMananged, GrantTokens, RevokeTokens, ChangeIssuer - unsigned int property; - - // SendToOwners v1 - unsigned int distribution_property; - - // CreatePropertyFixed, CreatePropertyVariable, CreatePropertyMananged, MetaDEx, SendAll - unsigned char ecosystem; - - // CreatePropertyFixed, CreatePropertyVariable, CreatePropertyMananged - unsigned short prop_type; - unsigned int prev_prop_id; - char category[SP_STRING_FIELD_LEN]; - char subcategory[SP_STRING_FIELD_LEN]; - char name[SP_STRING_FIELD_LEN]; - char url[SP_STRING_FIELD_LEN]; - char data[SP_STRING_FIELD_LEN]; - uint64_t deadline; - unsigned char early_bird; - unsigned char percentage; - - // MetaDEx - unsigned int desired_property; - uint64_t desired_value; - unsigned char action; // depreciated - - // TradeOffer - uint64_t amount_desired; - unsigned char blocktimelimit; - uint64_t min_fee; - unsigned char subaction; - - // Alert - uint16_t alert_type; - uint32_t alert_expiry; - char alert_text[SP_STRING_FIELD_LEN]; - - // Activation - uint16_t feature_id; - uint32_t activation_block; - uint32_t min_client_version; - - // Sigma - elysium::SigmaStatus sigmaStatus; - std::vector> mints; - uint8_t denomination; - uint32_t group; - uint16_t groupSize; - std::unique_ptr serial; - std::unique_ptr spend; - - CPubKey ecdsaPubkey; - elysium::ECDSASignature ecdsaSignature; - - // Indicates whether the transaction can be used to execute logic - bool rpcOnly; - - /** Checks whether a pointer to the payload is past it's last position. */ - bool isOverrun(const unsigned char *p); - - /** - * Payload parsing - */ - bool interpret_TransactionType(); - bool interpret_SimpleSend(); - bool interpret_SendToOwners(); - bool interpret_SendAll(); - bool interpret_TradeOffer(); - bool interpret_MetaDExTrade(); - bool interpret_MetaDExCancelPrice(); - bool interpret_MetaDExCancelPair(); - bool interpret_MetaDExCancelEcosystem(); - bool interpret_AcceptOfferBTC(); - bool interpret_CreatePropertyFixed(); - bool interpret_CreatePropertyVariable(); - bool interpret_CloseCrowdsale(); - bool interpret_CreatePropertyManaged(); - bool interpret_GrantTokens(); - bool interpret_RevokeTokens(); - bool interpret_ChangeIssuer(); - bool interpret_EnableFreezing(); - bool interpret_DisableFreezing(); - bool interpret_FreezeTokens(); - bool interpret_UnfreezeTokens(); - bool interpret_CreateDenomination(); - bool interpret_SimpleMint(); - bool interpret_SimpleSpend(); - bool interpret_Activation(); - bool interpret_Deactivation(); - bool interpret_Alert(); - - /** - * Logic and "effects" - */ - int logicMath_SimpleSend(); - int logicMath_SendToOwners(); - int logicMath_SendAll(); - int logicMath_TradeOffer(); - int logicMath_AcceptOffer_BTC(); - int logicMath_MetaDExTrade(); - int logicMath_MetaDExCancelPrice(); - int logicMath_MetaDExCancelPair(); - int logicMath_MetaDExCancelEcosystem(); - int logicMath_CreatePropertyFixed(); - int logicMath_CreatePropertyVariable(); - int logicMath_CloseCrowdsale(); - int logicMath_CreatePropertyManaged(); - int logicMath_GrantTokens(); - int logicMath_RevokeTokens(); - int logicMath_ChangeIssuer(); - int logicMath_EnableFreezing(); - int logicMath_DisableFreezing(); - int logicMath_FreezeTokens(); - int logicMath_UnfreezeTokens(); - int logicMath_CreateDenomination(); - int logicMath_Activation(); - int logicMath_Deactivation(); - int logicMath_Alert(); - - /** - * Logic helpers - */ - int logicHelper_CrowdsaleParticipation(); - -public: - //! DEx and MetaDEx action values - enum ActionTypes - { - INVALID = 0, - - // DEx - NEW = 1, - UPDATE = 2, - CANCEL = 3, - - // MetaDEx - ADD = 1, - CANCEL_AT_PRICE = 2, - CANCEL_ALL_FOR_PAIR = 3, - CANCEL_EVERYTHING = 4, - }; - - uint256 getHash() const { return txid; } - int getBlock() const { return block; } - const std::vector& getRaw() const { return raw; } - unsigned int getType() const { return type; } - std::string getTypeString() const { return strTransactionType(getType()); } - unsigned int getProperty() const { return property; } - unsigned short getVersion() const { return version; } - unsigned short getPropertyType() const { return prop_type; } - uint64_t getFeePaid() const { return tx_fee_paid; } - const std::string& getSender() const { return sender; } - const std::string& getReceiver() const { return receiver; } - const boost::optional& getReferenceAmount() const { return referenceAmount; } - uint64_t getAmount() const { return nValue; } - uint64_t getNewAmount() const { return nNewValue; } - uint8_t getEcosystem() const { return ecosystem; } - uint32_t getPreviousId() const { return prev_prop_id; } - std::string getSPCategory() const { return category; } - std::string getSPSubCategory() const { return subcategory; } - std::string getSPName() const { return name; } - std::string getSPUrl() const { return url; } - std::string getSPData() const { return data; } - int64_t getDeadline() const { return deadline; } - uint8_t getEarlyBirdBonus() const { return early_bird; } - uint8_t getIssuerBonus() const { return percentage; } - bool isRpcOnly() const { return rpcOnly; } - const boost::optional& getPacketClass() const { return packetClass; } - uint16_t getAlertType() const { return alert_type; } - uint32_t getAlertExpiry() const { return alert_expiry; } - std::string getAlertMessage() const { return alert_text; } - uint16_t getFeatureId() const { return feature_id; } - uint32_t getActivationBlock() const { return activation_block; } - uint32_t getMinClientVersion() const { return min_client_version; } - unsigned int getIndexInBlock() const { return tx_idx; } - uint32_t getDistributionProperty() const { return distribution_property; } - - /** Sigma */ - std::vector> const & getMints() const { return mints; } - uint8_t getDenomination() const { return denomination; } - uint32_t getGroup() const { return group; } - uint16_t getGroupSize() const { return groupSize; } - const secp_primitives::Scalar *getSerial() const { return serial.get(); } - const elysium::SigmaProof *getSpend() const { return spend.get(); } - const CPubKey &getECDSAPublicKey() const { return ecdsaPubkey; } - const elysium::ECDSASignature &getECDSASignature() const { return ecdsaSignature; } - CAmount getMintAmount() const { - auto itr = boost::make_transform_iterator(mints.begin(), [] (std::pair const &m) -> uint8_t { - return m.first; - }); - - return SumDenominationsValue(getProperty(), itr, itr + mints.size()); - } - - CAmount getSpendAmount() const { - std::array denoms = {getDenomination()}; - return elysium::SumDenominationsValue(getProperty(), denoms.begin(), denoms.end()); - } - - - /** Creates a new CMPTransaction object. */ - CMPTransaction() - { - SetNull(); - } - - /** Resets and clears all values. */ - void SetNull() - { - txid.SetNull(); - block = -1; - blockTime = 0; - raw.clear(); - tx_idx = 0; - tx_fee_paid = 0; - packetClass = boost::none; - sender.clear(); - receiver.clear(); - referenceAmount = boost::none; - type = 0; - version = 0; - nValue = 0; - nNewValue = 0; - property = 0; - ecosystem = 0; - prop_type = 0; - prev_prop_id = 0; - memset(&category, 0, sizeof(category)); - memset(&subcategory, 0, sizeof(subcategory)); - memset(&name, 0, sizeof(name)); - memset(&url, 0, sizeof(url)); - memset(&data, 0, sizeof(data)); - deadline = 0; - early_bird = 0; - percentage = 0; - desired_property = 0; - desired_value = 0; - action = 0; - amount_desired = 0; - blocktimelimit = 0; - min_fee = 0; - subaction = 0; - alert_type = 0; - alert_expiry = 0; - memset(&alert_text, 0, sizeof(alert_text)); - rpcOnly = true; - feature_id = 0; - activation_block = 0; - min_client_version = 0; - distribution_property = 0; - sigmaStatus = elysium::SigmaStatus::SoftDisabled; - } - - /** Sets the given values. */ - void Set(const uint256& t, int b, unsigned int idx, int64_t bt) - { - txid = t; - block = b; - tx_idx = idx; - blockTime = bt; - } - - /** Sets the given values. */ - void Set( - const std::string& s, - const std::string& r, - uint64_t n, - const uint256& t, - int b, - unsigned int idx, - unsigned char *p, - unsigned int size, - const boost::optional& packetClass, - uint64_t txf, - const boost::optional& referenceAmount); - - /** Parses the packet or payload. */ - bool interpret_Transaction(); - - /** Interprets the payload and executes the logic. */ - int interpretPacket(); - - /** Enables access of interpretPacket. */ - void unlockLogic() { rpcOnly = false; }; - - /** Compares transaction objects based on block height and position within the block. */ - bool operator<(const CMPTransaction& other) const - { - if (block != other.block) return block > other.block; - return tx_idx > other.tx_idx; - } - -private: - bool CheckPropertyCreationFee(); - -private: - std::vector raw; -}; - -/** Parses a transaction and populates the CMPTransaction object. */ -int ParseTransaction(const CTransaction& tx, int nBlock, unsigned int idx, CMPTransaction& mptx, unsigned int nTime=0); - -#endif // FIRO_ELYSIUM_TX_H diff --git a/src/elysium/txprocessor.cpp b/src/elysium/txprocessor.cpp deleted file mode 100644 index dc1a1887e1..0000000000 --- a/src/elysium/txprocessor.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include "txprocessor.h" - -#include "rules.h" -#include "sigma.h" -#include "signaturebuilder.h" - -#include "../base58.h" - -namespace elysium { - -TxProcessor *txProcessor; - -int TxProcessor::ProcessTx(CMPTransaction& tx) -{ - LOCK(cs_main); - - tx.unlockLogic(); - - auto result = tx.interpretPacket(); - - if (result == (PKT_ERROR - 100)) { - // Unknow transaction type. - switch (tx.getType()) { - case ELYSIUM_TYPE_SIMPLE_MINT: - result = ProcessSimpleMint(tx); - break; - - case ELYSIUM_TYPE_SIMPLE_SPEND: - result = ProcessSimpleSpend(tx); - break; - } - } - - if (result) { - return result; // Error. - } - - TransactionProcessed(tx); - - return 0; -} - -int TxProcessor::ProcessSimpleMint(const CMPTransaction& tx) -{ - auto block = tx.getBlock(); - auto type = tx.getType(); - auto version = tx.getVersion(); - auto property = tx.getProperty(); - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block - ); - return PKT_ERROR_SIGMA - 22; - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return PKT_ERROR_SIGMA - 24; - } - - if (!IsSigmaEnabled(property)) { - PrintToLog("%s(): rejected: property %d does not enable sigma\n", __func__, property); - return PKT_ERROR_SIGMA - 901; - } - - std::vector denominations; - denominations.reserve(tx.getMints().size()); - - auto spendV1IsActivated = IsFeatureActivated(FEATURE_SIGMA_SPENDV1, block); - for (auto &mint : tx.getMints()) { - auto denom = mint.first; - auto& pubkey = mint.second; - - auto isValid = spendV1IsActivated ? pubkey.IsValid() : pubkey.IsMember(); - - if (!isValid) { - PrintToLog("%s(): rejected: public key is invalid\n", __func__); - return PKT_ERROR_SIGMA - 904; - } - - denominations.push_back(denom); - } - - int64_t amount; - try { - amount = SumDenominationsValue(property, denominations.begin(), denominations.end()); - } catch (std::invalid_argument const &e) { - // The only possible cases is invalid denomination. - PrintToLog("%s(): rejected: error %s\n", __func__, e.what()); - return PKT_ERROR_SIGMA - 905; - } catch (std::overflow_error const &e) { - PrintToLog("%s(): rejected: overflow error %s\n", __func__, e.what()); - return PKT_ERROR_SIGMA - 906; - } - - auto& sender = tx.getSender(); - int64_t balance = getMPbalance(sender, property, BALANCE); - - if (balance < amount) { - PrintToLog("%s(): rejected: sender %s has insufficient balance of property %d [%s < %s]\n", - __func__, - tx.getSender(), - property, - FormatMP(property, balance), - FormatMP(property, amount) - ); - return PKT_ERROR_SIGMA - 25; - } - - // subtract balance - assert(update_tally_map(sender, property, -amount, BALANCE)); - - for (auto &mint : tx.getMints()) { - SigmaMintGroup group; - SigmaMintIndex index; - - auto denom = mint.first; - auto& pubkey = mint.second; - - std::tie(group, index) = sigmaDb->RecordMint(property, denom, pubkey, block); - - SimpleMintProcessed(property, denom, group, index, pubkey); - } - - return 0; -} - -int TxProcessor::ProcessSimpleSpend(const CMPTransaction& tx) -{ - auto block = tx.getBlock(); - auto type = tx.getType(); - auto version = tx.getVersion(); - auto property = tx.getProperty(); - - if (!IsTransactionTypeAllowed(block, property, type, version)) { - PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", - __func__, - type, - version, - property, - block); - return PKT_ERROR_SIGMA - 22; - } - - if (!IsPropertyIdValid(property)) { - PrintToLog("%s(): rejected: property %d does not exist\n", __func__, property); - return PKT_ERROR_SIGMA - 24; - } - - if (!IsSigmaEnabled(property)) { - PrintToLog("%s(): rejected: property %d does not enable sigma\n", __func__, property); - return PKT_ERROR_SIGMA - 901; - } - - auto spend = tx.getSpend(); - auto serial = tx.getSerial(); - auto denomination = tx.getDenomination(); - auto group = tx.getGroup(); - auto groupSize = tx.getGroupSize(); - - bool const fPadding = block >= ::Params().GetConsensus().nSigmaPaddingBlock; - - assert(spend); - assert(serial); - - CBitcoinAddress receiver(tx.getReceiver()); - if (!receiver.IsValid()) { - PrintToLog("%s(): rejected: receiver address is invalid\n", __func__); - return PKT_ERROR_SIGMA - 45; - } - - // check signature - if (version == MP_TX_PKT_V1) { - int64_t referenceAmount = tx.getReferenceAmount().value(); - auto &publicKey = tx.getECDSAPublicKey(); - if (!publicKey.IsFullyValid()) { - PrintToLog("%s(): rejected: signature public key is invalid\n", __func__); - return PKT_ERROR_SIGMA - 907; - } - - SigmaV1SignatureBuilder sigVerifier( - receiver, - referenceAmount, - *spend); - - if (!sigVerifier.Verify(publicKey, tx.getECDSASignature())) { - PrintToLog("%s(): rejected: signature is invalid\n", __func__); - return PKT_ERROR_SIGMA - 907; - } - } - - // check serial in database - uint256 spendTx; - if (sigmaDb->HasSpendSerial(property, denomination, *serial, spendTx) - || !VerifySigmaSpend(property, denomination, group, groupSize, *spend, *serial, fPadding)) { - PrintToLog("%s(): rejected: spend is invalid\n", __func__); - return PKT_ERROR_SIGMA - 907; - } - std::array denoms = {denomination}; - - uint64_t amount; - try { - amount = SumDenominationsValue(property, denoms.begin(), denoms.end()); - } catch (std::invalid_argument const& e) { - PrintToLog("%s(): rejected: error %s\n", __func__, e.what()); - return PKT_ERROR_SIGMA - 905; - } - - // subtract balance - sigmaDb->RecordSpendSerial(property, denomination, *serial, block, tx.getHash()); - assert(update_tally_map(tx.getReceiver(), property, amount, BALANCE)); - - return 0; -} - - -} diff --git a/src/elysium/txprocessor.h b/src/elysium/txprocessor.h deleted file mode 100644 index e21723d844..0000000000 --- a/src/elysium/txprocessor.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef FIRO_ELYSIUM_TXPROCESSOR_H -#define FIRO_ELYSIUM_TXPROCESSOR_H - -#include "property.h" -#include "sigmaprimitives.h" -#include "tx.h" - -#include - -namespace elysium { - -class TxProcessor -{ -public: - int ProcessTx(CMPTransaction& tx); - -public: - boost::signals2::signal SimpleMintProcessed; - boost::signals2::signal TransactionProcessed; - -private: - int ProcessSimpleMint(const CMPTransaction& tx); - int ProcessSimpleSpend(const CMPTransaction& tx); -}; - -extern TxProcessor *txProcessor; - -} - -#endif // FIRO_ELYSIUM_TXPROCESSOR_H diff --git a/src/elysium/uint256_extensions.h b/src/elysium/uint256_extensions.h deleted file mode 100644 index 1e7275c41a..0000000000 --- a/src/elysium/uint256_extensions.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * @file uint256_extensions.h - * - * This file provides helper to handle uint256 calculations. - */ - -#ifndef ELYSIUM_UINT256_EXTENSIONS_H -#define ELYSIUM_UINT256_EXTENSIONS_H - -#include "arith_uint256.h" - -#include -#include -#include - -namespace elysium { -namespace uint256_const { -//! The number 1 as uint256 -static const arith_uint256 one(static_cast(1)); -//! The highest number in range of int64_t as uint256 -static const arith_uint256 max_int64(static_cast(std::numeric_limits::max())); -} - -/** - * Returns a mod n. - */ -inline arith_uint256 Modulo256(const arith_uint256& a, const arith_uint256& n) -{ - return (a - (n * (a / n))); -} - -/** - * Converts a positive primitive number to uint256. - */ -template -inline arith_uint256 ConvertTo256(const NumberT& number) -{ - assert(number >= 0); - return arith_uint256(static_cast(number)); -} - -/** - * Converts an uint256 to int64_t. - */ -inline int64_t ConvertTo64(const arith_uint256& number) -{ - assert(number <= uint256_const::max_int64); - return static_cast(number.GetLow64()); -} - -/** - * Returns ceil(numerator / denominator). - */ -inline arith_uint256 DivideAndRoundUp(const arith_uint256& numerator, const arith_uint256& denominator) -{ - if (numerator == 0) { - return arith_uint256(0); - } - return uint256_const::one + (numerator - uint256_const::one) / denominator; -} - -} // namespace elysium - -#endif // ELYSIUM_UINT256_EXTENSIONS_H diff --git a/src/elysium/utils.cpp b/src/elysium/utils.cpp deleted file mode 100644 index 38bdcb3a35..0000000000 --- a/src/elysium/utils.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file utils.cpp - * - * This file serves to seperate utility functions from the main elysium.cpp - * and elysium.h files. - */ - -#include "elysium/utils.h" - -#include "base58.h" -#include "utilstrencodings.h" - -// TODO: use crypto/sha256 instead of openssl -#include "openssl/sha.h" - -#include "elysium/log.h" -#include "elysium/script.h" - -#include - -#include -#include -#include -#include - -std::string HashToAddress(unsigned char version, const uint160& hash) -{ - CBitcoinAddress address; - if (version == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)[0]) { - CKeyID keyId = hash; - address.Set(keyId); - return address.ToString(); - } else if (version == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)[0]) { - CScriptID scriptId = hash; - address.Set(scriptId); - return address.ToString(); - } - - return ""; -} - -std::vector AddressToBytes(const std::string& address) -{ - std::vector addressBytes; - bool success = DecodeBase58(address, addressBytes); - if (!success) { - PrintToLog("ERROR: failed to decode address %s.\n", address); - } - if (addressBytes.size() == 25) { - addressBytes.resize(21); // truncate checksum - } else { - PrintToLog("ERROR: unexpected size from DecodeBase58 when decoding address %s.\n", address); - } - - return addressBytes; -} diff --git a/src/elysium/utils.h b/src/elysium/utils.h deleted file mode 100644 index 05e46a976e..0000000000 --- a/src/elysium/utils.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ELYSIUM_UTILS_H -#define ELYSIUM_UTILS_H - -#include - -#include "uint256.h" - -/** Determines the Bitcoin address associated with a given hash and version. */ -std::string HashToAddress(unsigned char version, const uint160& hash); - -/** Returns a vector of bytes containing the version and hash160 for an address.*/ -std::vector AddressToBytes(const std::string& address); - -#endif // ELYSIUM_UTILS_H diff --git a/src/elysium/utilsbitcoin.cpp b/src/elysium/utilsbitcoin.cpp deleted file mode 100644 index 0859961326..0000000000 --- a/src/elysium/utilsbitcoin.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file utilsbitcoin.cpp - * - * This file contains certain helpers to access information about Bitcoin. - */ - -#include "chain.h" -#include "chainparams.h" -#include "validation.h" -#include "sync.h" - -#include -#include - -namespace elysium -{ -/** - * @return The current chain length. - */ -int GetHeight() -{ - LOCK(cs_main); - return chainActive.Height(); -} - -/** - * @return The timestamp of the latest block. - */ -uint32_t GetLatestBlockTime() -{ - LOCK(cs_main); - if (chainActive.Tip()) - return chainActive.Tip()->GetBlockTime(); - else - return Params().GenesisBlock().nTime; -} - -/** - * @return The CBlockIndex, or NULL, if the block isn't available. - */ -CBlockIndex* GetBlockIndex(const uint256& hash) -{ - CBlockIndex* pBlockIndex = NULL; - LOCK(cs_main); - BlockMap::const_iterator it = mapBlockIndex.find(hash); - if (it != mapBlockIndex.end()) { - pBlockIndex = it->second; - } - - return pBlockIndex; -} - -bool MainNet() -{ - return Params().NetworkIDString() == "main"; -} - -bool TestNet() -{ - return Params().NetworkIDString() == "test"; -} - -bool RegTest() -{ - return Params().NetworkIDString() == "regtest"; -} - -bool UnitTest() -{ - return Params().NetworkIDString() == "unittest"; -} - -bool isNonMainNet() -{ - return !MainNet() && !UnitTest(); -} - - -} // namespace elysium diff --git a/src/elysium/utilsbitcoin.h b/src/elysium/utilsbitcoin.h deleted file mode 100644 index 1624f2474a..0000000000 --- a/src/elysium/utilsbitcoin.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef ELYSIUM_BITCOIN_H -#define ELYSIUM_BITCOIN_H - -class CBlockIndex; -class uint256; - -#include - -namespace elysium -{ -/** Returns the current chain length. */ -int GetHeight(); -/** Returns the timestamp of the latest block. */ -uint32_t GetLatestBlockTime(); -/** Returns the CBlockIndex for a given block hash, or NULL. */ -CBlockIndex* GetBlockIndex(const uint256& hash); - -bool MainNet(); -bool TestNet(); -bool RegTest(); -bool UnitTest(); -bool isNonMainNet(); -} - -#endif // ELYSIUM_BITCOIN_H diff --git a/src/elysium/version.cpp b/src/elysium/version.cpp deleted file mode 100644 index 20a71dbbd3..0000000000 --- a/src/elysium/version.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "elysium/version.h" - -#include "clientversion.h" -#include "tinyformat.h" - -#include - -#ifdef HAVE_BUILD_INFO -# include "build.h" -#endif - -#ifdef ELYSIUM_VERSION_STATUS -# define ELYSIUM_VERSION_SUFFIX STRINGIZE(ELYSIUM_VERSION_STATUS) -#else -# define ELYSIUM_VERSION_SUFFIX "" -#endif - -extern const int ELYSIUM_VERSION_MAJOR; -extern const int ELYSIUM_VERSION_MINOR; -extern const int ELYSIUM_VERSION_PATCH; -extern const int ELYSIUM_VERSION_BUILD; - -//! Returns formatted Elysium version, e.g. "1.2.0" or "1.3.4.1" -const std::string ElysiumVersion() -{ - if (ELYSIUM_VERSION_BUILD) { - return strprintf("%d.%d.%d.%d", - ELYSIUM_VERSION_MAJOR, - ELYSIUM_VERSION_MINOR, - ELYSIUM_VERSION_PATCH, - ELYSIUM_VERSION_BUILD); - } else { - return strprintf("%d.%d.%d", - ELYSIUM_VERSION_MAJOR, - ELYSIUM_VERSION_MINOR, - ELYSIUM_VERSION_PATCH); - } -} - -//! Returns formatted Firo Core version, e.g. "0.10", "0.9.3" -const std::string FiroCoreVersion() -{ - if (CLIENT_VERSION_BUILD) { - return strprintf("%d.%d.%d.%d", - CLIENT_VERSION_MAJOR, - CLIENT_VERSION_MINOR, - CLIENT_VERSION_REVISION, - CLIENT_VERSION_BUILD); - } else { - return strprintf("%d.%d.%d", - CLIENT_VERSION_MAJOR, - CLIENT_VERSION_MINOR, - CLIENT_VERSION_REVISION); - } -} diff --git a/src/elysium/version.h b/src/elysium/version.h deleted file mode 100644 index e4f57b23bd..0000000000 --- a/src/elysium/version.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef ELYSIUM_VERSION_H -#define ELYSIUM_VERSION_H - -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#else -#endif // HAVE_CONFIG_H - -// -// *-res.rc includes this file, but it cannot cope with real c++ code. -// WINDRES_PREPROC is defined to indicate that its pre-processor is running. -// Anything other than a define should be guarded below: -// - -#include - -// -// Elysium version information are also to be defined in configure.ac. -// -// During the configuration, this information are used for other places. -// - -// Increase with every consensus affecting change -//#define ELYSIUM_VERSION_MAJOR 0 - -const int ELYSIUM_VERSION_MAJOR = 0; - -// Increase with every non-consensus affecting feature -//#define ELYSIUM_VERSION_MINOR 3 -const int ELYSIUM_VERSION_MINOR = 3; - -// Increase with every patch, which is not a feature or consensus affecting -//#define ELYSIUM_VERSION_PATCH 0 -const int ELYSIUM_VERSION_PATCH = 0; - -// Non-public build number/revision (usually zero) -//#define ELYSIUM_VERSION_BUILD 0 -const int ELYSIUM_VERSION_BUILD = 0; - -//! Elysium client version -static const int ELYSIUM_VERSION = // lgtm [cpp/unused-static-variable] - +100000000000 * ELYSIUM_VERSION_MAJOR - + 10000000 * ELYSIUM_VERSION_MINOR - + 1000 * ELYSIUM_VERSION_PATCH - + 1 * ELYSIUM_VERSION_BUILD; - -//! Returns formatted Elysium version, e.g. "1.2.0" -const std::string ElysiumVersion(); - -//! Returns formatted Bitcoin Core version, e.g. "0.10", "0.9.3" -const std::string FiroCoreVersion(); - -#endif // ELYSIUM_VERSION_H diff --git a/src/elysium/wallet.cpp b/src/elysium/wallet.cpp deleted file mode 100644 index f8686dfcbe..0000000000 --- a/src/elysium/wallet.cpp +++ /dev/null @@ -1,337 +0,0 @@ -#include "wallet.h" - -#include "sigma.h" - -#include "../validation.h" -#include "../sync.h" -#include "../util.h" - -#include "../wallet/walletdb.h" -#include "../wallet/walletexcept.h" - -#include - -#include -#include - -namespace elysium { - -Wallet *wallet; - -Wallet::Wallet(const std::string& walletFile) : walletFile(walletFile) -{ - using std::placeholders::_1; - using std::placeholders::_2; - using std::placeholders::_3; - using std::placeholders::_4; - using std::placeholders::_5; - using std::placeholders::_6; - - // Subscribe to events. - LOCK(cs_main); - - { - auto h = std::bind(&Wallet::OnMintAdded, this, _1, _2, _3, _4, _5, _6); - eventConnections.emplace_front(sigmaDb->MintAdded.connect(h)); - } - { - auto h = std::bind(&Wallet::OnMintRemoved, this, _1, _2, _3); - eventConnections.emplace_front(sigmaDb->MintRemoved.connect(h)); - } - { - auto h = std::bind(&Wallet::OnSpendAdded, this, _1, _2, _3, _4); - eventConnections.emplace_front(sigmaDb->SpendAdded.connect(h)); - } - { - auto h = std::bind(&Wallet::OnSpendRemoved, this, _1, _2, _3); - eventConnections.emplace_front(sigmaDb->SpendRemoved.connect(h)); - } -} - -Wallet::~Wallet() -{ -} - -void Wallet::ReloadMasterKey() -{ - mintWalletV0.ReloadMasterKey(); - mintWalletV1.ReloadMasterKey(); -} - -SigmaMintId Wallet::CreateSigmaMint(PropertyId property, SigmaDenomination denomination) -{ - return mintWalletV1.GenerateMint(property, denomination); -} - -void Wallet::SetSigmaMintCreatedTransaction(const SigmaMintId& id, const uint256& tx) -{ - auto &wallet = GetMintWallet(id); - wallet.UpdateMintCreatedTx(id, tx); -} - -void Wallet::SetSigmaMintUsedTransaction(const SigmaMintId& id, const uint256& tx) -{ - auto &wallet = GetMintWallet(id); - wallet.UpdateMintSpendTx(id, tx); -} - -void Wallet::ClearAllChainState() -{ - mintWalletV0.ClearMintsChainState(); - mintWalletV1.ClearMintsChainState(); -} - -SigmaSpend Wallet::CreateSigmaSpendV0(PropertyId property, SigmaDenomination denomination, bool fPadding) -{ - return CreateSigmaSpend(property, denomination, fPadding, SigmaMintVersion::V0); -} - -SigmaSpend Wallet::CreateSigmaSpendV1(PropertyId property, SigmaDenomination denomination, bool fPadding) -{ - return CreateSigmaSpend(property, denomination, fPadding, SigmaMintVersion::V1); -} - -SigmaSpend Wallet::CreateSigmaSpend(PropertyId property, SigmaDenomination denomination, bool fPadding, SigmaMintVersion version) -{ - LOCK(cs_main); - - auto mint = GetSpendableSigmaMint(property, denomination, version); - if (!mint) { - throw InsufficientFunds(_("No available mint to spend")); - } - - // Get anonimity set for spend. - std::vector anonimitySet; - - sigmaDb->GetAnonimityGroup( - mint->property, - mint->denomination, - mint->chainState.group, - std::back_inserter(anonimitySet) - ); - - if (anonimitySet.size() < 2) { - throw WalletError(_("Amount of coins in anonimity set is not enough to spend")); - } - - // Create spend. - auto key = GetKey(mint.get()); - SigmaProof proof(DefaultSigmaParams, key, anonimitySet.begin(), anonimitySet.end(), fPadding); - - if (!VerifySigmaSpend(mint->property, mint->denomination, mint->chainState.group, anonimitySet.size(), proof, key.serial, fPadding)) { - throw WalletError(_("Failed to create spendable spend")); - } - - return SigmaSpend(SigmaMintId(mint->property, mint->denomination, SigmaPublicKey(key, DefaultSigmaParams)), - mint->chainState.group, anonimitySet.size(), proof); -} - -void Wallet::DeleteUnconfirmedSigmaMint(const SigmaMintId &id) -{ - auto &wallet = GetMintWallet(id); - wallet.DeleteUnconfirmedMint(id); -} - -bool Wallet::HasSigmaMint(const SigmaMintId& id) -{ - return GetSigmaMintVersion(id) != boost::none; -} - -bool Wallet::HasSigmaMint(const secp_primitives::Scalar& serial) -{ - return GetSigmaMintVersion(serial) != boost::none; -} - -SigmaMint Wallet::GetSigmaMint(const SigmaMintId& id) -{ - auto &wallet = GetMintWallet(id); - return wallet.GetMint(id); -} - -CKey Wallet::GetSigmaSignatureKey(const SigmaMintId &id) -{ - return mintWalletV1.GetSignatureKey(id); -} - -boost::optional Wallet::GetSpendableSigmaMint(PropertyId property, SigmaDenomination denomination, SigmaMintVersion version) -{ - // Get all spendable mints. - std::vector spendables; - - auto &mintWallet = GetMintWallet(version); - mintWallet.ListMints(boost::make_function_output_iterator([&] (const std::pair& m) { - if (m.second.property != property || m.second.denomination != denomination) { - return; - } - - if (m.second.IsSpent() || !m.second.IsOnChain()) { - return; - } - - spendables.push_back(m.second); - })); - - if (spendables.empty()) { - return boost::none; - } - - // Pick the oldest mint. - auto oldest = std::min_element( - spendables.begin(), - spendables.end(), - [](const SigmaMint& a, const SigmaMint& b) -> bool { - - if (a.chainState.group == b.chainState.group) { - return a.chainState.index < b.chainState.index; - } - - return a.chainState.group < b.chainState.group; - } - ); - - return *oldest; -} - -SigmaPrivateKey Wallet::GetKey(const SigmaMint &mint) -{ - // Try all mint wallets - try { - return mintWalletV1.GeneratePrivateKey(mint.seedId); - } catch (const std::exception &) { - return mintWalletV0.GeneratePrivateKey(mint.seedId); - } -} - -void Wallet::SetSigmaMintChainState(const SigmaMintId& id, const SigmaMintChainState& state) -{ - auto &mintWallet = GetMintWallet(id); - mintWallet.UpdateMintChainstate(id, state); -} - -SigmaWallet& Wallet::GetMintWallet(SigmaMintVersion version) -{ - switch (version) { - case SigmaMintVersion::V0: - return mintWalletV0; - case SigmaMintVersion::V1: - return mintWalletV1; - default: - throw new std::invalid_argument("Coin version is not found."); - } -} - -SigmaWallet& Wallet::GetMintWallet(SigmaMintId const &id) -{ - auto version = GetSigmaMintVersion(id); - if (version) { - return GetMintWallet(version.get()); - } - - throw std::invalid_argument("Sigma Mint Id is not found."); -} - -boost::optional Wallet::GetSigmaMintVersion(const SigmaMintId& id) -{ - if (mintWalletV0.HasMint(id)) { - return SigmaMintVersion::V0; - } else if (mintWalletV1.HasMint(id)) { - return SigmaMintVersion::V1; - } - - return boost::none; -} - -boost::optional Wallet::GetSigmaMintVersion(const secp_primitives::Scalar &scalar) -{ - if (mintWalletV0.HasMint(scalar)) { - return SigmaMintVersion::V0; - } else if (mintWalletV1.HasMint(scalar)) { - return SigmaMintVersion::V1; - } - - return boost::none; -} - -void Wallet::OnSpendAdded( - PropertyId property, - SigmaDenomination denomination, - const secp_primitives::Scalar &serial, - const uint256 &tx) -{ - auto version = GetSigmaMintVersion(serial); - if (!version) { - // the serial is not in wallet. - return; - } - - SigmaMintId id; - auto &mintWallet = GetMintWallet(version.get()); - try { - id = mintWallet.GetMintId(serial); - } catch (std::runtime_error const &e) { - LogPrintf("%s : fail to get mint id when spend added have been triggered, %s\n", e.what()); - throw; - } - SetSigmaMintUsedTransaction(id, tx); -} - -void Wallet::OnSpendRemoved( - PropertyId property, - SigmaDenomination denomination, - const secp_primitives::Scalar &serial) -{ - auto version = GetSigmaMintVersion(serial); - if (!version) { - // the serial is not in wallet. - return; - } - - auto &mintWallet = GetMintWallet(version.get()); - try { - auto id = mintWallet.GetMintId(serial); - SetSigmaMintUsedTransaction(id, uint256()); - } catch (std::runtime_error const &e) { - LogPrintf("%s : fail to get mint id when spend removed have been triggered, %s\n", e.what()); - throw; - } -} - -void Wallet::OnMintAdded( - PropertyId property, - SigmaDenomination denomination, - SigmaMintGroup group, - SigmaMintIndex idx, - const SigmaPublicKey& pubKey, - int block) -{ - SigmaMintId id(property, denomination, pubKey); - - if (HasSigmaMint(id)) { - - // 1. is in wallet then update state - SetSigmaMintChainState(id, SigmaMintChainState(block, group, idx)); - } else { - - // 2. try to recover new mint - SigmaMintChainState chainState(block, group, idx); - - if (mintWalletV1.TryRecoverMint(id, chainState)) { - LogPrintf("%s : Found new mint when try to recover\n", __func__); - } else if (mintWalletV0.TryRecoverMint(id, chainState)) { - LogPrintf("%s : Found new legacy mint when try to recover\n", __func__); - } - } -} - -void Wallet::OnMintRemoved(PropertyId property, SigmaDenomination denomination, const SigmaPublicKey& pubKey) -{ - SigmaMintId id(property, denomination, pubKey); - - if (!HasSigmaMint(id)) { - return; - } - - SetSigmaMintChainState(id, SigmaMintChainState()); -} - -} // namespace elysium diff --git a/src/elysium/wallet.h b/src/elysium/wallet.h deleted file mode 100644 index 06be9e58af..0000000000 --- a/src/elysium/wallet.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef FIRO_ELYSIUM_WALLET_H -#define FIRO_ELYSIUM_WALLET_H - -#include "elysium.h" -#include "property.h" -#include "sigmaprimitives.h" -#include "sigmawalletv0.h" -#include "sigmawalletv1.h" -#include "sp.h" -#include "walletmodels.h" - -#include "../uint256.h" - -#include "../wallet/walletdb.h" - -#include - -#include -#include - -namespace elysium { - -class Wallet -{ -protected: - enum class SigmaMintVersion : uint8_t - { - V0, - V1 - }; - -public: - Wallet(const std::string& walletFile); - virtual ~Wallet(); - -public: - void ReloadMasterKey(); - -public: - SigmaMintId CreateSigmaMint(PropertyId property, SigmaDenomination denomination); - - template - Output CreateSigmaMints(PropertyId property, Denomination begin, Denomination end, Output output) - { - for (auto it = begin; it != end; it++) { - *output++ = CreateSigmaMint(property, *it); - } - - return output; - } - - void SetSigmaMintCreatedTransaction(const SigmaMintId& id, const uint256& tx); - void SetSigmaMintUsedTransaction(const SigmaMintId& id, const uint256& tx); - - void ClearAllChainState(); - - SigmaSpend CreateSigmaSpendV0(PropertyId property, SigmaDenomination denomination, bool fPadding); - SigmaSpend CreateSigmaSpendV1(PropertyId property, SigmaDenomination denomination, bool fPadding); - - void DeleteUnconfirmedSigmaMint(SigmaMintId const &id); - -public: - template - void ListSigmaMintsV0(OutputIt it) - { - mintWalletV0.ListMints(it); - } - - template - void ListSigmaMintsV1(OutputIt it) - { - mintWalletV1.ListMints(it); - } - - SigmaMint GetSigmaMint(const SigmaMintId& id); - CKey GetSigmaSignatureKey(const SigmaMintId &id); - SigmaPrivateKey GetKey(const SigmaMint &mint); - - bool HasSigmaMint(const SigmaMintId& id); - bool HasSigmaMint(const secp_primitives::Scalar &serial); - -protected: - boost::optional GetSpendableSigmaMint( - PropertyId property, SigmaDenomination denomination, SigmaMintVersion version); - void SetSigmaMintChainState(const SigmaMintId &id, const SigmaMintChainState &state); - - SigmaWallet& GetMintWallet(SigmaMintVersion version); - SigmaWallet& GetMintWallet(SigmaMintId const &id); - - boost::optional GetSigmaMintVersion(const SigmaMintId& id); - boost::optional GetSigmaMintVersion(const secp_primitives::Scalar &scalar); - - SigmaSpend CreateSigmaSpend(PropertyId property, SigmaDenomination denomination, bool fPadding, SigmaMintVersion version); - -private: - void OnSpendAdded( - PropertyId property, - SigmaDenomination denomination, - const secp_primitives::Scalar &serial, - const uint256 &tx); - - void OnSpendRemoved( - PropertyId property, - SigmaDenomination denomination, - const secp_primitives::Scalar &serial); - - void OnMintAdded( - PropertyId property, - SigmaDenomination denomination, - SigmaMintGroup group, - SigmaMintIndex idx, - const SigmaPublicKey& pubKey, - int block); - - void OnMintRemoved(PropertyId property, SigmaDenomination denomination, const SigmaPublicKey& pubKey); - -private: - std::string walletFile; - std::forward_list eventConnections; - SigmaWalletV0 mintWalletV0; - SigmaWalletV1 mintWalletV1; -}; - -extern Wallet *wallet; - -} // namespace elysium - -#endif // FIRO_ELYSIUM_WALLET_H diff --git a/src/elysium/walletcache.cpp b/src/elysium/walletcache.cpp deleted file mode 100644 index 6484f2ff4b..0000000000 --- a/src/elysium/walletcache.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "walletcache.h" - -#include "log.h" -#include "tally.h" -#include "wallettxs.h" - -#include "../init.h" -#include "../validation.h" -#include "../sync.h" -#include "../uint256.h" -#ifdef ENABLE_WALLET -#include "../wallet/wallet.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace elysium { - -//! Global vector of Elysium transactions in the wallet -std::vector walletTXIDCache; - -//! Map of wallet balances -static std::map walletBalancesCache; - -/** - * Adds a txid to the wallet txid cache, performing duplicate detection. - */ -void WalletTXIDCacheAdd(const uint256& hash) -{ - if (elysium_debug_walletcache) PrintToLog("WALLETTXIDCACHE: Adding tx to txid cache : %s\n", hash.GetHex()); - if (std::find(walletTXIDCache.begin(), walletTXIDCache.end(), hash) != walletTXIDCache.end()) { - PrintToLog("ERROR: Wallet TXID Cache blocked duplicate insertion for %s\n", hash.GetHex()); - } else { - walletTXIDCache.push_back(hash); - } -} - -/** - * Performs initial population of the wallet txid cache. - */ -void WalletTXIDCacheInit() -{ - if (elysium_debug_walletcache) PrintToLog("WALLETTXIDCACHE: WalletTXIDCacheInit requested\n"); -#ifdef ENABLE_WALLET - LOCK2(cs_main, pwalletMain->cs_wallet); - - std::list acentries; - CWallet::TxItems txOrdered = pwalletMain->wtxOrdered; - - // Iterate through the wallet, checking if each transaction is Elysium (via levelDB) - for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { - const CWalletTx* pwtx = it->second.first; - if (pwtx != NULL) { - // get the hash of the transaction and check leveldb to see if this is an Elysium tx, if so add to cache - const uint256& hash = pwtx->GetHash(); - if (p_txlistdb->exists(hash)) { - walletTXIDCache.push_back(hash); - if (elysium_debug_walletcache) PrintToLog("WALLETTXIDCACHE: Adding tx to txid cache : %s\n", hash.GetHex()); - } - } - } -#endif -} - -/** - * Updates the cache with the latest state, returning true if changes were made to wallet addresses (including watch only). - * - * Also prepares a list of addresses that were changed (for future usage). - */ -int WalletCacheUpdate() -{ - if (elysium_debug_walletcache) PrintToLog("WALLETCACHE: Update requested\n"); - int numChanges = 0; - std::set changedAddresses; - - LOCK(cs_main); - - for (std::unordered_map::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) { - const std::string& address = my_it->first; - - // determine if this address is in the wallet - int addressIsMine = IsMyAddress(address); - if (!addressIsMine) { - if (elysium_debug_walletcache) PrintToLog("WALLETCACHE: Ignoring non-wallet address %s\n", address); - continue; // ignore this address, not in wallet - } - - // obtain & init the tally - CMPTally& tally = my_it->second; - tally.init(); - - // check cache for miss on address - std::map::iterator search_it = walletBalancesCache.find(address); - if (search_it == walletBalancesCache.end()) { // cache miss, new address - ++numChanges; - changedAddresses.insert(address); - walletBalancesCache.insert(std::make_pair(address,tally)); - if (elysium_debug_walletcache) PrintToLog("WALLETCACHE: *CACHE MISS* - %s not in cache\n", address); - continue; - } - - // check cache for miss on balance - TODO TRY AND OPTIMIZE THIS - CMPTally &cacheTally = search_it->second; - uint32_t propertyId; - while (0 != (propertyId = (tally.next()))) { - if (tally.getMoney(propertyId, BALANCE) != cacheTally.getMoney(propertyId, BALANCE) || - tally.getMoney(propertyId, PENDING) != cacheTally.getMoney(propertyId, PENDING) || - tally.getMoney(propertyId, SELLOFFER_RESERVE) != cacheTally.getMoney(propertyId, SELLOFFER_RESERVE) || - tally.getMoney(propertyId, ACCEPT_RESERVE) != cacheTally.getMoney(propertyId, ACCEPT_RESERVE) || - tally.getMoney(propertyId, METADEX_RESERVE) != cacheTally.getMoney(propertyId, METADEX_RESERVE)) { // cache miss, balance - ++numChanges; - changedAddresses.insert(address); - walletBalancesCache.erase(search_it); - walletBalancesCache.insert(std::make_pair(address,tally)); - if (elysium_debug_walletcache) PrintToLog("WALLETCACHE: *CACHE MISS* - %s balance for property %d differs\n", address, propertyId); - break; - } - } - } - if (elysium_debug_walletcache) PrintToLog("WALLETCACHE: Update finished - there were %d changes\n", numChanges); - return numChanges; -} - - -} // namespace elysium diff --git a/src/elysium/walletcache.h b/src/elysium/walletcache.h deleted file mode 100644 index 08be9f021f..0000000000 --- a/src/elysium/walletcache.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef ELYSIUM_WALLETCACHE_H -#define ELYSIUM_WALLETCACHE_H - -class uint256; - -#include - -namespace elysium -{ -//! Global vector of Elysium transactions in the wallet -extern std::vector walletTXIDCache; - -/** Adds a txid to the wallet txid cache, performing duplicate detection */ -void WalletTXIDCacheAdd(const uint256& hash); - -/** Performs initial population of the wallet txid cache */ -void WalletTXIDCacheInit(); - -/** Updates the cache and returns whether any wallet addresses were changed */ -int WalletCacheUpdate(); -} - -#endif // ELYSIUM_WALLETCACHE_H diff --git a/src/elysium/walletmodels.cpp b/src/elysium/walletmodels.cpp deleted file mode 100644 index 893486d461..0000000000 --- a/src/elysium/walletmodels.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "walletmodels.h" - -namespace elysium { - -// SigmaMintChainState Implementation. - -SigmaMintChainState::SigmaMintChainState() noexcept : block(-1), group(0), index(0) -{ -} - -SigmaMintChainState::SigmaMintChainState(int block, SigmaMintGroup group, SigmaMintIndex index) noexcept : - block(block), - group(group), - index(index) -{ -} - -bool SigmaMintChainState::operator==(const SigmaMintChainState& other) const noexcept -{ - return block == other.block && group == other.group && index == other.index; -} - -bool SigmaMintChainState::operator!=(const SigmaMintChainState& other) const noexcept -{ - return !(*this == other); -} - -void SigmaMintChainState::Clear() noexcept -{ - block = -1; - group = 0; - index = 0; -} - -// SigmaMint Implementation. - -SigmaMint::SigmaMint() : property(0), denomination(0) -{ -} - -SigmaMint::SigmaMint(PropertyId property, SigmaDenomination denomination, CKeyID const &seedId, uint160 const &serialId) : - property(property), denomination(denomination), seedId(seedId), serialId(serialId) -{ -} - -bool SigmaMint::operator==(const SigmaMint& other) const -{ - return property == other.property && - denomination == other.denomination && - seedId == other.seedId && - serialId == other.serialId && - createdTx == other.createdTx && - chainState == other.chainState && - spendTx == other.spendTx; -} - -bool SigmaMint::operator!=(const SigmaMint& other) const -{ - return !(*this == other); -} - -// SigmaMintId Implementation. -SigmaMintId::SigmaMintId() : property(0), denomination(0) -{ -} - -SigmaMintId::SigmaMintId(PropertyId property, SigmaDenomination denomination, const SigmaPublicKey& pubKey) : - property(property), - denomination(denomination), - pubKey(pubKey) -{ -} - -bool SigmaMintId::operator==(const SigmaMintId& other) const -{ - return property == other.property && denomination == other.denomination && pubKey == other.pubKey; -} - -bool SigmaMintId::operator!=(const SigmaMintId& other) const -{ - return !(*this == other); -} - -// SigmaSpend Implementation. - -SigmaSpend::SigmaSpend(const SigmaMintId& mint, SigmaMintGroup group, size_t groupSize, const SigmaProof& proof) : - mint(mint), - group(group), - groupSize(groupSize), - proof(proof) -{ -} - -} // namespace elysium diff --git a/src/elysium/walletmodels.h b/src/elysium/walletmodels.h deleted file mode 100644 index 31c2192264..0000000000 --- a/src/elysium/walletmodels.h +++ /dev/null @@ -1,209 +0,0 @@ -#ifndef FIRO_ELYSIUM_WALLETMODELS_H -#define FIRO_ELYSIUM_WALLETMODELS_H - -#include "property.h" -#include "sigmaprimitives.h" - -#include "../pubkey.h" -#include "../serialize.h" -#include "../uint256.h" - -#include -#include - -#include - -namespace elysium { - -class SigmaMintChainState -{ -public: - int block; - SigmaMintGroup group; - SigmaMintIndex index; - -public: - SigmaMintChainState() noexcept; - SigmaMintChainState(int block, SigmaMintGroup group, SigmaMintIndex index) noexcept; - - bool operator==(const SigmaMintChainState& other) const noexcept; - bool operator!=(const SigmaMintChainState& other) const noexcept; - - void Clear() noexcept; - - ADD_SERIALIZE_METHODS; - -private: - template - void SerializationOp(Stream& s, Operation ser_action) - { - int32_t block = this->block; - - READWRITE(block); - READWRITE(group); - READWRITE(index); - - this->block = block; - } -}; - -class SigmaMintId -{ -public: - PropertyId property; - SigmaDenomination denomination; - SigmaPublicKey pubKey; - -public: - SigmaMintId(); - SigmaMintId(PropertyId property, SigmaDenomination denomination, const SigmaPublicKey& key); - - bool operator==(const SigmaMintId& other) const; - bool operator!=(const SigmaMintId& other) const; - - ADD_SERIALIZE_METHODS; - -private: - template - void SerializationOp(Stream& s, Operation ser_action) - { - READWRITE(property); - READWRITE(denomination); - READWRITE(pubKey); - } -}; - -class SigmaMint -{ -public: - PropertyId property; - SigmaDenomination denomination; - CKeyID seedId; - uint160 serialId; - - uint256 createdTx; - SigmaMintChainState chainState; - uint256 spendTx; - -public: - SigmaMint(); - SigmaMint(PropertyId property, SigmaDenomination denomination, CKeyID const &seedId, uint160 const &serialId); - - bool operator==(const SigmaMint& other) const; - bool operator!=(const SigmaMint& other) const; - - bool IsOnChain() const - { - return chainState.block >= 0; - } - - bool IsSpent() const - { - return !spendTx.IsNull(); - } - - ADD_SERIALIZE_METHODS; - -private: - template - void SerializationOp(Stream& s, Operation ser_action) - { - READWRITE(property); - READWRITE(denomination); - READWRITE(seedId); - READWRITE(serialId); - READWRITE(createdTx); - READWRITE(chainState); - READWRITE(spendTx); - } -}; - -class SigmaSpend -{ -public: - SigmaMintId mint; - SigmaMintGroup group; - size_t groupSize; - SigmaProof proof; - -public: - SigmaSpend(const SigmaMintId& mint, SigmaMintGroup group, size_t groupSize, const SigmaProof& proof); -}; - -} // namespace elysium - -namespace std { - -using namespace elysium; - -// std::hash specialization. - -template<> -struct hash -{ - size_t operator()(const SigmaMintChainState& state) const - { - return hash()(state.block) - ^ hash()(state.group) - ^ hash()(state.index); - } -}; - -template<> -struct hash -{ - size_t operator()(const SigmaMintId& id) const - { - return hash()(id.property) - ^ hash()(id.denomination) - ^ hash()(id.pubKey); - } -}; - -template<> -struct hash -{ - size_t operator()(const SigmaMint& mint) const - { - return hash()(mint.property) - ^ hash()(mint.denomination) - ^ hash()(mint.seedId) - ^ hash()(mint.serialId) - ^ hash()(mint.createdTx) - ^ hash()(mint.chainState) - ^ hash()(mint.spendTx); - } -}; - -// basic_ostream supports. - -template -basic_ostream& operator<<(basic_ostream& os, const SigmaMintId& id) -{ - return os << "{property: " << id.property << ", denomination: " << static_cast(id.denomination) << ", pubKey: " << id.pubKey << '}'; -} - -template -basic_ostream& operator<<(basic_ostream& os, const SigmaMintChainState& state) -{ - return os << "{block: " << state.block << ", group: " << state.group << ", index: " << state.index << '}'; -} - -template -basic_ostream& operator<<(basic_ostream& os, const SigmaMint& mint) -{ - os << '{'; - os << "property: " << mint.property << ", "; - os << "denomination: " << mint.denomination << ", "; - os << "seedId: " << mint.seedId.GetHex() << ", "; - os << "serialId: " << mint.serialId.GetHex() << ", "; - os << "chainState: " << mint.chainState << ", "; - os << "spentTx: " << mint.spendTx.GetHex(); - os << '}'; - - return os; -} - -} // namespace std - -#endif // FIRO_ELYSIUM_WALLETMODELS_H diff --git a/src/elysium/wallettxs.cpp b/src/elysium/wallettxs.cpp deleted file mode 100644 index 8fac61c5a2..0000000000 --- a/src/elysium/wallettxs.cpp +++ /dev/null @@ -1,305 +0,0 @@ -#include "elysium/wallettxs.h" - -#include "elysium/log.h" -#include "elysium/elysium.h" -#include "elysium/rules.h" -#include "elysium/script.h" -#include "elysium/utilsbitcoin.h" - -#include "amount.h" -#include "base58.h" -#include "wallet/coincontrol.h" -#include "init.h" -#include "validation.h" -#include "pubkey.h" -#include "script/standard.h" -#include "sync.h" -#include "txmempool.h" -#include "uint256.h" -#include "utilstrencodings.h" -#ifdef ENABLE_WALLET -#include "script/ismine.h" -#include "wallet/wallet.h" -#include "wallet/walletexcept.h" -#endif - -#include -#include -#include -#include - -namespace elysium -{ -/** - * Retrieves a public key from the wallet, or converts a hex-string to a public key. - */ -bool AddressToPubKey(const std::string& key, CPubKey& pubKey) -{ -#ifdef ENABLE_WALLET - // Case 1: Bitcoin address and the key is in the wallet - CBitcoinAddress address(key); - if (pwalletMain && address.IsValid()) { - CKeyID keyID; - if (!address.GetKeyID(keyID)) { - PrintToLog("%s() ERROR: redemption address %s does not refer to a public key\n", __func__, key); - return false; - } - if (!pwalletMain->GetPubKey(keyID, pubKey)) { - PrintToLog("%s() ERROR: no public key in wallet for redemption address %s\n", __func__, key); - return false; - } - } - // Case 2: Hex-encoded public key - else -#endif - if (IsHex(key)) { - pubKey = CPubKey(ParseHex(key)); - } - - if (!pubKey.IsFullyValid()) { - PrintToLog("%s() ERROR: invalid redemption key %s\n", __func__, key); - return false; - } - - return true; -} - -/** - * Checks, whether enough spendable outputs are available to pay for transaction fees. - */ -bool CheckFee(const std::string& fromAddress, size_t nDataSize) -{ - int64_t minFee = 0; - int64_t feePerKB = 0; - int64_t inputTotal = 0; -#ifdef ENABLE_WALLET - bool fUseClassC = UseEncodingClassC(nDataSize); - - CCoinControl coinControl; - inputTotal = SelectCoins(fromAddress, coinControl, 0); - - // calculate the estimated fee per KB based on the currently set confirm target - CFeeRate feeRate = mempool.estimateFee(nTxConfirmTarget); - - // if there is not enough data (and zero is estimated) then base minimum on a fairly high/safe 50,000 satoshi fee per KB - if (feeRate == CFeeRate(0)) { - feePerKB = 50000; - } else { - feePerKB = feeRate.GetFeePerK(); - } - - // we do not know the size of the transaction at this point. Warning calculation employs some guesswork - if (!fUseClassC) { - // Calculation based on a 3KB transaction due to: - // - the average size across all Class B transactions ever sent to date is 909 bytes. - // - under 2% of Class B transactions are over 2KB, under 0.6% of transactions are over 3KB. - // Thus if created transaction will be over 3KB (rare as per above) warning may not be sufficient. - minFee = feePerKB * 3; - } else { - // Averages for Class C transactions are not yet available, Calculation based on a 2KB transaction due to: - // - Class B values but considering Class C removes outputs for both data and Elysium (reduces size). - minFee = feePerKB * 2; - } -#endif - return inputTotal >= minFee; -} - -/** - * Checks, whether the output qualifies as input for a transaction. - */ -bool CheckInput(const CTxOut& txOut, int nHeight, CTxDestination& dest) -{ - txnouttype whichType; - - if (!GetOutputType(txOut.scriptPubKey, whichType)) { - return false; - } - if (!IsAllowedInputType(whichType, nHeight)) { - return false; - } - if (!ExtractDestination(txOut.scriptPubKey, dest)) { - return false; - } - - return true; -} - -/** - * Retrieves the label, used by the UI, for an address from the wallet. - */ -std::string GetAddressLabel(const std::string& address) -{ - std::string addressLabel; -#ifdef ENABLE_WALLET - if (pwalletMain) { - LOCK(pwalletMain->cs_wallet); - - CBitcoinAddress addressParsed(address); - std::map::const_iterator mi = pwalletMain->mapAddressBook.find(addressParsed.Get()); - if (mi != pwalletMain->mapAddressBook.end()) { - addressLabel = mi->second.name; - } - } -#endif - return addressLabel; -} - -/** - * IsMine wrapper to determine whether the address is in the wallet. - */ -int IsMyAddress(const std::string& address) -{ -#ifdef ENABLE_WALLET - if (pwalletMain) { - LOCK(pwalletMain->cs_wallet); - - CBitcoinAddress parsedAddress(address); - isminetype isMine = IsMine(*pwalletMain, parsedAddress.Get()); - - return static_cast(isMine); - } -#endif - return 0; -} - -/** - * Estimate the minimum fee considering user set parameters and the required fee. - * - * @return The estimated fee per 1000 byte, or 50000 satoshi as per default - */ -static int64_t GetEstimatedFeePerKb() -{ - int64_t nFee = 50000; // 0.0005 BTC; - -#ifdef ENABLE_WALLET - if (pwalletMain) { - nFee = pwalletMain->GetMinimumFee(1000, nTxConfirmTarget, mempool); - } -#endif - - return nFee; -} - -/** - * Output values below this value are considered uneconomic, because it would - * require more fees to pay than the output is worth. - * - * @param txOut[in] The transaction output to check - * @return The minimum value an output to spent should have - */ -static int64_t GetEconomicThreshold(const CTxOut& txOut) -{ - // Minimum value needed to relay the transaction - int64_t nThresholdDust = txOut.GetDustThreshold(minRelayTxFee); - - // Use the estimated fee that is also used to contruct transactions. - // We use the absolute minimum, so we divide by 3, to get rid of the - // safety margin used for the dust threshold used for relaying. - CFeeRate estimatedFeeRate(GetEstimatedFeePerKb()); - int64_t nThresholdFees = txOut.GetDustThreshold(estimatedFeeRate) / 3; - - return std::max(nThresholdDust, nThresholdFees); -} - -/** - * Selects spendable outputs to create a transaction. - */ -int64_t SelectCoins(const std::string& fromAddress, CCoinControl& coinControl, int64_t additional, InputMode inputMode) -{ - // total output funds collected - int64_t nTotal = 0; - -#ifdef ENABLE_WALLET - if (NULL == pwalletMain) { - return 0; - } - - // select coins to cover up to 20 kB max. transaction size - int64_t nMax = 20 * GetEstimatedFeePerKb(); - - // if referenceamount is set it is needed to be accounted for here too - if (0 < additional) nMax += additional; - - int nHeight = GetHeight(); - LOCK2(cs_main, pwalletMain->cs_wallet); - - switch (inputMode) { - case InputMode::NORMAL: - // iterate over the wallet - for (std::map::const_iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { - const uint256& txid = it->first; - const CWalletTx& wtx = it->second; - - if (!wtx.IsTrusted()) { - continue; - } - if (!wtx.GetAvailableCredit()) { - continue; - } - - for (unsigned int n = 0; n < wtx.tx->vout.size(); n++) { - const CTxOut& txOut = wtx.tx->vout[n]; - - CTxDestination dest; - if (!CheckInput(txOut, nHeight, dest)) { - continue; - } - - if (!IsMine(*pwalletMain, dest)) { - continue; - } - - if (pwalletMain->IsSpent(txid, n)) { - continue; - } - if (txOut.nValue < GetEconomicThreshold(txOut)) { - if (elysium_debug_tokens) - PrintToLog("%s: output value below economic threshold: %s:%d, value: %d\n", - __func__, txid.GetHex(), n, txOut.nValue); - continue; - } - - std::string sAddress = CBitcoinAddress(dest).ToString(); - if (elysium_debug_tokens) - PrintToLog("%s: sender: %s, outpoint: %s:%d, value: %d\n", __func__, sAddress, txid.GetHex(), n, txOut.nValue); - - // only use funds from the sender's address - if (fromAddress == sAddress) { - COutPoint outpoint(txid, n); - coinControl.Select(outpoint); - - nTotal += txOut.nValue; - - if (nMax <= nTotal) break; - } - } - - if (nMax <= nTotal) break; - } - break; - case InputMode::SIGMA: - std::vector coinsToSpend; - std::vector remints; - try { - std::list sigmaCoins = pwalletMain->GetAvailableCoins(); - pwalletMain->GetCoinsToSpend(nMax, coinsToSpend, remints, sigmaCoins); - } catch (std::exception const &err) { - LogPrintf("SelectCoins() fail to get coin to spend: %s\n", err.what()); - return nTotal; - } - for (auto const &mint : coinsToSpend) { - COutPoint coin; - if (sigma::GetOutPoint(coin, mint.value)) { - nTotal += mint.get_denomination_value(); - coinControl.Select(coin); - } - } - break; - }; -#endif - - return nTotal; -} - - -} // namespace elysium diff --git a/src/elysium/wallettxs.h b/src/elysium/wallettxs.h deleted file mode 100644 index da2af15999..0000000000 --- a/src/elysium/wallettxs.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef ELYSIUM_WALLETTXS_H -#define ELYSIUM_WALLETTXS_H - -class CCoinControl; -class CPubKey; - -#include "script/standard.h" -#include "elysium.h" - -#include -#include - -namespace elysium -{ -/** Retrieves a public key from the wallet, or converts a hex-string to a public key. */ -bool AddressToPubKey(const std::string& key, CPubKey& pubKey); - -/** Checks, whether enough spendable outputs are available to pay for transaction fees. */ -bool CheckFee(const std::string& fromAddress, size_t nDataSize); - -/** Checks, whether the output qualifies as input for a transaction. */ -bool CheckInput(const CTxOut& txOut, int nHeight, CTxDestination& dest); - -/** Retrieves the label, used by the UI, for an address from the wallet. */ -std::string GetAddressLabel(const std::string& address); - -/** IsMine wrapper to determine whether the address is in the wallet. */ -int IsMyAddress(const std::string& address); - -/** Selects spendable outputs to create a transaction. */ -int64_t SelectCoins(const std::string& fromAddress, CCoinControl& coinControl, int64_t additional = 0, - InputMode inputMode = InputMode::NORMAL); -} - -#endif // ELYSIUM_WALLETTXS_H diff --git a/src/init.cpp b/src/init.cpp index ef2d083275..1b2c071448 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -61,10 +61,6 @@ #include "evo/deterministicmns.h" #include "llmq/quorums_init.h" -#ifdef ENABLE_ELYSIUM -#include "elysium/elysium.h" -#endif - #include #include #include @@ -304,12 +300,6 @@ void Shutdown() evoDb = NULL; } -#ifdef ENABLE_ELYSIUM - if (isElysiumEnabled()) { - elysium_shutdown(); - } -#endif - #ifdef ENABLE_WALLET if (pwalletMain) pwalletMain->Flush(true); @@ -365,7 +355,6 @@ static void HandleSIGTERM(int) void HandleSIGHUP(int) { fReopenDebugLog = true; - fReopenElysiumLog = true; } #else static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) @@ -598,23 +587,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-rpcforceutf8", strprintf("Replace invalid UTF-8 encoded characters with question marks in RPC response (default: %d)", 1)); } -#ifdef ENABLE_ELYSIUM - strUsage += HelpMessageGroup("Elysium options:"); - strUsage += HelpMessageOpt("-elysium", "Enable Elysium"); - strUsage += HelpMessageOpt("-startclean", "Clear all persistence files on startup; triggers reparsing of Elysium transactions"); - strUsage += HelpMessageOpt("-elysiumtxcache=", "The maximum number of transactions in the input transaction cache (default: 500000)"); - strUsage += HelpMessageOpt("-elysiumprogressfrequency=", "Time in seconds after which the initial scanning progress is reported (default: 30)"); - strUsage += HelpMessageOpt("-elysiumdebug=", "Enable or disable log categories, can be \"all\" or \"none\""); - strUsage += HelpMessageOpt("-autocommit=", "Enable or disable broadcasting of transactions, when creating transactions (default: 1)"); - strUsage += HelpMessageOpt("-overrideforcedshutdown=", "Disable force shutdown when error (default: 0)"); - strUsage += HelpMessageOpt("-elysiumalertallowsender=", "Whitelist senders of alerts, can be \"any\")"); - strUsage += HelpMessageOpt("-elysiumalertignoresender=", "Ignore senders of alerts"); - strUsage += HelpMessageOpt("-elysiumactivationignoresender=", "Ignore senders of activations"); - strUsage += HelpMessageOpt("-elysiumactivationallowsender=", "Whitelist senders of activations"); - strUsage += HelpMessageOpt("-elysiumuiwalletscope=", "Max. transactions to show in trade and transaction history (default: 65535)"); - strUsage += HelpMessageOpt("-elysiumshowblockconsensushash=", "Calculate and log the consensus hash for the specified block"); -#endif - strUsage += HelpMessageOpt("-skipmnpayoutcheck", _("Do not check for masternode payout when handling listtransactions, listsinceblock and gettransaction calls (improves performance)")); return strUsage; @@ -1955,53 +1927,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("No wallet support compiled in!\n"); #endif // !ENABLE_WALLET - // ********************************************************* Step 8.5: load elysium - -#ifdef ENABLE_ELYSIUM - if (isElysiumEnabled()) { - if (!fTxIndex) { - // ask the user if they would like us to modify their config file for them - std::string msg = _("Disabled transaction index detected.\n\n" - "Elysium requires an enabled transaction index. To enable " - "transaction indexing, please use the \"-txindex\" option as " - "command line argument or add \"txindex=1\" to your client " - "configuration file within your data directory.\n\n" - "Configuration file"); // allow translation of main text body while still allowing differing config file string - msg += ": " + GetConfigFile("").string() + "\n\n"; - msg += _("Would you like Elysium to attempt to update your configuration file accordingly?"); - bool fRet = uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_INFORMATION | CClientUIInterface::BTN_OK | CClientUIInterface::MODAL | CClientUIInterface::BTN_ABORT); - if (fRet) { - // add txindex=1 to config file in GetConfigFile() - boost::filesystem::path configPathInfo = GetConfigFile(""); - FILE *fp = fopen(configPathInfo.string().c_str(), "at"); - if (!fp) { - std::string failMsg = _("Unable to update configuration file at"); - failMsg += ":\n" + GetConfigFile("").string() + "\n\n"; - failMsg += _("The file may be write protected or you may not have the required permissions to edit it.\n"); - failMsg += _("Please add txindex=1 to your configuration file manually.\n\nElysium will now shutdown."); - return InitError(failMsg); - } - fprintf(fp, "\ntxindex=1\n"); - fflush(fp); - fclose(fp); - std::string strUpdated = _( - "Your configuration file has been updated.\n\n" - "Elysium will now shutdown - please restart the client for your new configuration to take effect."); - uiInterface.ThreadSafeMessageBox(strUpdated, "", CClientUIInterface::MSG_INFORMATION | CClientUIInterface::BTN_OK | CClientUIInterface::MODAL); - return false; - } else { - return InitError(_("Please add txindex=1 to your configuration file manually.\n\nOmni Core will now shutdown.")); - } - } - - uiInterface.InitMessage(_("Parsing Elysium transactions...")); - elysium_init(); - - // Elysium code should be initialized and wallet should now be loaded, perform an initial populate - CheckWalletUpdate(); - } -#endif - // ********************************************************* Step 9: data directory maintenance LogPrintf("Step 9: data directory maintenance **********************\n"); // if pruning, unset the service bit and perform the initial blockstore prune diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 8ade56f1d5..ed9bee3465 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -368,7 +368,6 @@ class CTransaction { public: // Default transaction version. - // TODO: confirm Exodus works with transaction v2 and change it to 2 here static const int32_t CURRENT_VERSION=1; // Changing the default transaction version requires a two step process: first diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index 5f02b5956f..af8ae02326 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -59,17 +59,6 @@ res/icons/tools.png res/icons/exchange.png res/icons/balances.png - res/icons/elysium_in.png - res/icons/elysium_inout.png - res/icons/elysium_invalid.png - res/icons/elysium_out.png - res/icons/meta_cancelled.png - res/icons/meta_filled.png - res/icons/meta_open.png - res/icons/meta_partcancelled.png - res/icons/meta_partfilled.png - res/icons/meta_pending.png - res/icons/elysium_hourglass.png res/icons/lelantus.png res/icons/paymentcode.png res/icons/ext_add.png diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index fe27475ed2..7fd12eca39 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -40,12 +40,6 @@ #include "evo/deterministicmns.h" #include "masternode-sync.h" #include "masternodelist.h" -#include "elysium_qtutils.h" - -#ifdef ENABLE_ELYSIUM -#include "../elysium/elysium.h" -#endif - #include #include @@ -101,17 +95,11 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle * labelWalletHDStatusIcon(0), connectionsControl(0), labelBlocksIcon(0), - labelElysiumPendingIcon(0), - labelElysiumPendingText(0), progressBarLabel(0), progressBar(0), progressDialog(0), appMenuBar(0), overviewAction(0), -#ifdef ENABLE_ELYSIUM - elyAssetsAction(0), - toolboxAction(0), -#endif historyAction(0), quitAction(0), sendCoinsAction(0), @@ -253,13 +241,6 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle * framePendingLayout->setContentsMargins(3,0,3,0); framePendingLayout->setSpacing(3); framePendingLayout->addStretch(); - labelElysiumPendingIcon = new QLabel(); - labelElysiumPendingText = new QLabel("You have Elysium transactions awaiting confirmation."); - framePendingLayout->addWidget(labelElysiumPendingIcon); - framePendingLayout->addWidget(labelElysiumPendingText); - framePendingLayout->addStretch(); - labelElysiumPendingIcon->hide(); - labelElysiumPendingText->hide(); // Progress bar and label for blocks download progressBarLabel = new QLabel(); @@ -385,26 +366,6 @@ void BitcoinGUI::createActions() tabGroup->addAction(masternodeAction); #endif -#ifdef ENABLE_ELYSIUM - bool elysiumEnabled = isElysiumEnabled(); - - if (elysiumEnabled) { - elyAssetsAction = new QAction(tr("E&lyAssets"), this); - elyAssetsAction->setStatusTip(tr("Show Elysium balances")); - elyAssetsAction->setToolTip(elyAssetsAction->statusTip()); - elyAssetsAction->setCheckable(true); - elyAssetsAction->setShortcut(QKeySequence(Qt::ALT + key++)); - tabGroup->addAction(elyAssetsAction); - - toolboxAction = new QAction(tr("&Toolbox"), this); - toolboxAction->setStatusTip(tr("Tools to obtain varions Elysium information and transaction information")); - toolboxAction->setToolTip(toolboxAction->statusTip()); - toolboxAction->setCheckable(true); - toolboxAction->setShortcut(QKeySequence(Qt::ALT + key++)); - tabGroup->addAction(toolboxAction); - } -#endif - createPcodeAction = new QAction(tr("RA&P addresses"), this); createPcodeAction->setStatusTip(tr("Create RAP addresses (BIP47 payment codes)")); createPcodeAction->setToolTip(createPcodeAction->statusTip()); @@ -430,14 +391,6 @@ void BitcoinGUI::createActions() connect(lelantusAction, &QAction::triggered, this, &BitcoinGUI::gotoLelantusPage); connect(createPcodeAction, &QAction::triggered, this, &BitcoinGUI::gotoCreatePcodePage); -#ifdef ENABLE_ELYSIUM - if (elysiumEnabled) { - connect(elyAssetsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); - connect(elyAssetsAction, &QAction::triggered, this, &BitcoinGUI::gotoElyAssetsPage); - connect(toolboxAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); - connect(toolboxAction, &QAction::triggered, this, &BitcoinGUI::gotoToolboxPage); - } -#endif #endif // ENABLE_WALLET quitAction = new QAction(tr("E&xit"), this); @@ -577,13 +530,6 @@ void BitcoinGUI::createToolBars() toolbar->addAction(historyAction); toolbar->addAction(lelantusAction); toolbar->addAction(masternodeAction); - -#ifdef ENABLE_ELYSIUM - if (isElysiumEnabled()) { - toolbar->addAction(elyAssetsAction); - toolbar->addAction(toolboxAction); - } -#endif toolbar->addAction(createPcodeAction); QLabel *logoLabel = new QLabel(); @@ -630,9 +576,6 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) rpcConsole->setClientModel(_clientModel); #ifdef ENABLE_WALLET - // Update Elysium pending status - connect(_clientModel, &ClientModel::refreshElysiumPending, this, &BitcoinGUI::setElysiumPendingStatus); - if(walletFrame) { walletFrame->setClientModel(_clientModel); @@ -727,13 +670,6 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) usedSendingAddressesAction->setEnabled(enabled); usedReceivingAddressesAction->setEnabled(enabled); openAction->setEnabled(enabled); - -#ifdef ENABLE_ELYSIUM - if (isElysiumEnabled()) { - elyAssetsAction->setEnabled(enabled); - toolboxAction->setEnabled(enabled); - } -#endif } void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle) @@ -849,42 +785,18 @@ void BitcoinGUI::gotoOverviewPage() if (walletFrame) walletFrame->gotoOverviewPage(); } -#ifdef ENABLE_ELYSIUM -void BitcoinGUI::gotoElyAssetsPage() -{ - elyAssetsAction->setChecked(true); - if (walletFrame) walletFrame->gotoElyAssetsPage(); -} -#endif - void BitcoinGUI::gotoHistoryPage() { historyAction->setChecked(true); if (walletFrame) walletFrame->gotoHistoryPage(); } -#ifdef ENABLE_ELYSIUM -void BitcoinGUI::gotoElysiumHistoryTab() -{ - historyAction->setChecked(true); - if (walletFrame) walletFrame->gotoElysiumHistoryTab(); -} -#endif - void BitcoinGUI::gotoBitcoinHistoryTab() { historyAction->setChecked(true); if (walletFrame) walletFrame->gotoBitcoinHistoryTab(); } -#ifdef ENABLE_ELYSIUM -void BitcoinGUI::gotoToolboxPage() -{ - toolboxAction->setChecked(true); - if (walletFrame) walletFrame->gotoToolboxPage(); -} -#endif - void BitcoinGUI::gotoMasternodePage() { QSettings settings; @@ -1312,19 +1224,6 @@ bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient) return false; } -void BitcoinGUI::setElysiumPendingStatus(bool pending) -{ - if (!pending) { - labelElysiumPendingIcon->hide(); - labelElysiumPendingText->hide(); - } else { - labelElysiumPendingIcon->show(); - labelElysiumPendingText->show(); - labelElysiumPendingIcon->setPixmap(QIcon(":/icons/elysium_hourglass").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); - labelElysiumPendingIcon->setToolTip(tr("You have Elysium transactions awaiting confirmation.")); - } -} - void BitcoinGUI::setHDStatus(int hdEnabled) { labelWalletHDStatusIcon->setPixmap(QIcon(hdEnabled ? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index a4da2cc4d8..514b0f3501 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -92,18 +92,12 @@ class BitcoinGUI : public QMainWindow QLabel *labelWalletHDStatusIcon; GUIUtil::ClickableLabel *connectionsControl; GUIUtil::ClickableLabel *labelBlocksIcon; - QLabel *labelElysiumPendingIcon; - QLabel *labelElysiumPendingText; QLabel *progressBarLabel; GUIUtil::ClickableProgressBar *progressBar; QProgressDialog *progressDialog; QMenuBar *appMenuBar; QAction *overviewAction; -#ifdef ENABLE_ELYSIUM - QAction *elyAssetsAction; - QAction *toolboxAction; -#endif QAction *historyAction; QAction *quitAction; QAction *sendCoinsAction; @@ -200,8 +194,6 @@ public Q_SLOTS: */ void setEncryptionStatus(int status); - /** Set the Elysium pending transactions label **/ - void setElysiumPendingStatus(bool pending); /** Set the hd-enabled status as shown in the UI. @param[in] status current hd enabled status @see WalletModel::EncryptionStatus @@ -218,14 +210,6 @@ public Q_SLOTS: #ifdef ENABLE_WALLET /** Switch to overview (home) page */ void gotoOverviewPage(); -#ifdef ENABLE_ELYSIUM - /** Switch to ElyAssets page */ - void gotoElyAssetsPage(); - /** Switch to utility page */ - void gotoToolboxPage(); - /** Switch directly to Elysium history tab */ - void gotoElysiumHistoryTab(); -#endif /** Switch to history (transactions) page */ void gotoHistoryPage(); /** Switch directly to Firo history tab */ diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 5a63e65806..a26f1cf886 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -57,14 +57,6 @@ QT_TRANSLATE_NOOP("firo-core", "" "Delete all wallet transactions and only recover those parts of the " "blockchain through -rescan on startup"), QT_TRANSLATE_NOOP("firo-core", "" -"Disabled transaction index detected.\n" -"\n" -"Exodus requires an enabled transaction index. To enable transaction " -"indexing, please use the \"-txindex\" option as command line argument or add " -"\"txindex=1\" to your client configuration file within your data directory.\n" -"\n" -"Configuration file"), -QT_TRANSLATE_NOOP("firo-core", "" "Discover own IP addresses (default: 1 when listening and no -externalip or -" "proxy)"), QT_TRANSLATE_NOOP("firo-core", "" @@ -162,10 +154,6 @@ QT_TRANSLATE_NOOP("firo-core", "" QT_TRANSLATE_NOOP("firo-core", "" "Please add txindex=1 to your configuration file manually.\n" "\n" -"Exodus will now shutdown."), -QT_TRANSLATE_NOOP("firo-core", "" -"Please add txindex=1 to your configuration file manually.\n" -"\n" "Omni Core will now shutdown."), QT_TRANSLATE_NOOP("firo-core", "" "Please check that your computer's date and time are correct! If your clock " @@ -305,9 +293,6 @@ QT_TRANSLATE_NOOP("firo-core", "" "Whitelisted peers cannot be DoS banned and their transactions are always " "relayed, even if they are already in the mempool, useful e.g. for a gateway"), QT_TRANSLATE_NOOP("firo-core", "" -"Would you like Exodus to attempt to update your configuration file " -"accordingly?"), -QT_TRANSLATE_NOOP("firo-core", "" "You must specify a znodeprivkey in the configuration. Please see " "documentation for help."), QT_TRANSLATE_NOOP("firo-core", "" @@ -316,11 +301,6 @@ QT_TRANSLATE_NOOP("firo-core", "" QT_TRANSLATE_NOOP("firo-core", "" "You need to rebuild the database using -reindex-chainstate to change -txindex"), QT_TRANSLATE_NOOP("firo-core", "" -"Your configuration file has been updated.\n" -"\n" -"Exodus will now shutdown - please restart the client for your new " -"configuration to take effect."), -QT_TRANSLATE_NOOP("firo-core", "" "it has to have at least two mint coins with at least 2 confirmation in order " "to spend a coin"), QT_TRANSLATE_NOOP("firo-core", "" @@ -483,7 +463,6 @@ QT_TRANSLATE_NOOP("firo-core", "One of minted coin does not found in the chain") QT_TRANSLATE_NOOP("firo-core", "One of the minted coin is invalid"), QT_TRANSLATE_NOOP("firo-core", "Only connect to nodes in network (ipv4, ipv6 or onion)"), QT_TRANSLATE_NOOP("firo-core", "Options:"), -QT_TRANSLATE_NOOP("firo-core", "Parsing Exodus transactions..."), QT_TRANSLATE_NOOP("firo-core", "Pass named instead of positional arguments (default: %s)"), QT_TRANSLATE_NOOP("firo-core", "Password for JSON-RPC connections"), QT_TRANSLATE_NOOP("firo-core", "Port: %d"), diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 870c0775d9..023c012a36 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -34,9 +34,7 @@ ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent) : optionsModel(_optionsModel), peerTableModel(0), banTableModel(0), - pollTimer(0), - lockedElysiumStateChanged(false), - lockedElysiumBalanceChanged(false) + pollTimer(0) { cachedBestHeaderHeight = -1; cachedBestHeaderTime = -1; @@ -182,51 +180,6 @@ void ClientModel::updateNumConnections(int numConnections) Q_EMIT numConnectionsChanged(numConnections); } - -void ClientModel::invalidateElysiumState() -{ - Q_EMIT reinitElysiumState(); -} - -void ClientModel::updateElysiumState() -{ - lockedElysiumStateChanged = false; - Q_EMIT refreshElysiumState(); -} - -bool ClientModel::tryLockElysiumStateChanged() -{ - // Try to avoid Elysium queuing too many messages for the UI - if (lockedElysiumStateChanged) { - return false; - } - - lockedElysiumStateChanged = true; - return true; -} - -void ClientModel::updateElysiumBalance() -{ - lockedElysiumBalanceChanged = false; - Q_EMIT refreshElysiumBalance(); -} - -bool ClientModel::tryLockElysiumBalanceChanged() -{ - // Try to avoid Elysium queuing too many messages for the UI - if (lockedElysiumBalanceChanged) { - return false; - } - - lockedElysiumBalanceChanged = true; - return true; -} - -void ClientModel::updateElysiumPending(bool pending) -{ - Q_EMIT refreshElysiumPending(pending); -} - void ClientModel::updateNetworkActive(bool networkActive) { Q_EMIT networkActiveChanged(networkActive); @@ -319,35 +272,6 @@ void ClientModel::updateBanlist() banTableModel->refresh(); } -// Handlers for core signals -static void ElysiumStateInvalidated(ClientModel *clientmodel) -{ - // This will be triggered if a reorg invalidates the state - QMetaObject::invokeMethod(clientmodel, "invalidateElysiumState", Qt::QueuedConnection); -} - -static void ElysiumStateChanged(ClientModel *clientmodel) -{ - // This will be triggered for each block that contains Elysium layer transactions - if (clientmodel->tryLockElysiumStateChanged()) { - QMetaObject::invokeMethod(clientmodel, "updateElysiumState", Qt::QueuedConnection); - } -} - -static void ElysiumBalanceChanged(ClientModel *clientmodel) -{ - // Triggered when a balance for a wallet address changes - if (clientmodel->tryLockElysiumBalanceChanged()) { - QMetaObject::invokeMethod(clientmodel, "updateElysiumBalance", Qt::QueuedConnection); - } -} - -static void ElysiumPendingChanged(ClientModel *clientmodel, bool pending) -{ - // Triggered when Elysium pending map adds/removes transactions - QMetaObject::invokeMethod(clientmodel, "updateElysiumPending", Qt::QueuedConnection, Q_ARG(bool, pending)); -} - static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress) { // emits signal "showProgress" @@ -440,12 +364,6 @@ void ClientModel::subscribeToCoreSignals() uiInterface.NotifyHeaderTip.connect(boost::bind(BlockTipChanged, this, _1, _2, true)); uiInterface.NotifyAdditionalDataSyncProgressChanged.connect(boost::bind(NotifyAdditionalDataSyncProgressChanged, this, _1)); uiInterface.NotifyMasternodeListChanged.connect(boost::bind(NotifyMasternodeListChanged, this, _1)); - - // Connect Elysium signals - uiInterface.ElysiumStateChanged.connect(boost::bind(ElysiumStateChanged, this)); - uiInterface.ElysiumPendingChanged.connect(boost::bind(ElysiumPendingChanged, this, _1)); - uiInterface.ElysiumBalanceChanged.connect(boost::bind(ElysiumBalanceChanged, this)); - uiInterface.ElysiumStateInvalidated.connect(boost::bind(ElysiumStateInvalidated, this)); } void ClientModel::unsubscribeFromCoreSignals() @@ -461,10 +379,4 @@ void ClientModel::unsubscribeFromCoreSignals() uiInterface.NotifyHeaderTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, true)); uiInterface.NotifyAdditionalDataSyncProgressChanged.disconnect(boost::bind(NotifyAdditionalDataSyncProgressChanged, this, _1)); uiInterface.NotifyMasternodeListChanged.disconnect(boost::bind(NotifyMasternodeListChanged, this, _1)); - - // Disconnect Elysium signals - uiInterface.ElysiumStateChanged.disconnect(boost::bind(ElysiumStateChanged, this)); - uiInterface.ElysiumPendingChanged.disconnect(boost::bind(ElysiumPendingChanged, this, _1)); - uiInterface.ElysiumBalanceChanged.disconnect(boost::bind(ElysiumBalanceChanged, this)); - uiInterface.ElysiumStateInvalidated.disconnect(boost::bind(ElysiumStateInvalidated, this)); } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 1464e61ff1..750633c15a 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -93,10 +93,6 @@ class ClientModel : public QObject mutable std::atomic cachedBestHeaderHeight; mutable std::atomic cachedBestHeaderTime; - // Try to avoid Elysium queuing too many messages - bool tryLockElysiumStateChanged(); - bool tryLockElysiumBalanceChanged(); - private: OptionsModel *optionsModel; PeerTableModel *peerTableModel; @@ -113,10 +109,6 @@ class ClientModel : public QObject void subscribeToCoreSignals(); void unsubscribeFromCoreSignals(); - // Locks for Elysium state changes - bool lockedElysiumStateChanged; - bool lockedElysiumBalanceChanged; - Q_SIGNALS: void numConnectionsChanged(int count); void masternodeListChanged() const; @@ -127,12 +119,6 @@ class ClientModel : public QObject void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); void additionalDataSyncProgressChanged(double nSyncProgress); - // Additional Elysium signals - void reinitElysiumState(); - void refreshElysiumState(); - void refreshElysiumBalance(); - void refreshElysiumPending(bool pending); - //! Fired when a message should be reported to the user void message(const QString &title, const QString &message, unsigned int style); @@ -148,12 +134,6 @@ public Q_SLOTS: void updateNetworkActive(bool networkActive); void updateAlert(); void updateBanlist(); - - // Additional Elysium slots - void invalidateElysiumState(); - void updateElysiumState(); - void updateElysiumBalance(); - void updateElysiumPending(bool pending); }; #endif // BITCOIN_QT_CLIENTMODEL_H diff --git a/src/qt/elyassetsdialog.cpp b/src/qt/elyassetsdialog.cpp deleted file mode 100644 index 6928c106f0..0000000000 --- a/src/qt/elyassetsdialog.cpp +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "elyassetsdialog.h" -#include "forms/ui_elyassetsdialog.h" - -#include "clientmodel.h" -#include "walletmodel.h" -#include "guiutil.h" - -#include "elysium/elysium.h" -#include "elysium/sp.h" -#include "elysium/tally.h" -#include "elysium/wallettxs.h" - -#include "amount.h" -#include "sync.h" -#include "ui_interface.h" -#include "wallet/wallet.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using std::ostringstream; -using std::string; -using namespace elysium; - -ElyAssetsDialog::ElyAssetsDialog(QWidget *parent) : - QDialog(parent), ui(new Ui::ElyAssetsDialog()), clientModel(0), walletModel(0) -{ - // setup - ui->setupUi(this); - ui->balancesTable->setColumnCount(4); - ui->balancesTable->setHorizontalHeaderItem(0, new QTableWidgetItem("Property ID")); - ui->balancesTable->setHorizontalHeaderItem(1, new QTableWidgetItem("Property Name")); - ui->balancesTable->setHorizontalHeaderItem(2, new QTableWidgetItem("Reserved")); - ui->balancesTable->setHorizontalHeaderItem(3, new QTableWidgetItem("Available")); - - // note neither resizetocontents or stretch allow user to adjust - go interactive then manually set widths - #if QT_VERSION < 0x050000 - ui->balancesTable->horizontalHeader()->setResizeMode(0, QHeaderView::Interactive); - ui->balancesTable->horizontalHeader()->setResizeMode(1, QHeaderView::Interactive); - ui->balancesTable->horizontalHeader()->setResizeMode(2, QHeaderView::Interactive); - ui->balancesTable->horizontalHeader()->setResizeMode(3, QHeaderView::Interactive); - #else - ui->balancesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Interactive); - ui->balancesTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Interactive); - ui->balancesTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Interactive); - ui->balancesTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Interactive); - #endif - ui->balancesTable->setAlternatingRowColors(true); - - // do an initial population - UpdatePropSelector(); - PopulateBalances(2147483646); // 2147483646 = summary (last possible ID for test eco props) - - // initial resizing - ui->balancesTable->resizeColumnToContents(0); - ui->balancesTable->resizeColumnToContents(2); - ui->balancesTable->resizeColumnToContents(3); - ui->balancesTable->verticalHeader()->setVisible(false); - ui->balancesTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->balancesTable->setSelectionBehavior(QAbstractItemView::SelectRows); - ui->balancesTable->setSelectionMode(QAbstractItemView::SingleSelection); - ui->balancesTable->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - ui->balancesTable->setTabKeyNavigation(false); - ui->balancesTable->setContextMenuPolicy(Qt::CustomContextMenu); - ui->balancesTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - - // Actions - QAction *balancesCopyIDAction = new QAction(tr("Copy property ID"), this); - QAction *balancesCopyNameAction = new QAction(tr("Copy property name"), this); - QAction *balancesCopyAddressAction = new QAction(tr("Copy address"), this); - QAction *balancesCopyLabelAction = new QAction(tr("Copy label"), this); - QAction *balancesCopyReservedAmountAction = new QAction(tr("Copy reserved amount"), this); - QAction *balancesCopyAvailableAmountAction = new QAction(tr("Copy available amount"), this); - - contextMenu = new QMenu(); - contextMenu->addAction(balancesCopyLabelAction); - contextMenu->addAction(balancesCopyAddressAction); - contextMenu->addAction(balancesCopyReservedAmountAction); - contextMenu->addAction(balancesCopyAvailableAmountAction); - contextMenuSummary = new QMenu(); - contextMenuSummary->addAction(balancesCopyIDAction); - contextMenuSummary->addAction(balancesCopyNameAction); - contextMenuSummary->addAction(balancesCopyReservedAmountAction); - contextMenuSummary->addAction(balancesCopyAvailableAmountAction); - - // Connect actions - connect(ui->balancesTable, &QWidget::customContextMenuRequested, this, &ElyAssetsDialog::contextualMenu); - connect(ui->propSelectorWidget, qOverload(&QComboBox::activated) , this, &ElyAssetsDialog::propSelectorChanged); - connect(balancesCopyIDAction, &QAction::triggered, this, &ElyAssetsDialog::balancesCopyCol0); - connect(balancesCopyNameAction, &QAction::triggered, this, &ElyAssetsDialog::balancesCopyCol1); - connect(balancesCopyLabelAction, &QAction::triggered, this, &ElyAssetsDialog::balancesCopyCol0); - connect(balancesCopyAddressAction, &QAction::triggered, this, &ElyAssetsDialog::balancesCopyCol1); - connect(balancesCopyReservedAmountAction, &QAction::triggered, this, &ElyAssetsDialog::balancesCopyCol2); - connect(balancesCopyAvailableAmountAction, &QAction::triggered, this, &ElyAssetsDialog::balancesCopyCol3); -} - -ElyAssetsDialog::~ElyAssetsDialog() -{ - delete ui; -} - -void ElyAssetsDialog::reinitEly() -{ - ui->propSelectorWidget->clear(); - ui->balancesTable->setRowCount(0); - UpdatePropSelector(); - PopulateBalances(2147483646); // 2147483646 = summary (last possible ID for test eco props) -} - -void ElyAssetsDialog::setClientModel(ClientModel *model) -{ - this->clientModel = model; - if (model != NULL) { - connect(model, &ClientModel::refreshElysiumBalance, this, &ElyAssetsDialog::balancesUpdated); - connect(model, &ClientModel::reinitElysiumState, this, &ElyAssetsDialog::reinitEly); - } -} - -void ElyAssetsDialog::setWalletModel(WalletModel *model) -{ - this->walletModel = model; - if (model != NULL) { } // do nothing, signals from walletModel no longer needed -} - -void ElyAssetsDialog::UpdatePropSelector() -{ - LOCK(cs_main); - - // don't waste time updating if there are no new properties - if ((uint32_t)ui->propSelectorWidget->count() > global_wallet_property_list.size()) return; - - // a new property has been added to the wallet, update the property selector - QString spId = ui->propSelectorWidget->itemData(ui->propSelectorWidget->currentIndex()).toString(); - ui->propSelectorWidget->clear(); - ui->propSelectorWidget->addItem("Wallet Totals (Summary)","2147483646"); //use last possible ID for summary for now - // populate property selector - for (std::set::iterator it = global_wallet_property_list.begin() ; it != global_wallet_property_list.end(); ++it) { - uint32_t propertyId = *it; - std::string spId = strprintf("%d", propertyId); - std::string spName = getPropertyName(propertyId).c_str(); - if(spName.size()>20) spName=spName.substr(0,20)+"..."; - spName += " (#" + spId + ")"; - ui->propSelectorWidget->addItem(spName.c_str(), spId.c_str()); - } - int propIdx = ui->propSelectorWidget->findData(spId); - if (propIdx != -1) { ui->propSelectorWidget->setCurrentIndex(propIdx); } -} - -void ElyAssetsDialog::AddRow(const std::string& label, const std::string& address, const std::string& reserved, const std::string& available) -{ - int workingRow = ui->balancesTable->rowCount(); - ui->balancesTable->insertRow(workingRow); - QTableWidgetItem *labelCell = new QTableWidgetItem(QString::fromStdString(label)); - QTableWidgetItem *addressCell = new QTableWidgetItem(QString::fromStdString(address)); - QTableWidgetItem *reservedCell = new QTableWidgetItem(QString::fromStdString(reserved)); - QTableWidgetItem *availableCell = new QTableWidgetItem(QString::fromStdString(available)); - labelCell->setTextAlignment(Qt::AlignLeft + Qt::AlignVCenter); - addressCell->setTextAlignment(Qt::AlignLeft + Qt::AlignVCenter); - reservedCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - availableCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - ui->balancesTable->setItem(workingRow, 0, labelCell); - ui->balancesTable->setItem(workingRow, 1, addressCell); - ui->balancesTable->setItem(workingRow, 2, reservedCell); - ui->balancesTable->setItem(workingRow, 3, availableCell); -} - -void ElyAssetsDialog::PopulateBalances(unsigned int propertyId) -{ - ui->balancesTable->setRowCount(0); // fresh slate (note this will automatically cleanup all existing QWidgetItems in the table) - - LOCK(cs_main); - //are we summary? - if(propertyId==2147483646) { - ui->balancesTable->setHorizontalHeaderItem(0, new QTableWidgetItem("Property ID")); - ui->balancesTable->setHorizontalHeaderItem(1, new QTableWidgetItem("Property Name")); - - // loop over the wallet property list and add the wallet totals - for (std::set::iterator it = global_wallet_property_list.begin() ; it != global_wallet_property_list.end(); ++it) { - uint32_t propertyId = *it; - std::string spId = strprintf("%d", propertyId); - std::string spName = getPropertyName(propertyId).c_str(); - std::string available = FormatMP(propertyId, global_balance_money[propertyId]); - std::string reserved = FormatMP(propertyId, global_balance_reserved[propertyId]); - AddRow(spId, spName, reserved, available); - } - } else { - ui->balancesTable->setHorizontalHeaderItem(0, new QTableWidgetItem("Label")); - ui->balancesTable->setHorizontalHeaderItem(1, new QTableWidgetItem("Address")); - bool propertyIsDivisible = isPropertyDivisible(propertyId); // only fetch the SP once, not for every address - - // iterate mp_tally_map looking for addresses that hold a balance in propertyId - for(std::unordered_map::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) { - const std::string& address = my_it->first; - CMPTally& tally = my_it->second; - tally.init(); - - uint32_t id; - bool watchAddress = false, includeAddress = false; - while (0 != (id = (tally.next()))) { - if (id == propertyId) { - includeAddress = true; - break; - } - } - if (!includeAddress) continue; //ignore this address, has never transacted in this propertyId - - // determine if this address is in the wallet - int addressIsMine = IsMyAddress(address); - if (!addressIsMine) continue; // ignore this address, not in wallet - if (addressIsMine != ISMINE_SPENDABLE) watchAddress = true; - - // obtain the balances for the address directly form tally - int64_t available = tally.getMoney(propertyId, BALANCE); - available += tally.getMoney(propertyId, PENDING); - int64_t reserved = tally.getMoney(propertyId, SELLOFFER_RESERVE); - reserved += tally.getMoney(propertyId, ACCEPT_RESERVE); - reserved += tally.getMoney(propertyId, METADEX_RESERVE); - - // format the balances - string reservedStr, availableStr; - if (propertyIsDivisible) { - reservedStr = FormatDivisibleMP(reserved); - availableStr = FormatDivisibleMP(available); - } else { - reservedStr = FormatIndivisibleMP(reserved); - availableStr = FormatIndivisibleMP(available); - } - - // add the row - if (!watchAddress) { - AddRow(GetAddressLabel(my_it->first), address, reservedStr, availableStr); - } else { - AddRow(GetAddressLabel(my_it->first), address + " (watch-only)", reservedStr, availableStr); - } - } - } -} - -void ElyAssetsDialog::propSelectorChanged() -{ - QString spId = ui->propSelectorWidget->itemData(ui->propSelectorWidget->currentIndex()).toString(); - unsigned int propertyId = spId.toUInt(); - PopulateBalances(propertyId); -} - -void ElyAssetsDialog::contextualMenu(const QPoint &point) -{ - QModelIndex index = ui->balancesTable->indexAt(point); - if(index.isValid()) - { - QString spId = ui->propSelectorWidget->itemData(ui->propSelectorWidget->currentIndex()).toString(); - unsigned int propertyId = spId.toUInt(); - if (propertyId == 2147483646) { - contextMenuSummary->exec(QCursor::pos()); - } else { - contextMenu->exec(QCursor::pos()); - } - } -} - -void ElyAssetsDialog::balancesCopyCol0() -{ - GUIUtil::setClipboard(ui->balancesTable->item(ui->balancesTable->currentRow(),0)->text()); -} - -void ElyAssetsDialog::balancesCopyCol1() -{ - GUIUtil::setClipboard(ui->balancesTable->item(ui->balancesTable->currentRow(),1)->text()); -} - -void ElyAssetsDialog::balancesCopyCol2() -{ - GUIUtil::setClipboard(ui->balancesTable->item(ui->balancesTable->currentRow(),2)->text()); -} - -void ElyAssetsDialog::balancesCopyCol3() -{ - GUIUtil::setClipboard(ui->balancesTable->item(ui->balancesTable->currentRow(),3)->text()); -} - -void ElyAssetsDialog::balancesUpdated() -{ - UpdatePropSelector(); - propSelectorChanged(); // refresh the table with the currently selected property ID -} diff --git a/src/qt/elyassetsdialog.h b/src/qt/elyassetsdialog.h deleted file mode 100644 index 4e5fffaed9..0000000000 --- a/src/qt/elyassetsdialog.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef ELYASSETSDIALOG_H -#define ELYASSETSDIALOG_H - -#include "guiutil.h" - -#include - -class ClientModel; -class WalletModel; - -QT_BEGIN_NAMESPACE -class QMenu; -class QPoint; -class QResizeEvent; -class QString; -class QWidget; -QT_END_NAMESPACE - -namespace Ui { - class ElyAssetsDialog; -} - -class ElyAssetsDialog : public QDialog -{ - Q_OBJECT - -public: - explicit ElyAssetsDialog(QWidget *parent = 0); - ~ElyAssetsDialog(); - - void setClientModel(ClientModel *model); - void setWalletModel(WalletModel *model); - void AddRow(const std::string& label, const std::string& address, const std::string& reserved, const std::string& available); - void PopulateBalances(unsigned int propertyId); - void UpdatePropSelector(); - -private: - Ui::ElyAssetsDialog *ui; - ClientModel *clientModel; - WalletModel *walletModel; - QMenu *contextMenu; - QMenu *contextMenuSummary; - -public Q_SLOTS: - void propSelectorChanged(); - void balancesUpdated(); - void reinitEly(); - -private Q_SLOTS: - void contextualMenu(const QPoint &point); - void balancesCopyCol0(); - void balancesCopyCol1(); - void balancesCopyCol2(); - void balancesCopyCol3(); - -Q_SIGNALS: - /** Fired when a message should be reported to the user */ - void message(const QString &title, const QString &message, unsigned int style); -}; - -#endif // ELYASSETSDIALOG_H diff --git a/src/qt/elysium_qtutils.cpp b/src/qt/elysium_qtutils.cpp deleted file mode 100644 index 5cd342c782..0000000000 --- a/src/qt/elysium_qtutils.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "elysium_qtutils.h" - -#include "guiutil.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace elysium -{ - -/** - * Displays a 'transaction sent' message box containing the transaction ID and an extra button to copy txid to clipboard - */ -void PopulateTXSentDialog(const std::string& txidStr) -{ - std::string strSentText = "Your Elysium transaction has been sent.\n\nThe transaction ID is:\n\n" + txidStr + "\n\n"; - QMessageBox sentDialog; - sentDialog.setIcon(QMessageBox::Information); - sentDialog.setWindowTitle("Transaction broadcast successfully"); - sentDialog.setText(QString::fromStdString(strSentText)); - sentDialog.setStandardButtons(QMessageBox::Yes|QMessageBox::Ok); - sentDialog.setDefaultButton(QMessageBox::Ok); - sentDialog.setButtonText( QMessageBox::Yes, "Copy TXID to clipboard" ); - if(sentDialog.exec() == QMessageBox::Yes) GUIUtil::setClipboard(QString::fromStdString(txidStr)); -} - -/** - * Displays a simple dialog layout that can be used to provide selectable text to the user - * - * Note: used in place of standard dialogs in cases where text selection & copy to clipboard functions are useful - */ -void PopulateSimpleDialog(const std::string& content, const std::string& title, const std::string& tooltip) -{ - QDialog *simpleDlg = new QDialog; - QLayout *dlgLayout = new QVBoxLayout; - dlgLayout->setSpacing(12); - dlgLayout->setMargin(12); - QTextEdit *dlgTextEdit = new QTextEdit; - dlgTextEdit->setText(QString::fromStdString(content)); - dlgTextEdit->setStatusTip(QString::fromStdString(tooltip)); - dlgTextEdit->setReadOnly(true); - dlgTextEdit->setTextInteractionFlags(dlgTextEdit->textInteractionFlags() | Qt::TextSelectableByKeyboard); - dlgLayout->addWidget(dlgTextEdit); - QPushButton *closeButton = new QPushButton(QObject::tr("&Close")); - closeButton->setDefault(true); - QDialogButtonBox *buttonBox = new QDialogButtonBox; - buttonBox->addButton(closeButton, QDialogButtonBox::AcceptRole); - dlgLayout->addWidget(buttonBox); - QObject::connect(buttonBox, &QDialogButtonBox::accepted, simpleDlg, &QDialog::accept); - simpleDlg->setAttribute(Qt::WA_DeleteOnClose); - simpleDlg->setWindowTitle(QString::fromStdString(title)); - simpleDlg->setLayout(dlgLayout); - simpleDlg->resize(700, 360); - if (simpleDlg->exec() == QDialog::Accepted) { } //do nothing but close -} - -/** - * Strips trailing zeros from a string containing a divisible value - */ -std::string StripTrailingZeros(const std::string& inputStr) -{ - size_t dot = inputStr.find("."); - std::string outputStr = inputStr; // make a copy we will manipulate and return - if (dot==std::string::npos) { // could not find a decimal marker, unsafe - return original input string - return inputStr; - } - size_t lastZero = outputStr.find_last_not_of('0') + 1; - if (lastZero > dot) { // trailing zeros are after decimal marker, safe to remove - outputStr.erase ( lastZero, std::string::npos ); - if (outputStr.length() > 0) { std::string::iterator it = outputStr.end() - 1; if (*it == '.') { outputStr.erase(it); } } //get rid of trailing dot if needed - } else { // last non-zero is before the decimal marker, this is a whole number - outputStr.erase ( dot, std::string::npos ); - } - return outputStr; -} - -/** - * Truncates a string at n digits and adds "..." to indicate that display is incomplete - */ -std::string TruncateString(const std::string& inputStr, unsigned int length) -{ - if (inputStr.empty()) return ""; - std::string outputStr = inputStr; - if (length > 0 && inputStr.length() > length) { - outputStr = inputStr.substr(0, length) + "..."; - } - return outputStr; -} - -/** - * Variable length find and replace. Find all iterations of findText within inputStr and replace them - * with replaceText. - */ -std::string ReplaceStr(const std::string& findText, const std::string& replaceText, const std::string& inputStr) -{ - size_t start_pos = 0; - std::string outputStr = inputStr; - while((start_pos = outputStr.find(findText, start_pos)) != std::string::npos) { - outputStr.replace(start_pos, findText.length(), replaceText); - start_pos += replaceText.length(); - } - return outputStr; -} - -} // end namespace diff --git a/src/qt/elysium_qtutils.h b/src/qt/elysium_qtutils.h deleted file mode 100644 index ac68d02cd4..0000000000 --- a/src/qt/elysium_qtutils.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef ELYSIUM_QTUTILS -#define ELYSIUM_QTUTILS - -#include - -namespace elysium -{ - /** - * Sets up a simple dialog layout that can be used to provide selectable text to the user - */ - void PopulateSimpleDialog(const std::string& content, const std::string& title, const std::string& tooltip); - - /** - * Truncates a string at n digits and adds "..." to indicate that display is incomplete - */ - std::string TruncateString(const std::string& inputStr, unsigned int length); - - /** - * Strips trailing zeros from a string containing a divisible value - */ - std::string StripTrailingZeros(const std::string& inputStr); - - /** - * Displays a 'transaction sent' message box containing the transaction ID and an extra button to copy txid to clipboard - */ - void PopulateTXSentDialog(const std::string& txidStr); - - /** - * Variable length find and replace. Find all iterations of findText within inputStr and replace them - * with replaceText. - */ - std::string ReplaceStr(const std::string& findText, const std::string& replaceText, const std::string& inputStr); -} - -#endif // ELYSIUM_QTUTILS diff --git a/src/qt/forms/elyassetsdialog.ui b/src/qt/forms/elyassetsdialog.ui deleted file mode 100644 index fa574d3338..0000000000 --- a/src/qt/forms/elyassetsdialog.ui +++ /dev/null @@ -1,84 +0,0 @@ - - - ElyAssetsDialog - - - - 0 - 0 - 664 - 362 - - - - Form - - - - - - 0 - - - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Show balances for: - - - - - - - - 0 - 0 - - - - - 300 - 0 - - - - - 300 - 0 - - - - - - - - - - false - - - - - - - - - - diff --git a/src/qt/forms/lookupaddressdialog.ui b/src/qt/forms/lookupaddressdialog.ui deleted file mode 100644 index 9eb96824d2..0000000000 --- a/src/qt/forms/lookupaddressdialog.ui +++ /dev/null @@ -1,584 +0,0 @@ - - - LookupAddressDialog - - - - 0 - 0 - 664 - 474 - - - - Form - - - - - - false - - - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; - - - true - - - 3 - - - - - - - 0 - - - - - true - - - - 0 - 0 - - - - Search Address: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 8 - - - - - - - - - - Search - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 6 - 20 - - - - - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - - - 75 - true - - - - Address Information - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - - 0 - 0 - - - - - 96 - 96 - - - - QRCode - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0 - - - - - Address: - - - - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Type: - - - - - - - - 50 - false - - - - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - In Wallet: - - - - - - - Balance: - - - - - - - - 75 - true - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - 0 - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 12 - - - - - - - - - - <b>Balance Information</b> - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 6 - - - - - Property1: - - - - - - - - 75 - true - - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Property2: - - - - - - - - 75 - true - - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Property3: - - - - - - - - 75 - true - - - - Qt::LeftToRight - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Property4: - - - - - - - - 75 - true - - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Property5: - - - - - - - - 75 - true - - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Property6: - - - - - - - - 75 - true - - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Property7: - - - - - - - - 75 - true - - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Property8: - - - - - - - - 75 - true - - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Property9: - - - - - - - - 75 - true - - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Property10: - - - - - - - - 75 - true - - - - 0.00 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - *Only first 10 properties shown - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - - - - - - diff --git a/src/qt/forms/lookupspdialog.ui b/src/qt/forms/lookupspdialog.ui deleted file mode 100644 index 10907a2cf9..0000000000 --- a/src/qt/forms/lookupspdialog.ui +++ /dev/null @@ -1,815 +0,0 @@ - - - LookupSPDialog - - - - 0 - 0 - 664 - 497 - - - - Form - - - - - - false - - - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; - - - true - - - 3 - - - - - - - 0 - - - - - true - - - - 0 - 0 - - - - Search: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 8 - - - - - - - - 0 - 0 - - - - - 150 - 0 - - - - - - - - Search - - - - - - - - 0 - 0 - - - - padding-left:15px; - - - Results: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 0 - - - - - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 6 - 20 - - - - - - - - - - 0 - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - - - 75 - true - - - - Smart Property Information - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 0 - - - - - Property ID: - - - - - - - - 75 - true - - - - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Name: - - - - - - - - 75 - true - - - - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Issuer: - - - - - - - - 0 - 0 - - - - - 75 - true - - - - color:rgb(148, 148, 148) - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 0 - - - -1 - - - - - - - Category: - - - - - - - - 50 - false - - - - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - URL: - - - - - - - - 50 - false - - - - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Data: - - - - - - - - 50 - false - - - - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - 0 - - - - - - - <b>Token Information</b> - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 12 - - - - - Divisible: - - - - - - - - 75 - true - - - - No - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Issuance Type: - - - - - - - - 75 - true - - - - Fixed - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Ecosystem: - - - - - - - - 75 - true - - - - Test - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Total Tokens: - - - - - - - - 75 - true - - - - Qt::LeftToRight - - - 0 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Wallet Balance: - - - - - - - - 75 - true - - - - 0 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Sigma Status: - - - - - - - - 75 - true - - - - SoftDisabled - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - 0 - 0 - - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - 0 - - - - - - 75 - true - - - - Crowdsale Information - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 12 - - - 0 - - - - - Desired Property: - - - - - - - - 75 - true - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Tokens Per Unit: - - - - - - - - 75 - true - - - - 0 SPT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Deadline: - - - - - - - - 75 - true - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Weekly Bonus: - - - - - - - - 75 - true - - - - 0% - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Issuer Percentage: - - - - - - - - 75 - true - - - - 0% - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Active: - - - - - - - - 75 - true - - - - N/A - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - diff --git a/src/qt/forms/lookuptxdialog.ui b/src/qt/forms/lookuptxdialog.ui deleted file mode 100644 index bc860ec9af..0000000000 --- a/src/qt/forms/lookuptxdialog.ui +++ /dev/null @@ -1,116 +0,0 @@ - - - LookupTXDialog - - - - 0 - 0 - 664 - 474 - - - - Form - - - - - - false - - - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; - - - true - - - 3 - - - - - - - 0 - - - - - true - - - - 0 - 0 - - - - Search Transaction: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 8 - - - - - - - - - - Search - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 6 - 20 - - - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - - - - - - diff --git a/src/qt/forms/metadexcanceldialog.ui b/src/qt/forms/metadexcanceldialog.ui deleted file mode 100755 index 5b95bf1800..0000000000 --- a/src/qt/forms/metadexcanceldialog.ui +++ /dev/null @@ -1,278 +0,0 @@ - - - MetaDExCancelDialog - - - - 0 - 0 - 664 - 474 - - - - Form - - - - - - 0 - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - 0 - - - - - - 75 - true - - - - padding-bottom:4px; - - - Cancellation Address: - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 8 - 20 - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 8 - 20 - - - - - - - - - - - 75 - true - - - - padding-top:10px;padding-bottom:4px; - - - Cancellation Type: - - - - - - - padding-left:10px; - - - Cancel by pair - - - - - - - padding-left:10px; - - - Cancel by price - - - - - - - padding-left:10px; - - - Cancel by ecosystem - - - - - - - - 75 - true - - - - padding-top:10px;padding-bottom:4px; - - - Cancellation Criteria: - - - - - - - 0 - - - 10 - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 8 - 20 - - - - - - - - - 0 - 0 - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 8 - 20 - - - - - - - - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Send Cancel Request - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 8 - 20 - - - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - diff --git a/src/qt/forms/metadexdialog.ui b/src/qt/forms/metadexdialog.ui deleted file mode 100755 index 7e83be5b18..0000000000 --- a/src/qt/forms/metadexdialog.ui +++ /dev/null @@ -1,471 +0,0 @@ - - - MetaDExDialog - - - - 0 - 0 - 704 - 474 - - - - Form - - - - - - false - - - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; - - - true - - - 3 - - - - - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - - - 6 - - - 0 - - - 0 - - - - - 6 - - - 0 - - - - - - 50 - false - - - - Sell - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - - - - for - - - - - - - - 0 - 0 - - - - - - - - using - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - Last Price - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 0.00000000 OMNI - - - - - - - - - 0 - - - - - Volume (24hr) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 0 - - - - - - - - - - - Total Available - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 0 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Test Eco - - - - - - - Trade History - - - - - - - Invert Pair - - - - - - - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - 0 - - - - - QFormLayout::AllNonFixedFieldsGrow - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 6 - - - - - Qt::LeftToRight - - - - - - Amount To Sell: - - - - - - - - - - - - - - Unit Price: - - - - - - - false - - - - - - - Amount Desired: - - - - - - - - - - - - 0 - - - 0 - - - - - 0 - - - 0 - - - - - SPT - - - - - - - - - - - - - - SPT - - - - - - - - - - - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Your Balance 0.000000000 SPT - - - - - - - Sell SP#3 - - - - - - - - - - 8 - - - - QLabel { -border: 1px solid rgb(142,61,0);padding:5px 5px 5px 5px;background-repeat: no-repeat;background-position: 10px center;color: #133959;background-color: rgb(255,191,142); color:rgb(142,61,0);} - - - TextLabel - - - - - - - - - - - - - - - - - - diff --git a/src/qt/forms/sendmpdialog.ui b/src/qt/forms/sendmpdialog.ui deleted file mode 100644 index 5c8505f474..0000000000 --- a/src/qt/forms/sendmpdialog.ui +++ /dev/null @@ -1,354 +0,0 @@ - - - SendMPDialog - - - - 0 - 0 - 850 - 400 - - - - Send Coins - - - true - - - - 8 - - - - - QFrame::NoFrame - - - QFrame::Plain - - - true - - - - - 0 - 0 - 832 - 350 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - 0 - 0 - - - - - 95 - 0 - - - - Send From: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 8 - - - - - - - - 0 - 0 - - - - - - - - Available: 0.00000000 ELYSIUM - - - 8 - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 15 - 20 - - - - - - - - - - - - - 95 - 0 - - - - Qt::LeftToRight - - - Send To: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 8 - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 15 - 20 - - - - - - - - - - 0 - - - - - - 95 - 0 - - - - Amount: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 8 - - - - - - - - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 15 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - 0 - - - - - - 8 - - - - QLabel { -border: 1px solid rgb(142,61,0);padding:5px 5px 5px 5px;background-repeat: no-repeat;background-position: 10px center;color: #133959;background-color: rgb(255,191,142); color:rgb(142,61,0);} - - - Warning: You will not be able to send this transaction. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - - - - - 150 - 0 - - - - Confirm the send action - - - S&end - - - true - - - - - - - - 0 - 0 - - - - Clear all fields of the form. - - - Clear &All - - - 300 - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 3 - - - - - - 0 - 0 - - - - IBeamCursor - - - 123.456 ELYSIUM - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - - - - - - diff --git a/src/qt/forms/tradehistorydialog.ui b/src/qt/forms/tradehistorydialog.ui deleted file mode 100644 index 726692a14e..0000000000 --- a/src/qt/forms/tradehistorydialog.ui +++ /dev/null @@ -1,41 +0,0 @@ - - - tradeHistoryDialog - - - - 0 - 0 - 664 - 474 - - - - Form - - - - - - 0 - - - - - Qt::RightToLeft - - - Hide inactive trades - - - - - - - - - - - - - diff --git a/src/qt/forms/txhistorydialog.ui b/src/qt/forms/txhistorydialog.ui deleted file mode 100644 index 941d74c579..0000000000 --- a/src/qt/forms/txhistorydialog.ui +++ /dev/null @@ -1,31 +0,0 @@ - - - txHistoryDialog - - - - 0 - 0 - 664 - 474 - - - - Form - - - - - - 0 - - - - - - - - - - - diff --git a/src/qt/lookupaddressdialog.cpp b/src/qt/lookupaddressdialog.cpp deleted file mode 100644 index f60afb6d85..0000000000 --- a/src/qt/lookupaddressdialog.cpp +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright (c) 2011-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "lookupaddressdialog.h" -#include "ui_lookupaddressdialog.h" - -#include "guiutil.h" - -#include "elysium/elysium.h" -#include "elysium/sp.h" -#include "elysium/wallettxs.h" - -#include "base58.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(HAVE_CONFIG_H) -#include "bitcoin-config.h" /* for USE_QRCODE */ -#endif - -#ifdef USE_QRCODE -#include -#endif - -using std::ostringstream; -using std::string; - -using namespace elysium; - -MPQRImageWidget::MPQRImageWidget(QWidget *parent): - QLabel(parent), contextMenu(0) -{ - contextMenu = new QMenu(); - QAction *saveImageAction = new QAction(tr("&Save Image..."), this); - connect(saveImageAction, &QAction::triggered, this, &MPQRImageWidget::saveImage); - contextMenu->addAction(saveImageAction); - QAction *copyImageAction = new QAction(tr("&Copy Image"), this); - connect(copyImageAction, &QAction::triggered, this, &MPQRImageWidget::copyImage); - contextMenu->addAction(copyImageAction); -} - -QImage MPQRImageWidget::exportImage() -{ - if(!pixmap()) - return QImage(); - return pixmap()->toImage().scaled(256,256); -} - -void MPQRImageWidget::mousePressEvent(QMouseEvent *event) -{ - if(event->button() == Qt::LeftButton && pixmap()) - { - event->accept(); - QMimeData *mimeData = new QMimeData; - mimeData->setImageData(exportImage()); - - QDrag *drag = new QDrag(this); - drag->setMimeData(mimeData); - drag->exec(); - } else { - QLabel::mousePressEvent(event); - } -} - -void MPQRImageWidget::saveImage() -{ - if(!pixmap()) - return; - QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), NULL); - if (!fn.isEmpty()) - { - exportImage().save(fn); - } -} - -void MPQRImageWidget::copyImage() -{ - if(!pixmap()) - return; - QApplication::clipboard()->setImage(exportImage()); -} - -void MPQRImageWidget::contextMenuEvent(QContextMenuEvent *event) -{ - if(!pixmap()) - return; - contextMenu->exec(event->globalPos()); -} - -LookupAddressDialog::LookupAddressDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::LookupAddressDialog) -{ - ui->setupUi(this); - -#if QT_VERSION >= 0x040700 - ui->searchLineEdit->setPlaceholderText("Search address"); -#endif - - // connect actions - connect(ui->searchButton, &QPushButton::clicked, this, &LookupAddressDialog::searchButtonClicked); - - // hide balance labels - QLabel* balances[] = { ui->propertyLabel1, ui->propertyLabel2, ui->propertyLabel3, ui->propertyLabel4, ui->propertyLabel5, ui->propertyLabel6, ui->propertyLabel7, ui->propertyLabel8, ui->propertyLabel9, ui->propertyLabel10 }; - QLabel* labels[] = { ui->property1, ui->property2, ui->property3, ui->property4, ui->property5, ui->property6, ui->property7, ui->property8, ui->property9, ui->property10 }; - int pItem = 0; - for (pItem = 1; pItem < 11; pItem++) - { - labels[pItem-1]->setVisible(false); - balances[pItem-1]->setVisible(false); - } - ui->onlyLabel->setVisible(false); - ui->frame->setVisible(false); -} - -LookupAddressDialog::~LookupAddressDialog() -{ - delete ui; -} - -void LookupAddressDialog::searchAddress() -{ - // search function to lookup address - string searchText = ui->searchLineEdit->text().toStdString(); - - // first let's check if we have a searchText, if not do nothing - if (searchText.empty()) return; - - // lets see if the string is a valid Firo address - CBitcoinAddress address; - address.SetString(searchText); // no null check on searchText required we've already checked it's not empty above - if (address.IsValid()) //do what? - { - // update top fields - ui->addressLabel->setText(QString::fromStdString(searchText)); - if ((searchText.substr(0,1) == "1") || (searchText.substr(0,1) == "m") || (searchText.substr(0,1) == "n")) ui->addressTypeLabel->setText("Public Key Hash"); - if ((searchText.substr(0,1) == "2") || (searchText.substr(0,1) == "3")) ui->addressTypeLabel->setText("Pay to Script Hash"); - if (IsMyAddress(searchText)) { ui->isMineLabel->setText("Yes"); } else { ui->isMineLabel->setText("No"); } - ui->balanceLabel->setText(QString::fromStdString(FormatDivisibleMP(getUserAvailableMPbalance(searchText, 1)) + " Elysium")); - // QR - #ifdef USE_QRCODE - ui->QRCode->setText(""); - QRcode *code = QRcode_encodeString(QString::fromStdString(searchText).toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1); - if (!code) - { - ui->QRCode->setText(tr("Error encoding address into QR Code.")); - } - else - { - QImage myImage = QImage(code->width + 4, code->width + 4, QImage::Format_RGB32); - myImage.fill(0xffffff); - unsigned char *p = code->data; - for (int y = 0; y < code->width; y++) - { - for (int x = 0; x < code->width; x++) - { - myImage.setPixel(x + 2, y + 2, ((*p & 1) ? 0x0 : 0xffffff)); - p++; - } - } - QRcode_free(code); - ui->QRCode->setPixmap(QPixmap::fromImage(myImage).scaled(96, 96)); - } - #endif - - //scrappy way to do this, find a more efficient way of interacting with labels - //show first 10 SPs with balances - needs to be converted to listwidget or something - unsigned int propertyId; - unsigned int lastFoundPropertyIdMainEco = 1; - unsigned int lastFoundPropertyIdTestEco = 1; - string pName[12]; // TODO: enough slots? - uint64_t pBal[12]; - bool pDivisible[12]; - bool pFound[12]; - unsigned int pItem; - bool foundProperty = false; - for (pItem = 1; pItem < 12; pItem++) - { - pFound[pItem] = false; - for (propertyId = lastFoundPropertyIdMainEco+1; propertyId<10000; propertyId++) - { - foundProperty=false; - if (getUserAvailableMPbalance(searchText, propertyId) > 0) - { - lastFoundPropertyIdMainEco = propertyId; - foundProperty=true; - pName[pItem] = getPropertyName(propertyId).c_str(); - if(pName[pItem].size()>32) pName[pItem]=pName[pItem].substr(0,32)+"..."; - pName[pItem] += strprintf(" (#%d)", propertyId); - pBal[pItem] = getUserAvailableMPbalance(searchText, propertyId); - pDivisible[pItem] = isPropertyDivisible(propertyId); - pFound[pItem] = true; - break; - } - } - - // have we found a property in main eco? If not let's try test eco - if (!foundProperty) - { - for (propertyId = lastFoundPropertyIdTestEco+1; propertyId<10000; propertyId++) - { - if (getUserAvailableMPbalance(searchText, propertyId+2147483647) > 0) - { - lastFoundPropertyIdTestEco = propertyId; - foundProperty=true; - pName[pItem] = getPropertyName(propertyId+2147483647).c_str(); - if(pName[pItem].size()>32) pName[pItem]=pName[pItem].substr(0,32)+"..."; - pName[pItem] += strprintf(" (#%d)", propertyId+2147483647); - pBal[pItem] = getUserAvailableMPbalance(searchText, propertyId+2147483647); - pDivisible[pItem] = isPropertyDivisible(propertyId+2147483647); - pFound[pItem] = true; - break; - } - } - } - } - - // set balance info - ui->frame->setVisible(true); - QLabel* balances[] = { ui->propertyLabel1, ui->propertyLabel2, ui->propertyLabel3, ui->propertyLabel4, ui->propertyLabel5, ui->propertyLabel6, ui->propertyLabel7, ui->propertyLabel8, ui->propertyLabel9, ui->propertyLabel10 }; - QLabel* labels[] = { ui->property1, ui->property2, ui->property3, ui->property4, ui->property5, ui->property6, ui->property7, ui->property8, ui->property9, ui->property10 }; - for (pItem = 1; pItem < 11; pItem++) - { - if (pFound[pItem]) - { - labels[pItem-1]->setVisible(true); - balances[pItem-1]->setVisible(true); - labels[pItem-1]->setText(pName[pItem].c_str()); - string tokenLabel = " SPT"; - if (pName[pItem]=="Test Elysium (#2)") { tokenLabel = " TELYSIUM"; } - if (pDivisible[pItem]) - { - balances[pItem-1]->setText(QString::fromStdString(FormatDivisibleMP(pBal[pItem]) + tokenLabel)); - } - else - { - string balText = strprintf("%d", pBal[pItem]); - balText += tokenLabel; - balances[pItem-1]->setText(balText.c_str()); - } - } - else - { - labels[pItem-1]->setVisible(false); - balances[pItem-1]->setVisible(false); - } - } - if (pFound[11]) { ui->onlyLabel->setVisible(true); } else { ui->onlyLabel->setVisible(false); } - } - else - { - // hide balance labels - QLabel* balances[] = { ui->propertyLabel1, ui->propertyLabel2, ui->propertyLabel3, ui->propertyLabel4, ui->propertyLabel5, ui->propertyLabel6, ui->propertyLabel7, ui->propertyLabel8, ui->propertyLabel9, ui->propertyLabel10 }; - QLabel* labels[] = { ui->property1, ui->property2, ui->property3, ui->property4, ui->property5, ui->property6, ui->property7, ui->property8, ui->property9, ui->property10 }; - int pItem = 0; - for (pItem = 1; pItem < 11; pItem++) - { - labels[pItem-1]->setVisible(false); - balances[pItem-1]->setVisible(false); - } - ui->addressLabel->setText("N/A"); - ui->addressTypeLabel->setText("N/A"); - ui->isMineLabel->setText("N/A"); - ui->frame->setVisible(false); - // show error message - string strText = "The address entered was not valid."; - QString strQText = QString::fromStdString(strText); - QMessageBox errorDialog; - errorDialog.setIcon(QMessageBox::Critical); - errorDialog.setWindowTitle("Address error"); - errorDialog.setText(strQText); - errorDialog.setStandardButtons(QMessageBox::Ok); - errorDialog.setDefaultButton(QMessageBox::Ok); - if(errorDialog.exec() == QMessageBox::Ok) { } // no other button to choose, acknowledged - } -} - -void LookupAddressDialog::searchButtonClicked() -{ - searchAddress(); -} diff --git a/src/qt/lookupaddressdialog.h b/src/qt/lookupaddressdialog.h deleted file mode 100644 index 9b5300d382..0000000000 --- a/src/qt/lookupaddressdialog.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef LOOKUPADDRESSDIALOG_H -#define LOOKUPADDRESSDIALOG_H - -#include -#include - -QT_BEGIN_NAMESPACE -class QContextMenuEvent; -class QImage; -class QMenu; -class QMouseEvent; -class QString; -class QWidget; -QT_END_NAMESPACE - -namespace Ui { - class LookupAddressDialog; -} - -/* Label widget for QR code. This image can be dragged, dropped, copied and saved - * to disk. - */ -class MPQRImageWidget : public QLabel -{ - Q_OBJECT - -public: - explicit MPQRImageWidget(QWidget *parent = 0); - QImage exportImage(); - -public Q_SLOTS: - void saveImage(); - void copyImage(); - -protected: - virtual void mousePressEvent(QMouseEvent *event); - virtual void contextMenuEvent(QContextMenuEvent *event); - -private: - QMenu *contextMenu; -}; - -/** Dialog for looking up Master Protocol address */ -class LookupAddressDialog : public QDialog -{ - Q_OBJECT - -public: - explicit LookupAddressDialog(QWidget *parent = 0); - ~LookupAddressDialog(); - - void searchAddress(); - -public Q_SLOTS: - void searchButtonClicked(); - -private: - Ui::LookupAddressDialog *ui; - -Q_SIGNALS: - // Fired when a message should be reported to the user - void message(const QString &title, const QString &message, unsigned int style); -}; - -#endif // LOOKUPADDRESSDIALOG_H diff --git a/src/qt/lookupspdialog.cpp b/src/qt/lookupspdialog.cpp deleted file mode 100644 index 520f098106..0000000000 --- a/src/qt/lookupspdialog.cpp +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright (c) 2011-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "lookupspdialog.h" -#include "ui_lookupspdialog.h" - -#include "guiutil.h" - -#include "elysium/elysium.h" -#include "elysium/sp.h" - -#include "base58.h" - -#include - -#include -#include -#include - -#include -#include -#include -#include - -using std::ostringstream; -using std::string; - -using namespace elysium; - -LookupSPDialog::LookupSPDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::LookupSPDialog), - model(0) -{ - ui->setupUi(this); - -#if QT_VERSION >= 0x040700 - ui->searchLineEdit->setPlaceholderText("ID, name or issuer"); -#endif - - // connect actions - connect(ui->matchingComboBox, qOverload(&QComboBox::activated), this, &LookupSPDialog::matchingComboBoxChanged); - connect(ui->searchButton, &QPushButton::clicked, this, &LookupSPDialog::searchButtonClicked); - - // hide crowd info - ui->desired->setVisible(false); - ui->tokensperunit->setVisible(false); - ui->deadline->setVisible(false); - ui->bonus->setVisible(false); - ui->issuerperc->setVisible(false); - ui->desiredLabel->setVisible(false); - ui->tokensPerUnitLabel->setVisible(false); - ui->deadlineLabel->setVisible(false); - ui->bonusLabel->setVisible(false); - ui->issuerPercLabel->setVisible(false); - ui->activeLabel->setVisible(false); - ui->active->setText("Not applicable."); - ui->topFrame->setVisible(false); - ui->leftFrame->setVisible(false); - ui->rightFrame->setVisible(false); - ui->denominationTable->setVisible(false); - - // denominations - ui->denominationTable->setColumnCount(2); - ui->denominationTable->setHorizontalHeaderItem(0, new QTableWidgetItem("Denomination")); - ui->denominationTable->setHorizontalHeaderItem(1, new QTableWidgetItem("Value")); - // note neither resizetocontents or stretch allow user to adjust - go interactive then manually set widths - #if QT_VERSION < 0x050000 - ui->denominationTable->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch); - ui->denominationTable->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch); - #else - ui->denominationTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); - ui->denominationTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); - #endif - ui->denominationTable->setAlternatingRowColors(true); - - // initial resizing - ui->denominationTable->resizeColumnToContents(0); - ui->denominationTable->verticalHeader()->setVisible(false); - ui->denominationTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->denominationTable->setSelectionBehavior(QAbstractItemView::SelectRows); - ui->denominationTable->setSelectionMode(QAbstractItemView::SingleSelection); - ui->denominationTable->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - ui->denominationTable->setTabKeyNavigation(false); - ui->denominationTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->denominationTable->setSortingEnabled(true); -} - -LookupSPDialog::~LookupSPDialog() -{ - delete ui; -} - -void LookupSPDialog::searchSP() -{ - // search function to lookup properties, we want this search function to be as capable as possible to - // help users find the property they're looking for via search terms they may want to use - int searchParamType = 0; - string searchText = ui->searchLineEdit->text().toStdString(); - unsigned int searchPropertyId = 0; - - // first let's check if we have a searchText, if not do nothing - if (searchText.empty()) return; - - // try seeing if we have a numerical search string, if so treat it as a property ID search - try - { - searchPropertyId = boost::lexical_cast(searchText); - searchParamType = 1; // search by propertyId - } - catch(const boost::bad_lexical_cast &e) { } - if (searchParamType == 1 && 0 >= searchPropertyId) searchParamType = 0; // we got a number but it's <=0 - - // next if not positive numerical, lets see if the string is a valid Firo address for issuer search - if (searchParamType == 0) - { - CBitcoinAddress address; - address.SetString(searchText); // no null check on searchText required we've already checked it's not empty above - if (address.IsValid()) searchParamType = 2; // search by address; - } - - // next if we have a "*" only, we'll assume the user wants to request all properties - // Znote - unsure about this, adding for now but may be removed in future when number of properties is - // higher because it will get out of hand to add 100,000 properties to a single combo unfiltered - if ((searchParamType == 0) && (searchText == "*")) { searchParamType = 4; } - - // if we still don't have a param we'll search against free text in the name - if (searchParamType == 0) searchParamType = 3; // search by free text - - // clear matching results combo - ui->matchingComboBox->clear(); - bool spExists; - unsigned int tmpPropertyId; - unsigned int nextSPID; - unsigned int nextTestSPID; - unsigned int propertyId; - QString strId; - switch(searchParamType) - { - case 1: //search by property Id - // convert search string to ID - strId = QString::fromStdString(searchText); - propertyId = strId.toUInt(); - // check if this property ID exists, if not no match to populate and just return - spExists = _my_sps->hasSP(propertyId); - if (spExists) - { - addSPToMatchingResults(propertyId); - updateDisplayedProperty(); //show straight away, only one to select - } - else - { - return; - } - break; - case 2: //search by address - // iterate through my_sps looking for the issuer address and add any properties issued by said address to matchingcombo - // talk with @Michael @Bart to see if perhaps a more efficient way to do this, but not major issue as only run on user request - nextSPID = _my_sps->peekNextSPID(1); - nextTestSPID = _my_sps->peekNextSPID(2); - for (tmpPropertyId = 1; tmpPropertyIdgetSP(tmpPropertyId, sp)) - { - if (sp.issuer == searchText) - { - addSPToMatchingResults(tmpPropertyId); - } - } - } - for (tmpPropertyId = TEST_ECO_PROPERTY_1; tmpPropertyIdgetSP(tmpPropertyId, sp)) - { - if (sp.issuer == searchText) - { - addSPToMatchingResults(tmpPropertyId); - } - } - } - break; - case 3: //search by freetext - // iterate through my_sps and see if property name contains the search text - nextSPID = _my_sps->peekNextSPID(1); - nextTestSPID = _my_sps->peekNextSPID(2); - for (tmpPropertyId = 1; tmpPropertyIdgetSP(tmpPropertyId, sp)) - { - // make the search case insensitive - string lowerName = sp.name; - std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); - string lowerSearch = searchText; - std::transform(lowerSearch.begin(), lowerSearch.end(), lowerSearch.begin(), ::tolower); - size_t loc = lowerName.find(lowerSearch); - if (loc!=std::string::npos) - { - addSPToMatchingResults(tmpPropertyId); - } - } - } - for (tmpPropertyId = TEST_ECO_PROPERTY_1; tmpPropertyIdgetSP(tmpPropertyId, sp)) - { - // make the search case insensitive - string lowerName = sp.name; - std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); - string lowerSearch = searchText; - std::transform(lowerSearch.begin(), lowerSearch.end(), lowerSearch.begin(), ::tolower); - size_t loc = lowerName.find(lowerSearch); - if (loc!=std::string::npos) - { - addSPToMatchingResults(tmpPropertyId); - } - } - } - break; - case 4: // grab everything - nextSPID = _my_sps->peekNextSPID(1); - for (tmpPropertyId = 1; tmpPropertyIdgetSP(tmpPropertyId, sp)) { addSPToMatchingResults(tmpPropertyId); } - } - nextTestSPID = _my_sps->peekNextSPID(2); - for (tmpPropertyId = TEST_ECO_PROPERTY_1; tmpPropertyIdgetSP(tmpPropertyId, sp)) { addSPToMatchingResults(tmpPropertyId); } - } - break; - } - -} - -void LookupSPDialog::addSPToMatchingResults(unsigned int propertyId) -{ - // verify the supplied property exists (sanity check) then populate the matching results combo box - bool spExists = _my_sps->hasSP(propertyId); - if (spExists) - { - string spName; - spName = getPropertyName(propertyId).c_str(); - if(spName.size()>40) spName=spName.substr(0,40)+"..."; - string spId = strprintf("%d", propertyId); - spName += " (#" + spId + ")"; - ui->matchingComboBox->addItem(spName.c_str(),spId.c_str()); - } - else - { - return; - } -} - -void LookupSPDialog::updateDisplayedProperty() -{ - uint64_t maxLabelWidth=100; // fairly safe value for now, next version consider wrapping - // instead of truncation and evaluate effects on vertical layout - QString strId = ui->matchingComboBox->itemData(ui->matchingComboBox->currentIndex()).toString(); - // protect against an empty matchedComboBox - if (strId.toStdString().empty()) return; - - // map property Id - unsigned int propertyId = strId.toUInt(); - CMPSPInfo::Entry sp; - if (false == _my_sps->getSP(propertyId, sp)) { return; } // something has gone wrong, don't attempt to display non-existent property - - // populate the fields - bool divisible=sp.isDivisible(); - if (divisible) { ui->divisibleLabel->setText("Yes"); } else { ui->divisibleLabel->setText("No"); } - if (isTestEcosystemProperty(propertyId)) { ui->ecosystemLabel->setText("Test"); } else { ui->ecosystemLabel->setText("Production"); } - ui->propertyIDLabel->setText(QString::fromStdString(FormatIndivisibleMP(propertyId))); - if(sp.name.size()>maxLabelWidth) { - ui->nameLabel->setText(QString::fromStdString(sp.name.substr(0,maxLabelWidth)+"...")); - } else { - ui->nameLabel->setText(QString::fromStdString(sp.name)); - } - std::string dispCat; - dispCat = sp.category + " > " + sp.subcategory; - if(dispCat.size()>maxLabelWidth) { - if(sp.category.size()>maxLabelWidth/2) { - dispCat = sp.category.substr(0,maxLabelWidth/2)+"..."; - } else { - dispCat = sp.category; - } - dispCat += " > "; - if(sp.subcategory.size()>maxLabelWidth/2) { - dispCat += sp.subcategory.substr(0,maxLabelWidth/2)+"..."; - } else { - dispCat += sp.subcategory; - } - } - ui->categoryLabel->setText(QString::fromStdString(dispCat)); - if(sp.data.size()>maxLabelWidth) { - ui->dataLabel->setText(QString::fromStdString(sp.data.substr(0,maxLabelWidth)+"...")); - } else { - ui->dataLabel->setText(QString::fromStdString(sp.data)); - } - if(sp.url.size()>maxLabelWidth) { - ui->urlLabel->setText(QString::fromStdString(sp.url.substr(0,maxLabelWidth)+"...")); - } else { - ui->urlLabel->setText(QString::fromStdString(sp.url)); - } - - string strTotalTokens; - string strWalletTokens; - int64_t totalTokens = getTotalTokens(propertyId); - int64_t walletTokens = 0; - { - LOCK(cs_main); - walletTokens = global_balance_money[propertyId]; - } - string tokenLabel; - if (propertyId > 2) - { - tokenLabel = " SPT"; - } - else - { - if (propertyId == 1) { tokenLabel = " ELYSIUM"; } else { tokenLabel = " TELYSIUM"; } - } - if (divisible) { strTotalTokens = FormatDivisibleMP(totalTokens); } else { strTotalTokens = FormatIndivisibleMP(totalTokens); } - if (divisible) { strWalletTokens = FormatDivisibleMP(walletTokens); } else { strWalletTokens = FormatIndivisibleMP(walletTokens); } - ui->totalTokensLabel->setText(QString::fromStdString(strTotalTokens + tokenLabel)); - ui->walletBalanceLabel->setText(QString::fromStdString(strWalletTokens + tokenLabel)); - ui->issuerLabel->setText(QString::fromStdString(sp.issuer)); - bool fixedIssuance = sp.fixed; - bool manualIssuance = sp.manual; - - // sigma - // ui->sigmaStatusLabel->setText(QString::fromStdString(std::to_string(sp.sigmaStatus))); - ui->denominationTable->setRowCount(0); - - for (size_t i = 0; i < sp.denominations.size(); i++) { - std::string value; - if (divisible) { - value = FormatDivisibleMP(sp.denominations[i]); - } else { - value = FormatIndivisibleMP(sp.denominations[i]); - } - addDenominationRow(i, value); - } - - if ((!fixedIssuance) && (!manualIssuance) && (propertyId > 2)) - { - ui->issuanceTypeLabel->setText("Crowdsale"); - // obtain crowdinfo - bool active = isCrowdsaleActive(propertyId); - int64_t deadline = sp.deadline; - uint8_t earlyBonus = sp.early_bird; - uint8_t percentToIssuer = sp.percentage; - int64_t tokensPerUnit = sp.num_tokens; - int64_t propertyIdDesired = sp.property_desired; - QDateTime qDeadline; - qDeadline.setTime_t(deadline); - string desiredText = getPropertyName(propertyIdDesired).c_str(); - if(desiredText.size()>22) desiredText=desiredText.substr(0,22)+"..."; - string spId = strprintf("%d", propertyIdDesired); - desiredText += " (#" + spId + ")"; - string tokensPerUnitText; - if (divisible) { tokensPerUnitText = FormatDivisibleMP(tokensPerUnit); } else { tokensPerUnitText = FormatIndivisibleMP(tokensPerUnit); } - if (active) { ui->activeLabel->setText("Yes"); } else { ui->activeLabel->setText("No"); } - // populate crowdinfo - ui->desiredLabel->setText(QString::fromStdString(desiredText)); - ui->tokensPerUnitLabel->setText(QString::fromStdString(tokensPerUnitText)); - ui->deadlineLabel->setText(qDeadline.toString(Qt::SystemLocaleShortDate)); - ui->bonusLabel->setText(QString::fromStdString(FormatIndivisibleMP((int64_t)earlyBonus) + "%")); - ui->issuerPercLabel->setText(QString::fromStdString(FormatIndivisibleMP((int64_t)percentToIssuer) + "%")); - // show crowdinfo - ui->desired->setVisible(true); - ui->tokensperunit->setVisible(true); - ui->deadline->setVisible(true); - ui->bonus->setVisible(true); - ui->issuerperc->setVisible(true); - ui->desiredLabel->setVisible(true); - ui->tokensPerUnitLabel->setVisible(true); - ui->deadlineLabel->setVisible(true); - ui->bonusLabel->setVisible(true); - ui->issuerPercLabel->setVisible(true); - ui->activeLabel->setVisible(true); - ui->active->setText("Active:"); - } - else - { - ui->issuanceTypeLabel->setText("Elysium"); - if (fixedIssuance) ui->issuanceTypeLabel->setText("Fixed"); - if (manualIssuance) ui->issuanceTypeLabel->setText("Manual"); - // hide crowdinfo - ui->desired->setVisible(false); - ui->tokensperunit->setVisible(false); - ui->deadline->setVisible(false); - ui->bonus->setVisible(false); - ui->issuerperc->setVisible(false); - ui->desiredLabel->setVisible(false); - ui->tokensPerUnitLabel->setVisible(false); - ui->deadlineLabel->setVisible(false); - ui->bonusLabel->setVisible(false); - ui->issuerPercLabel->setVisible(false); - ui->activeLabel->setVisible(false); - ui->active->setText("Not applicable."); - } - ui->topFrame->setVisible(true); - ui->leftFrame->setVisible(true); - ui->rightFrame->setVisible(true); - ui->denominationTable->setVisible(true); -} - -void LookupSPDialog::searchButtonClicked() -{ - searchSP(); -} - -void LookupSPDialog::matchingComboBoxChanged(int idx) -{ - updateDisplayedProperty(); -} - -class NumericalCmpWidgetItem : public QTableWidgetItem -{ -public: - NumericalCmpWidgetItem(const QString& text) : QTableWidgetItem(text) - { - } - - bool operator<(const QTableWidgetItem& other) const override - { - return text().toDouble() < other.text().toDouble(); - } -}; - -void LookupSPDialog::addDenominationRow(uint8_t id, const std::string& value) -{ - int index = ui->denominationTable->rowCount(); - ui->denominationTable->insertRow(index); - NumericalCmpWidgetItem *idCell = new NumericalCmpWidgetItem(QString::fromStdString(std::to_string(id))); - NumericalCmpWidgetItem *valuCell = new NumericalCmpWidgetItem(QString::fromStdString(value)); - idCell->setTextAlignment(Qt::AlignCenter); - valuCell->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); - ui->denominationTable->setItem(index, 0, idCell); - ui->denominationTable->setItem(index, 1, valuCell); -} diff --git a/src/qt/lookupspdialog.h b/src/qt/lookupspdialog.h deleted file mode 100644 index e85e593733..0000000000 --- a/src/qt/lookupspdialog.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef LOOKUPSPDIALOG_H -#define LOOKUPSPDIALOG_H - -#include "guiutil.h" - -#include - -class WalletModel; - -QT_BEGIN_NAMESPACE -class QString; -class QWidget; -QT_END_NAMESPACE - -namespace Ui { - class LookupSPDialog; -} - -/** Dialog for looking up Elysium Protocol tokens */ -class LookupSPDialog : public QDialog -{ - Q_OBJECT - -public: - explicit LookupSPDialog(QWidget *parent = 0); - ~LookupSPDialog(); - - void searchSP(); - void updateDisplayedProperty(); - void addSPToMatchingResults(unsigned int propertyId); - -public Q_SLOTS: - void searchButtonClicked(); - void matchingComboBoxChanged(int idx); - -private: - Ui::LookupSPDialog *ui; - WalletModel *model; - - void addDenominationRow(uint8_t id, const std::string& value); - -private Q_SLOTS: - // None - -Q_SIGNALS: - // Fired when a message should be reported to the user - void message(const QString &title, const QString &message, unsigned int style); -}; - -#endif // LOOKUPSPDIALOG_H diff --git a/src/qt/lookuptxdialog.cpp b/src/qt/lookuptxdialog.cpp deleted file mode 100644 index 95d39d4be9..0000000000 --- a/src/qt/lookuptxdialog.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2011-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "lookuptxdialog.h" -#include "ui_lookuptxdialog.h" - -#include "elysium/errors.h" -#include "elysium/rpc.h" -#include "elysium/rpctxobject.h" - -#include "elysium_qtutils.h" - -#include "uint256.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -using std::string; -using namespace elysium; - -LookupTXDialog::LookupTXDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::LookupTXDialog) -{ - ui->setupUi(this); - -#if QT_VERSION >= 0x040700 - ui->searchLineEdit->setPlaceholderText("Search transaction"); -#endif - - // connect actions - connect(ui->searchButton, &QPushButton::clicked, this, &LookupTXDialog::searchButtonClicked); -} - -LookupTXDialog::~LookupTXDialog() -{ - delete ui; -} - -void LookupTXDialog::searchTX() -{ - // search function to lookup address - string searchText = ui->searchLineEdit->text().toStdString(); - - // first let's check if we have a searchText, if not do nothing - if (searchText.empty()) return; - - uint256 hash; - hash.SetHex(searchText); - UniValue txobj(UniValue::VOBJ); - std::string strTXText; - // make a request to new RPC populator function to populate a transaction object - int populateResult = populateRPCTransactionObject(hash, txobj, "", true); - if (0<=populateResult) { - strTXText = txobj.write(true); - if (!strTXText.empty()) PopulateSimpleDialog(strTXText, "Transaction Information", "Transaction Information"); - } else { - // show error message - std::string strText = "The transaction hash entered is "; - switch(populateResult) { - case MP_TX_NOT_FOUND: - strText += "not a valid Firo or Elysium transaction. Please check the transaction hash " - "entered and try again."; - break; - case MP_TX_UNCONFIRMED: - strText += "unconfirmed. Toolbox lookup of transactions is currently only available for " - "confirmed transactions.\n\nTip: You can view your own outgoing unconfirmed " - "transactions in the transactions tab."; - break; - case MP_TX_IS_NOT_ELYSIUM_PROTOCOL: - strText += "a Firo transaction only.\n\nTip: You can use the debug console " - "'gettransaction' command to lookup specific Firo transactions."; - break; - - default: - strText += "of an unknown type. If you are seeing this message please raise a bug report " - "with the transaction hash at github.com/firoorg/firo/issues."; - break; - } - QString strQText = QString::fromStdString(strText); - QMessageBox errorDialog; - errorDialog.setIcon(QMessageBox::Critical); - errorDialog.setWindowTitle("TXID error"); - errorDialog.setText(strQText); - errorDialog.setStandardButtons(QMessageBox::Ok); - errorDialog.setDefaultButton(QMessageBox::Ok); - if(errorDialog.exec() == QMessageBox::Ok) { } // no other button to choose, acknowledged - } -} - -void LookupTXDialog::searchButtonClicked() -{ - searchTX(); -} diff --git a/src/qt/lookuptxdialog.h b/src/qt/lookuptxdialog.h deleted file mode 100644 index a5e452d0c9..0000000000 --- a/src/qt/lookuptxdialog.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef LOOKUPTXDIALOG_H -#define LOOKUPTXDIALOG_H - -#include - -QT_BEGIN_NAMESPACE -class QString; -class QWidget; -QT_END_NAMESPACE - -namespace Ui { - class LookupTXDialog; -} - -/** Dialog for looking up Omni Layer transactions */ -class LookupTXDialog : public QDialog -{ - Q_OBJECT - -public: - explicit LookupTXDialog(QWidget *parent = 0); - ~LookupTXDialog(); - - void searchTX(); - -public Q_SLOTS: - void searchButtonClicked(); - -private: - Ui::LookupTXDialog *ui; - -Q_SIGNALS: - // Fired when a message should be reported to the user - void message(const QString &title, const QString &message, unsigned int style); -}; - -#endif // LOOKUPTXDIALOG_H diff --git a/src/qt/metadexcanceldialog.cpp b/src/qt/metadexcanceldialog.cpp deleted file mode 100755 index 03cab0a302..0000000000 --- a/src/qt/metadexcanceldialog.cpp +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright (c) 2011-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "metadexcanceldialog.h" -#include "ui_metadexcanceldialog.h" - -#include "elysium_qtutils.h" - -#include "clientmodel.h" -#include "ui_interface.h" -#include "walletmodel.h" - -#include "elysium/createpayload.h" -#include "elysium/errors.h" -#include "elysium/mdex.h" -#include "elysium/elysium.h" -#include "elysium/sp.h" -#include "elysium/pending.h" -#include "elysium/utilsbitcoin.h" -#include "elysium/wallettxs.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using std::ostringstream; -using std::string; -using namespace elysium; - -MetaDExCancelDialog::MetaDExCancelDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::MetaDExCancelDialog), - clientModel(0), - walletModel(0) -{ - ui->setupUi(this); - - connect(ui->radioCancelPair, &QRadioButton::clicked,this, &MetaDExCancelDialog::UpdateCancelCombo); - connect(ui->radioCancelPrice, &QRadioButton::clicked,this, &MetaDExCancelDialog::UpdateCancelCombo); - connect(ui->radioCancelEverything, &QRadioButton::clicked,this, &MetaDExCancelDialog::UpdateCancelCombo); - connect(ui->cancelButton, &QPushButton::clicked,this, &MetaDExCancelDialog::SendCancelTransaction); - connect(ui->fromCombo, qOverload(&QComboBox::activated), this, &MetaDExCancelDialog::fromAddressComboBoxChanged); - - // perform initial from address population - UpdateAddressSelector(); -} - -MetaDExCancelDialog::~MetaDExCancelDialog() -{ - delete ui; -} - -/** - * Sets the client model. - */ -void MetaDExCancelDialog::setClientModel(ClientModel *model) -{ - this->clientModel = model; - if (model != NULL) { - connect(model, SIGNAL(refreshOmniBalance()), this, SLOT(RefreshUI())); - connect(model, SIGNAL(reinitOmniState()), this, SLOT(ReinitUI())); - } -} - -/** - * Sets the wallet model. - */ -void MetaDExCancelDialog::setWalletModel(WalletModel *model) -{ - this->walletModel = model; -} - -void MetaDExCancelDialog::ReinitUI() -{ - UpdateAddressSelector(); -} - -/** - * Refreshes the cancellation address selector - * - * Note: only addresses that have a currently open MetaDEx trade (determined by - * the metadex map) will be shown in the address selector (cancellations sent from - * addresses without an open MetaDEx trade are invalid). - */ -void MetaDExCancelDialog::UpdateAddressSelector() -{ - LOCK(cs_main); - - QString selectedItem = ui->fromCombo->currentText(); - ui->fromCombo->clear(); - - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - md_PricesMap & prices = my_it->second; - for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it) { - md_Set & indexes = (it->second); - for (md_Set::iterator it = indexes.begin(); it != indexes.end(); ++it) { - CMPMetaDEx obj = *it; - if(IsMyAddress(obj.getAddr())) { // this address is ours and has an active MetaDEx trade - int idx = ui->fromCombo->findText(QString::fromStdString(obj.getAddr())); // avoid adding duplicates - if (idx == -1) ui->fromCombo->addItem(QString::fromStdString(obj.getAddr())); - } - } - } - } - - // restore initial selection - int idx = ui->fromCombo->findText(selectedItem); - if (idx != -1) { - ui->fromCombo->setCurrentIndex(idx); - } -} - -/** - * Refreshes the cancel combo when the address selector is changed - */ -void MetaDExCancelDialog::fromAddressComboBoxChanged(int) -{ - UpdateCancelCombo(); // all that's needed at this stage -} - -/** - * Refreshes the cancel combo with the latest data based on the currently selected - * radio button. - */ -void MetaDExCancelDialog::UpdateCancelCombo() -{ - string senderAddress = ui->fromCombo->currentText().toStdString(); - QString existingSelection = ui->cancelCombo->currentText(); - - if (senderAddress.empty()) { - return; // no sender address selected, likely no wallet addresses have open MetaDEx trades - } - - if ((!ui->radioCancelPair->isChecked()) && (!ui->radioCancelPrice->isChecked()) && (!ui->radioCancelEverything->isChecked())) { - return; // no radio button is selected - } - - ui->cancelCombo->clear(); - - bool fMainEcosystem = false; - bool fTestEcosystem = false; - - LOCK(cs_main); - - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - md_PricesMap & prices = my_it->second; - for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it) { - md_Set & indexes = it->second; - for (md_Set::iterator it = indexes.begin(); it != indexes.end(); ++it) { - CMPMetaDEx obj = *it; - if(senderAddress == obj.getAddr()) { - // for "cancel all": - if (isMainEcosystemProperty(obj.getProperty())) fMainEcosystem = true; - if (isTestEcosystemProperty(obj.getProperty())) fTestEcosystem = true; - - bool isBuy = false; // sell or buy? (from UI perspective) - if ((obj.getProperty() == ELYSIUM_PROPERTY_ELYSIUM) || (obj.getProperty() == ELYSIUM_PROPERTY_TELYSIUM)) isBuy = true; - string sellToken = getPropertyName(obj.getProperty()).c_str(); - string desiredToken = getPropertyName(obj.getDesProperty()).c_str(); - string sellId = strprintf("%d", obj.getProperty()); - string desiredId = strprintf("%d", obj.getDesProperty()); - if(sellToken.size()>30) sellToken=sellToken.substr(0,30)+"..."; - sellToken += " (#" + sellId + ")"; - if(desiredToken.size()>30) desiredToken=desiredToken.substr(0,30)+"..."; - desiredToken += " (#" + desiredId + ")"; - string comboStr = "Cancel all orders "; - if (isBuy) { comboStr += "buying " + desiredToken; } else { comboStr += "selling " + sellToken; } - string dataStr = sellId + "/" + desiredId; - if (ui->radioCancelPrice->isChecked()) { // append price if needed - comboStr += " priced at " + StripTrailingZeros(obj.displayUnitPrice()); - if ((obj.getProperty() == ELYSIUM_PROPERTY_ELYSIUM) || (obj.getDesProperty() == ELYSIUM_PROPERTY_ELYSIUM)) { comboStr += " ELYSIUM/SPT"; } else { comboStr += " TELYSIUM/SPT"; } - dataStr += ":" + obj.displayUnitPrice(); - } - int index = ui->cancelCombo->findText(QString::fromStdString(comboStr)); - if ( index == -1 ) { ui->cancelCombo->addItem(QString::fromStdString(comboStr),QString::fromStdString(dataStr)); } - } - } - } - } - - if (ui->radioCancelEverything->isChecked()) { - ui->cancelCombo->clear(); - if (fMainEcosystem) ui->cancelCombo->addItem("All active orders in the main ecosystem", 1); - if (fTestEcosystem) ui->cancelCombo->addItem("All active orders in the test ecosystem", 2); - } - - int idx = ui->cancelCombo->findText(existingSelection, Qt::MatchExactly); - if (idx != -1) ui->cancelCombo->setCurrentIndex(idx); // if value selected before update and it still exists, reselect it -} - -/** - * Refreshes the UI fields with the most current data - called when the - * refreshOmniState() signal is received. - */ -void MetaDExCancelDialog::RefreshUI() -{ - UpdateAddressSelector(); - UpdateCancelCombo(); -} - - -/** - * Takes the data from the fields in the cancellation UI and asks the wallet to construct a - * MetaDEx cancel transaction. Then commits & broadcast the created transaction. - */ -void MetaDExCancelDialog::SendCancelTransaction() -{ - - std::string fromAddress = ui->fromCombo->currentText().toStdString(); - if (fromAddress.empty()) { - // no sender address selected - QMessageBox::critical( this, "Unable to send transaction", - "Please select the address you would like to send the cancellation transaction from." ); - return; - } - - uint8_t action = 0; - /* - * 1 = NEW - * 2 = CANCEL_AT_PRICE - * 3 = CANCEL_ALL_FOR_PAIR - * 4 = CANCEL_EVERYTHING - */ - - if (ui->radioCancelPrice->isChecked()) action = 2; - if (ui->radioCancelPair->isChecked()) action = 3; - if (ui->radioCancelEverything->isChecked()) action = 4; - if (action == 0) { - // no cancellation method selected - QMessageBox::critical( this, "Unable to send transaction", - "Please ensure you have selected a cancellation method and valid cancellation criteria." ); - return; - } -} diff --git a/src/qt/metadexcanceldialog.h b/src/qt/metadexcanceldialog.h deleted file mode 100755 index 51014889cb..0000000000 --- a/src/qt/metadexcanceldialog.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef METADEXCANCELDIALOG_H -#define METADEXCANCELDIALOG_H - -#include - -class ClientModel; -class WalletModel; - -QT_BEGIN_NAMESPACE -class QWidget; -class QString; -QT_END_NAMESPACE - -namespace Ui { - class MetaDExCancelDialog; -} - -/** Dialog for sending Master Protocol tokens */ -class MetaDExCancelDialog : public QDialog -{ - Q_OBJECT - -public: - explicit MetaDExCancelDialog(QWidget *parent = 0); - ~MetaDExCancelDialog(); - - void setClientModel(ClientModel *model); - void setWalletModel(WalletModel *model); - -public Q_SLOTS: - void SendCancelTransaction(); - void UpdateAddressSelector(); - void UpdateCancelCombo(); - void RefreshUI(); - void ReinitUI(); - void fromAddressComboBoxChanged(int); - -private: - Ui::MetaDExCancelDialog *ui; - ClientModel *clientModel; - WalletModel *walletModel; - -private Q_SLOTS: - // None! - -Q_SIGNALS: - // Fired when a message should be reported to the user - void message(const QString &title, const QString &message, unsigned int style); -}; - -#endif // METADEXCANCELDIALOG_H diff --git a/src/qt/metadexdialog.cpp b/src/qt/metadexdialog.cpp deleted file mode 100755 index 16f309f66f..0000000000 --- a/src/qt/metadexdialog.cpp +++ /dev/null @@ -1,561 +0,0 @@ -// Copyright (c) 2011-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "metadexdialog.h" -#include "ui_metadexdialog.h" - -#include "elysium_qtutils.h" - -#include "clientmodel.h" -#include "walletmodel.h" - -#include "elysium/createpayload.h" -#include "elysium/errors.h" -#include "elysium/mdex.h" -#include "elysium/elysium.h" -#include "elysium/parse_string.h" -#include "elysium/pending.h" -#include "elysium/rules.h" -#include "elysium/rpctxobject.h" -#include "elysium/sp.h" -#include "elysium/tally.h" -#include "elysium/utilsbitcoin.h" -#include "elysium/wallettxs.h" -#include "elysium/uint256_extensions.h" -#include "amount.h" -#include "sync.h" -#include "uint256.h" -// TODO #include "wallet_ismine.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using std::ostringstream; -using std::string; - -using namespace elysium; - -MetaDExDialog::MetaDExDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::MetaDExDialog), - clientModel(0), - walletModel(0), - global_metadex_market(3) -{ - ui->setupUi(this); - - ui->sellList->setColumnCount(5); - ui->sellList->verticalHeader()->setVisible(false); - #if QT_VERSION < 0x050000 - ui->sellList->horizontalHeader()->setResizeMode(QHeaderView::Stretch); - #else - ui->sellList->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); - #endif - ui->sellList->setShowGrid(false); - ui->sellList->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->sellList->setSelectionMode(QAbstractItemView::NoSelection); - ui->sellList->setAlternatingRowColors(true); - ui->sellList->setSelectionBehavior(QAbstractItemView::SelectRows); - ui->sellList->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->sellList->setSelectionMode(QAbstractItemView::SingleSelection); - - connect(ui->comboPairTokenA, qOverload(&QComboBox::activated), this, &MetaDExDialog::SwitchMarket); - connect(ui->comboPairTokenB, qOverload(&QComboBox::activated), this, &MetaDExDialog::SwitchMarket); - connect(ui->comboAddress, qOverload(&QComboBox::activated), this, &MetaDExDialog::UpdateBalance); - connect(ui->chkTestEco, &QCheckBox::clicked, this, &MetaDExDialog::FullRefresh); - connect(ui->buttonInvertPair, &QPushButton::clicked, this, &MetaDExDialog::InvertPair); - connect(ui->buttonTradeHistory, &QPushButton::clicked, this, &MetaDExDialog::ShowHistory); - connect(ui->sellAmountSaleLE, &QLineEdit::textEdited, this, &MetaDExDialog::RecalcSellValues); - connect(ui->sellAmountDesiredLE, &QLineEdit::textEdited, this, &MetaDExDialog::RecalcSellValues); - connect(ui->sellUnitPriceLE, &QLineEdit::textEdited, this, &MetaDExDialog::RecalcSellValues); - connect(ui->sellList, &QAbstractItemView::doubleClicked, this, &MetaDExDialog::ShowDetails); - connect(ui->sellButton, &QPushButton::clicked, this, &MetaDExDialog::sendTrade); - - FullRefresh(); -} - -MetaDExDialog::~MetaDExDialog() -{ - delete ui; -} - -uint32_t MetaDExDialog::GetPropForSale() -{ - QString propStr = ui->comboPairTokenA->itemData(ui->comboPairTokenA->currentIndex()).toString(); - if (propStr.isEmpty()) return 0; - return propStr.toUInt(); -} - -uint32_t MetaDExDialog::GetPropDesired() -{ - QString propStr = ui->comboPairTokenB->itemData(ui->comboPairTokenB->currentIndex()).toString(); - if (propStr.isEmpty()) return 0; - return propStr.toUInt(); -} - -void MetaDExDialog::setClientModel(ClientModel *model) -{ - this->clientModel = model; - if (NULL != model) { - connect(model, &ClientModel::refreshElysiumState, this, &MetaDExDialog::UpdateOffers); - connect(model, &ClientModel::refreshElysiumBalance, this, &MetaDExDialog::BalanceOrderRefresh); - connect(model, &ClientModel::reinitElysiumState, this, &MetaDExDialog::FullRefresh); - } -} - -void MetaDExDialog::setWalletModel(WalletModel *model) -{ - // use wallet model to get visibility into FIRO balance changes for fees - this->walletModel = model; - if (model != NULL) { - connect(model, &WalletModel::balanceChanged, this, &MetaDExDialog::UpdateBalance); - } -} - -void MetaDExDialog::PopulateAddresses() -{ - { // restrict scope of lock to address updates only (don't hold for balance update too) - LOCK(cs_main); - - uint32_t propertyId = GetPropForSale(); - QString currentSetAddress = ui->comboAddress->currentText(); - ui->comboAddress->clear(); - for (std::unordered_map::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) { - string address = (my_it->first).c_str(); - uint32_t id; - (my_it->second).init(); - while (0 != (id = (my_it->second).next())) { - if (id == propertyId) { - if (!getUserAvailableMPbalance(address, propertyId)) continue; // ignore this address, has no available balance to spend - if (IsMyAddress(address)) ui->comboAddress->addItem((my_it->first).c_str()); // only include wallet addresses - } - } - } - int idx = ui->comboAddress->findText(currentSetAddress); - if (idx != -1) { ui->comboAddress->setCurrentIndex(idx); } - } - UpdateBalance(); -} - -void MetaDExDialog::UpdateProperties() -{ - bool testEco = ui->chkTestEco->isChecked(); - - QString currentSetPropA = ui->comboPairTokenA->currentText(); - QString currentSetPropB = ui->comboPairTokenB->currentText(); - ui->comboPairTokenA->clear(); - ui->comboPairTokenB->clear(); - - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - uint32_t propertyId = my_it->first; - if ((testEco && !isTestEcosystemProperty(propertyId)) || (!testEco && isTestEcosystemProperty(propertyId))) continue; - string spName; - spName = getPropertyName(propertyId).c_str(); - uint32_t nameMax = 30; - if (isTestEcosystemProperty(propertyId)) nameMax = 20; - if (spName.size()>nameMax) { - spName = spName.substr(0,nameMax)+"..."; - } - string spId = strprintf("%d", propertyId); - spName += " (#" + spId + ")"; - ui->comboPairTokenA->addItem(spName.c_str(),spId.c_str()); - ui->comboPairTokenB->addItem(spName.c_str(),spId.c_str()); - } - - if (ui->comboPairTokenA->count() > 1) { - int idxA = ui->comboPairTokenA->findText(currentSetPropA); - if (idxA != -1) { - ui->comboPairTokenA->setCurrentIndex(idxA); - } else { - ui->comboPairTokenA->setCurrentIndex(0); - } - } - if (ui->comboPairTokenB->count() > 2) { - int idxB = ui->comboPairTokenB->findText(currentSetPropB); - if (idxB != -1) { - ui->comboPairTokenB->setCurrentIndex(idxB); - } else { - ui->comboPairTokenB->setCurrentIndex(1); - } - } -} - -// Update the balance for the currently selected address -void MetaDExDialog::UpdateBalance() -{ - QString currentSetAddress = ui->comboAddress->currentText(); - if (currentSetAddress.isEmpty()) { - ui->lblBalance->setText(QString::fromStdString("Your balance: N/A")); - ui->lblFeeWarning->setVisible(false); - } else { - uint32_t propertyId = GetPropForSale(); - int64_t balanceAvailable = getUserAvailableMPbalance(currentSetAddress.toStdString(), propertyId); - string sellBalStr; - if (isPropertyDivisible(propertyId)) { - sellBalStr = FormatDivisibleMP(balanceAvailable); - } else { - sellBalStr = FormatIndivisibleMP(balanceAvailable); - } - ui->lblBalance->setText(QString::fromStdString("Your balance: " + sellBalStr + getTokenLabel(propertyId))); - // warning label will be lit if insufficient fees for MetaDEx payload (28 bytes) - if (CheckFee(currentSetAddress.toStdString(), 28)) { - ui->lblFeeWarning->setVisible(false); - } else { - ui->lblFeeWarning->setText("WARNING: The address is low on BTC for transaction fees."); - ui->lblFeeWarning->setVisible(true); - } - } -} - -// Change markets when one of the property selector combos is changed -void MetaDExDialog::SwitchMarket() -{ - QString propAStr = ui->comboPairTokenA->itemData(ui->comboPairTokenA->currentIndex()).toString(); - QString propBStr = ui->comboPairTokenB->itemData(ui->comboPairTokenB->currentIndex()).toString(); - if (propAStr.isEmpty() || propBStr.isEmpty()) { - PrintToLog("QTERROR: Empty variable switching property markets. PropA=%s, PropB=%s\n",propAStr.toStdString(),propBStr.toStdString()); - return; - } - uint32_t propA = propAStr.toUInt(); - uint32_t propB = propBStr.toUInt(); - if (propA == propB) { - QMessageBox::critical( this, "Unable to change markets", - "The property being sold and property desired cannot be the same." ); - return; - } - ui->sellAmountSaleLE->clear(); - ui->sellAmountDesiredLE->clear(); - ui->sellUnitPriceLE->clear(); - - FullRefresh(); -} - -// Recalulates the form sell values when one is changed -void MetaDExDialog::RecalcSellValues() -{ - int64_t amountForSale = 0; - int64_t amountDesired = 0; - amountForSale = StrToInt64(ui->sellAmountSaleLE->text().toStdString(),isPropertyDivisible(GetPropForSale())); - amountDesired = StrToInt64(ui->sellAmountDesiredLE->text().toStdString(),isPropertyDivisible(GetPropDesired())); - - if (0 >= amountForSale) { - ui->sellAmountSaleLE->setStyleSheet(" QLineEdit { background-color:rgb(255, 204, 209); }"); - } else { - ui->sellAmountSaleLE->setStyleSheet(" QLineEdit { }"); - } - if (0 >= amountDesired) { - ui->sellAmountDesiredLE->setStyleSheet(" QLineEdit { background-color:rgb(255, 204, 209); }"); - } else { - ui->sellAmountDesiredLE->setStyleSheet(" QLineEdit { }"); - } - if (ui->sellAmountSaleLE->text().toStdString().length()==0) ui->sellAmountSaleLE->setStyleSheet(" QLineEdit { }"); - if (ui->sellAmountDesiredLE->text().toStdString().length()==0) ui->sellAmountDesiredLE->setStyleSheet(" QLineEdit { }"); - - if (0 >= amountForSale || 0>= amountDesired) { - ui->sellUnitPriceLE->clear(); - return; - } - - rational_t unitPrice(amountForSale, amountDesired); - std::string unitPriceStr = xToString(unitPrice); - if (unitPriceStr.length() > 25) unitPriceStr.resize(25); // keep the price from getting too long - ui->sellUnitPriceLE->setText(QString::fromStdString(unitPriceStr)); -} - -// Performs a full refresh of all elements - for example when switching markets -void MetaDExDialog::FullRefresh() -{ - UpdateProperties(); - PopulateAddresses(); - UpdateOffers(); - - ui->lblATSToken->setText(QString::fromStdString(getTokenLabel(GetPropForSale()))); - ui->lblADToken->setText(QString::fromStdString(getTokenLabel(GetPropDesired()))); - ui->sellList->setHorizontalHeaderItem(0, new QTableWidgetItem("TXID")); - ui->sellList->setHorizontalHeaderItem(1, new QTableWidgetItem("Seller")); - ui->sellList->setHorizontalHeaderItem(2, new QTableWidgetItem("Unit Price")); - ui->sellList->setHorizontalHeaderItem(3, new QTableWidgetItem(QString::fromStdString(getTokenLabel(GetPropForSale())) + " For Sale")); - ui->sellList->setHorizontalHeaderItem(4, new QTableWidgetItem(QString::fromStdString(getTokenLabel(GetPropDesired())) + " Desired")); - ui->sellButton->setText("Sell " + QString::fromStdString(getTokenLabel(GetPropForSale()))); -} - -// Inverts the pair -void MetaDExDialog::InvertPair() -{ - QString propAStr = ui->comboPairTokenA->itemData(ui->comboPairTokenA->currentIndex()).toString(); - QString propBStr = ui->comboPairTokenB->itemData(ui->comboPairTokenB->currentIndex()).toString(); - QString currentSetPropA = ui->comboPairTokenA->currentText(); - QString currentSetPropB = ui->comboPairTokenB->currentText(); - if (propAStr.isEmpty() || propBStr.isEmpty()) { - PrintToLog("QTERROR: Empty variable switching property markets. PropA=%s, PropB=%s\n",propAStr.toStdString(),propBStr.toStdString()); - return; - } - uint32_t propA = propAStr.toUInt(); - uint32_t propB = propBStr.toUInt(); - uint32_t tempB = propB; - propB = propA; - propA = tempB; - - if (ui->comboPairTokenA->count() > 1) { - int idxA = ui->comboPairTokenA->findText(currentSetPropB); - if (idxA != -1) { - ui->comboPairTokenA->setCurrentIndex(idxA); - } else { - ui->comboPairTokenA->setCurrentIndex(0); - } - } - if (ui->comboPairTokenB->count() > 2) { - int idxB = ui->comboPairTokenB->findText(currentSetPropA); - if (idxB != -1) { - ui->comboPairTokenB->setCurrentIndex(idxB); - } else { - ui->comboPairTokenB->setCurrentIndex(1); - } - } - - ui->sellAmountSaleLE->clear(); - ui->sellAmountDesiredLE->clear(); - ui->sellUnitPriceLE->clear(); - FullRefresh(); -} - -// Loops through the MetaDEx and updates the list of offers -void MetaDExDialog::UpdateOffers() -{ - ui->sellList->setRowCount(0); - - LOCK(cs_main); - - // Obtain divisibility outside the loop to avoid repeatedly loading properties - bool divisSale = isPropertyDivisible(GetPropForSale()); - bool divisDes = isPropertyDivisible(GetPropDesired()); - - for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) { - if ((my_it->first != GetPropForSale())) continue; // not the property we're looking for, don't waste any more work - md_PricesMap & prices = my_it->second; - for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it) { // loop through the sell prices for the property - std::string unitPriceStr; - bool includesMe = false; - md_Set & indexes = (it->second); - for (md_Set::iterator it = indexes.begin(); it != indexes.end(); ++it) { // multiple sell offers can exist at the same price, sum them for the UI - const CMPMetaDEx& obj = *it; - if ((obj.getDesProperty() != GetPropDesired())) continue; // not the property we're interested in - if (IsMyAddress(obj.getAddr())) includesMe = true; - std::string strAvail; - if (divisSale) { - strAvail = FormatDivisibleShortMP(obj.getAmountRemaining()); - } else { - strAvail = FormatIndivisibleMP(obj.getAmountRemaining()); - } - std::string strDesired; - if (divisDes) { - strDesired = FormatDivisibleShortMP(obj.getAmountToFill()); - } else { - strDesired = FormatIndivisibleMP(obj.getAmountToFill()); - } - std::string priceStr = StripTrailingZeros(obj.displayFullUnitPrice()); - if (priceStr.length() > 10) { - priceStr.resize(10); // keep price in UI managable - priceStr += "..."; - } - AddRow(includesMe, obj.getHash().GetHex(), obj.getAddr(), priceStr, strAvail, strDesired); - } - } - } -} - -// This function adds a row to the buy or sell offer list -void MetaDExDialog::AddRow(bool includesMe, const string& txid, const string& seller, const string& price, const string& available, const string& desired) -{ - int workingRow; - workingRow = ui->sellList->rowCount(); - ui->sellList->insertRow(workingRow); - - QTableWidgetItem *txidCell = new QTableWidgetItem(QString::fromStdString(txid)); - QTableWidgetItem *sellerCell = new QTableWidgetItem(QString::fromStdString(seller)); - QTableWidgetItem *priceCell = new QTableWidgetItem(QString::fromStdString(price)); - QTableWidgetItem *availableCell = new QTableWidgetItem(QString::fromStdString(available)); - QTableWidgetItem *desiredCell = new QTableWidgetItem(QString::fromStdString(desired)); - if(includesMe) { - QFont font; - font.setBold(true); - txidCell->setFont(font); - sellerCell->setFont(font); - priceCell->setFont(font); - availableCell->setFont(font); - desiredCell->setFont(font); - } - txidCell->setTextAlignment(Qt::AlignLeft + Qt::AlignVCenter); - sellerCell->setTextAlignment(Qt::AlignLeft + Qt::AlignVCenter); - availableCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - priceCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - desiredCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - ui->sellList->setItem(workingRow, 0, txidCell); - ui->sellList->setItem(workingRow, 1, sellerCell); - ui->sellList->setItem(workingRow, 2, priceCell); - ui->sellList->setItem(workingRow, 3, availableCell); - ui->sellList->setItem(workingRow, 4, desiredCell); -} - -// Displays details of the selected trade and any associated matches -void MetaDExDialog::ShowDetails() -{ - UniValue txobj(UniValue::VOBJ);; - uint256 txid; - txid.SetHex(ui->sellList->item(ui->sellList->currentRow(),0)->text().toStdString()); - std::string strTXText; - - if (!txid.IsNull()) { - // grab extended trade details via the RPC populator - int rc = populateRPCTransactionObject(txid, txobj, "", true); - if (rc >= 0) strTXText = txobj.write(true); - } - - if (!strTXText.empty()) { - PopulateSimpleDialog(strTXText, "Trade Information", "Trade Information"); - } -} - -// Show trade history for this pair -void MetaDExDialog::ShowHistory() -{ - UniValue history(UniValue::VARR); - LOCK(cs_main); - t_tradelistdb->getTradesForPair(GetPropForSale(), GetPropDesired(), history, 50); - std::string strHistory = history.write(true); - - if (!strHistory.empty()) { - PopulateSimpleDialog(strHistory, "Trade History", "Trade History"); - } -} - -void MetaDExDialog::BalanceOrderRefresh() -{ - PopulateAddresses(); - UpdateOffers(); -} - -void MetaDExDialog::sendTrade() -{ -// int blockHeight = GetHeight(); - - string strFromAddress = ui->comboAddress->currentText().toStdString(); - int64_t amountForSale = 0; - int64_t amountDesired = 0; - amountForSale = StrToInt64(ui->sellAmountSaleLE->text().toStdString(),isPropertyDivisible(GetPropForSale())); - amountDesired = StrToInt64(ui->sellAmountDesiredLE->text().toStdString(),isPropertyDivisible(GetPropDesired())); - if (0 >= amountForSale || 0>= amountDesired) { - QMessageBox::critical( this, "Unable to send MetaDEx trade", - "The amount values supplied are not valid. Please check your trade parameters and try again." ); - return; - } - -/** - // warn if we have to truncate the amount due to a decimal amount for an indivisible property, but allow send to continue - if (divisible) { - size_t pos = strAmount.find("."); - if (pos!=std::string::npos) { - string tmpStrAmount = strAmount.substr(0,pos); - string strMsgText = "The amount entered contains a decimal however the property being transacted is indivisible.\n\nThe amount entered will be truncated as follows:\n"; - strMsgText += "Original amount entered: " + strAmount + "\nAmount that will be used: " + tmpStrAmount + "\n\n"; - strMsgText += "Do you still wish to proceed with the transaction?"; - QString msgText = QString::fromStdString(strMsgText); - QMessageBox::StandardButton responseClick; - responseClick = QMessageBox::question(this, "Amount truncation warning", msgText, QMessageBox::Yes|QMessageBox::No); - if (responseClick == QMessageBox::No) { - QMessageBox::critical( this, "MetaDEx transaction cancelled", - "The MetaDEx transaction has been cancelled.\n\nPlease double-check the transction details thoroughly before retrying your transaction." ); - return; - } - strAmount = tmpStrAmount; - if (!sell) { ui->buyAmountLE->setText(QString::fromStdString(strAmount)); } else { ui->sellAmountLE->setText(QString::fromStdString(strAmount)); } - } - } -**/ - - // check if sending address has enough funds - int64_t balanceAvailable = 0; - balanceAvailable = getUserAvailableMPbalance(strFromAddress, GetPropForSale()); - if (amountForSale > balanceAvailable) { - QMessageBox::critical( this, "Unable to send MetaDEx transaction", - "The selected sending address does not have a sufficient balance to cover the amount entered.\n\nPlease double-check the transction details thoroughly before retrying your transaction." ); - return; - } - - // check if wallet is still syncing, as this will currently cause a lockup if we try to send - compare our chain to peers to see if we're up to date - // Bitcoin Core devs have removed GetNumBlocksOfPeers, switching to a time based best guess scenario - uint32_t intBlockDate = GetLatestBlockTime(); // uint32, not using time_t for portability - QDateTime currentDate = QDateTime::currentDateTime(); - int secs = QDateTime::fromTime_t(intBlockDate).secsTo(currentDate); - if(secs > 90*60) { - QMessageBox::critical( this, "Unable to send MetaDEx transaction", - "The client is still synchronizing. Sending transactions can currently be performed only when the client has completed synchronizing." ); - return; - } - - // validation checks all look ok, let's throw up a confirmation dialog - std::string strMsgText = "You are about to send the following MetaDEx transaction, please check the details thoroughly:\n\n"; - strMsgText += "Type: Trade Request\nFrom: " + strFromAddress + "\n\n"; - strMsgText += "Sell " + FormatMP(isPropertyDivisible(GetPropForSale()), amountForSale) + getTokenLabel(GetPropForSale()); - strMsgText += " for " + FormatMP(isPropertyDivisible(GetPropDesired()), amountDesired) + getTokenLabel(GetPropDesired()); - strMsgText += "\n\nAre you sure you wish to send this transaction?"; - QString msgText = QString::fromStdString(strMsgText); - QMessageBox::StandardButton responseClick; - responseClick = QMessageBox::question(this, "Confirm MetaDEx transaction", msgText, QMessageBox::Yes|QMessageBox::No); - if (responseClick == QMessageBox::No) - { - QMessageBox::critical( this, "MetaDEx transaction cancelled", - "The transaction has been cancelled.\n\nPlease double-check the transction details thoroughly before retrying your transaction." ); - return; - } - - // unlock the wallet - WalletModel::UnlockContext ctx(walletModel->requestUnlock()); - if(!ctx.isValid()) - { - // Unlock wallet was cancelled/failed - QMessageBox::critical( this, "MetaDEx transaction failed", - "The transaction has been cancelled.\n\nThe wallet unlock process must be completed to send a transaction." ); - return; - } - - // create a payload for the transaction - std::vector payload = CreatePayload_MetaDExTrade(GetPropForSale(), amountForSale, GetPropDesired(), amountDesired); - - // request the wallet build the transaction (and if needed commit it) - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(strFromAddress, "", "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - string strError = error_str(result); - QMessageBox::critical( this, "MetaDEx transaction failed", - "The MetaDEx transaction has failed.\n\nThe error code was: " + QString::number(result) + "\nThe error message was:\n" + QString::fromStdString(strError)); - return; - } else { - if (!autoCommit) { - PopulateSimpleDialog(rawHex, "Raw Hex (auto commit is disabled)", "Raw transaction hex"); - } else { - PendingAdd(txid, strFromAddress, ELYSIUM_TYPE_METADEX_TRADE, GetPropForSale(), amountForSale); - PopulateTXSentDialog(txid.GetHex()); - } - } -} diff --git a/src/qt/metadexdialog.h b/src/qt/metadexdialog.h deleted file mode 100755 index 3ca73073fc..0000000000 --- a/src/qt/metadexdialog.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef METADEXDIALOG_H -#define METADEXDIALOG_H - -#include -#include - -#include - -class WalletModel; -class ClientModel; - -QT_BEGIN_NAMESPACE -class QString; -class QWidget; -QT_END_NAMESPACE - -namespace Ui { - class MetaDExDialog; -} - -/** Dialog for looking up Master Protocol tokens */ -class MetaDExDialog : public QDialog -{ - Q_OBJECT - -public: - explicit MetaDExDialog(QWidget *parent = 0); - ~MetaDExDialog(); - - void AddRow(bool includesMe, const std::string& txid, const std::string& seller, const std::string& price, const std::string& available, const std::string& desired); - void UpdateProperties(); - void setWalletModel(WalletModel *model); - void setClientModel(ClientModel *model); - void PopulateAddresses(); - uint32_t GetPropForSale(); - uint32_t GetPropDesired(); - -public Q_SLOTS: - void SwitchMarket(); - void sendTrade(); - void UpdateBalance(); - void UpdateOffers(); - void BalanceOrderRefresh(); - void FullRefresh(); - void RecalcSellValues(); - void InvertPair(); - void ShowDetails(); - void ShowHistory(); - -private: - Ui::MetaDExDialog *ui; - ClientModel *clientModel; - WalletModel *walletModel; - uint32_t global_metadex_market; - -private Q_SLOTS: - // none - -Q_SIGNALS: - // Fired when a message should be reported to the user - void message(const QString &title, const QString &message, unsigned int style); -}; - -#endif // METADEXDIALOG_H diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 59f200e486..3e3e79acd1 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -60,18 +60,11 @@ public Q_SLOTS: const CAmount& privateBalance, const CAmount& unconfirmedPrivateBalance, const CAmount& anonymizableBalance); - //void updateElysium(); - //void reinitElysium(); Q_SIGNALS: void transactionClicked(const QModelIndex &index); void enabledTorChanged(); void outOfSyncWarningClicked(); - -#ifdef ENABLE_ELYSIUM - void elysiumTransactionClicked(const uint256& txid); -#endif - private: Ui::OverviewPage *ui; ClientModel *clientModel; diff --git a/src/qt/res/css/firo.css b/src/qt/res/css/firo.css index d99b96f80b..ddb8c583e6 100644 --- a/src/qt/res/css/firo.css +++ b/src/qt/res/css/firo.css @@ -1246,21 +1246,6 @@ QDialog#LelantusDialog QRadioButton#radioCustomFee { margin-top: 7px; } -/* LookupAddressDialog */ - -QWidget#LookupAddressDialog QLabel#addressInfo, -QWidget#LookupAddressDialog QLabel#balanceInfo { - font-weight: bold; -} - -/* LookupSPDialog */ - -QWidget#LookupSPDialog QLabel#spInfo, -QWidget#LookupSPDialog QLabel#tokenInfo, -QWidget#LookupSPDialog QLabel#crowdInfo { - font-weight: bold; -} - /* ManualMintDialog */ QDialog#ManualMintDialog QLabel#availableAmount, @@ -1268,14 +1253,6 @@ QDialog#ManualMintDialog QLabel#totalAmount { font-weight: bold; } -/* MetaDExCancelDialog */ - -QWidget#MetaDExCancelDialog QLabel#label_3, -QWidget#MetaDExCancelDialog QLabel#label_2, -QWidget#MetaDExCancelDialog QLabel#label { - font-weight: bold; -} - /* ModalOverlay */ QWidget#bgWidget { diff --git a/src/qt/res/icons/elysium_hourglass.png b/src/qt/res/icons/elysium_hourglass.png deleted file mode 100644 index 78a258a371..0000000000 Binary files a/src/qt/res/icons/elysium_hourglass.png and /dev/null differ diff --git a/src/qt/res/icons/elysium_in.png b/src/qt/res/icons/elysium_in.png deleted file mode 100644 index 8ac588399a..0000000000 Binary files a/src/qt/res/icons/elysium_in.png and /dev/null differ diff --git a/src/qt/res/icons/elysium_inout.png b/src/qt/res/icons/elysium_inout.png deleted file mode 100644 index 312a8ec70e..0000000000 Binary files a/src/qt/res/icons/elysium_inout.png and /dev/null differ diff --git a/src/qt/res/icons/elysium_invalid.png b/src/qt/res/icons/elysium_invalid.png deleted file mode 100644 index 76f9c8b680..0000000000 Binary files a/src/qt/res/icons/elysium_invalid.png and /dev/null differ diff --git a/src/qt/res/icons/elysium_out.png b/src/qt/res/icons/elysium_out.png deleted file mode 100644 index 5d01efc18d..0000000000 Binary files a/src/qt/res/icons/elysium_out.png and /dev/null differ diff --git a/src/qt/sendmpdialog.cpp b/src/qt/sendmpdialog.cpp deleted file mode 100644 index 1c7b6ebfbe..0000000000 --- a/src/qt/sendmpdialog.cpp +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright (c) 2011-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "sendmpdialog.h" -#include "ui_sendmpdialog.h" - -#include "elysium_qtutils.h" - -#include "clientmodel.h" -#include "walletmodel.h" - -#include "platformstyle.h" - -#include "../elysium/createpayload.h" -#include "../elysium/errors.h" -#include "../elysium/parse_string.h" -#include "../elysium/pending.h" -#include "../elysium/sp.h" -#include "../elysium/tally.h" -#include "../elysium/tx.h" -#include "../elysium/utilsbitcoin.h" -#include "../elysium/wallettxs.h" - -#include "../amount.h" -#include "../base58.h" -#include "../validation.h" -#include "../sync.h" -#include "../uint256.h" -#include "../wallet/wallet.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -using std::ostringstream; -using std::string; - -using namespace elysium; - -SendMPDialog::SendMPDialog(const PlatformStyle *platformStyle, QWidget *parent) : - QDialog(parent), - ui(new Ui::SendMPDialog), - clientModel(0), - walletModel(0), - platformStyle(platformStyle) -{ - ui->setupUi(this); - - // Use platformStyle instead of ifdef Q_OS_MAC to hide icons on Mac - if (!platformStyle->getImagesOnButtons()) { - ui->clearButton->setIcon(QIcon()); - ui->sendButton->setIcon(QIcon()); - } else { - // Use platformStyle to color the icons to match the rest of the UI - ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); - ui->sendButton->setIcon(platformStyle->SingleColorIcon(":/icons/send")); - } - -#if QT_VERSION >= 0x040700 // populate placeholder text - ui->sendToLineEdit->setPlaceholderText("Enter an Elysium address (e.g. 1oMn1LaYeRADDreSShef77z6A5S4P)"); - ui->amountLineEdit->setPlaceholderText("Enter Amount"); -#endif - - // connect actions - connect(ui->propertyComboBox, qOverload(&QComboBox::activated), this, &SendMPDialog::propertyComboBoxChanged); - connect(ui->sendFromComboBox, qOverload(&QComboBox::activated), this, &SendMPDialog::sendFromComboBoxChanged); - connect(ui->clearButton, &QPushButton::clicked, this, &SendMPDialog::clearButtonClicked); - connect(ui->sendButton, &QPushButton::clicked, this, &SendMPDialog::sendButtonClicked); - - // initial update - balancesUpdated(); -} - -SendMPDialog::~SendMPDialog() -{ - delete ui; -} - -void SendMPDialog::setClientModel(ClientModel *model) -{ - this->clientModel = model; - if (model != NULL) { - connect(model, &ClientModel::refreshElysiumBalance, this, &SendMPDialog::balancesUpdated); - connect(model, &ClientModel::reinitElysiumState, this, &SendMPDialog::balancesUpdated); - } -} - -void SendMPDialog::setWalletModel(WalletModel *model) -{ - // use wallet model to get visibility into BTC balance changes for fees - this->walletModel = model; - if (model != NULL) { - connect(model, &WalletModel::balanceChanged, this, &SendMPDialog::updateFrom); - } -} - -void SendMPDialog::updatePropSelector() -{ - LOCK(cs_main); - - uint32_t nextPropIdMainEco = GetNextPropertyId(true); // these allow us to end the for loop at the highest existing - uint32_t nextPropIdTestEco = GetNextPropertyId(false); // property ID rather than a fixed value like 100000 (optimization) - QString spId = ui->propertyComboBox->itemData(ui->propertyComboBox->currentIndex()).toString(); - ui->propertyComboBox->clear(); - - for (unsigned int propertyId = 1; propertyId < nextPropIdMainEco; propertyId++) { - if ((global_balance_money[propertyId] > 0) || (global_balance_reserved[propertyId] > 0)) { - std::string spName = getPropertyName(propertyId); - std::string spId = strprintf("%d", propertyId); - if(spName.size()>23) spName=spName.substr(0,23) + "..."; - spName += " (#" + spId + ")"; - if (isPropertyDivisible(propertyId)) { spName += " [D]"; } else { spName += " [I]"; } - ui->propertyComboBox->addItem(spName.c_str(),spId.c_str()); - } - } - for (unsigned int propertyId = 2147483647; propertyId < nextPropIdTestEco; propertyId++) { - if ((global_balance_money[propertyId] > 0) || (global_balance_reserved[propertyId] > 0)) { - std::string spName = getPropertyName(propertyId); - std::string spId = strprintf("%d", propertyId); - if(spName.size()>23) spName=spName.substr(0,23)+"..."; - spName += " (#" + spId + ")"; - if (isPropertyDivisible(propertyId)) { spName += " [D]"; } else { spName += " [I]"; } - ui->propertyComboBox->addItem(spName.c_str(),spId.c_str()); - } - } - int propIdx = ui->propertyComboBox->findData(spId); - if (propIdx != -1) { ui->propertyComboBox->setCurrentIndex(propIdx); } -} - -void SendMPDialog::clearFields() -{ - ui->sendToLineEdit->setText(""); - ui->amountLineEdit->setText(""); -} - -void SendMPDialog::updateFrom() -{ - // check if this from address has sufficient fees for a send, if not light up warning label - std::string currentSetFromAddress = ui->sendFromComboBox->currentText().toStdString(); - size_t spacer = currentSetFromAddress.find(" "); - if (spacer!=std::string::npos) { - currentSetFromAddress = currentSetFromAddress.substr(0,spacer); - ui->sendFromComboBox->setEditable(true); - QLineEdit *comboDisplay = ui->sendFromComboBox->lineEdit(); - comboDisplay->setText(QString::fromStdString(currentSetFromAddress)); - comboDisplay->setReadOnly(true); - } - - if (currentSetFromAddress.empty()) { - ui->balanceLabel->setText(QString::fromStdString("Address Balance: N/A")); - ui->feeWarningLabel->setVisible(false); - } else { - // update the balance for the selected address - QString spId = ui->propertyComboBox->itemData(ui->propertyComboBox->currentIndex()).toString(); - uint32_t propertyId = spId.toUInt(); - if (propertyId > 0) { - ui->balanceLabel->setText(QString::fromStdString("Address Balance: " + FormatMP(propertyId, getUserAvailableMPbalance(currentSetFromAddress, propertyId)) + getTokenLabel(propertyId))); - } - // warning label will be lit if insufficient fees for simple send (16 byte payload) - if (CheckFee(currentSetFromAddress, 16)) { - ui->feeWarningLabel->setVisible(false); - } else { - ui->feeWarningLabel->setText("WARNING: The sending address is low on FIRO for transaction fees. Please topup the FIRO balance for the sending address to send Elysium transactions."); - ui->feeWarningLabel->setVisible(true); - } - } -} - -void SendMPDialog::updateProperty() -{ - // cache currently selected from address & clear address selector - std::string currentSetFromAddress = ui->sendFromComboBox->currentText().toStdString(); - ui->sendFromComboBox->clear(); - - // populate from address selector - QString spId = ui->propertyComboBox->itemData(ui->propertyComboBox->currentIndex()).toString(); - uint32_t propertyId = spId.toUInt(); - LOCK(cs_main); - for (std::unordered_map::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) { - string address = (my_it->first).c_str(); - uint32_t id = 0; - bool includeAddress=false; - (my_it->second).init(); - while (0 != (id = (my_it->second).next())) { - if(id == propertyId) { includeAddress=true; break; } - } - if (!includeAddress) continue; //ignore this address, has never transacted in this propertyId - if (IsMyAddress(address) != ISMINE_SPENDABLE) continue; // ignore this address, it's not spendable - if (!getUserAvailableMPbalance(address, propertyId)) continue; // ignore this address, has no available balance to spend - ui->sendFromComboBox->addItem(QString::fromStdString(address + " \t" + FormatMP(propertyId, getUserAvailableMPbalance(address, propertyId)) + getTokenLabel(propertyId))); - } - - // attempt to set from address back to cached value - int fromIdx = ui->sendFromComboBox->findText(QString::fromStdString(currentSetFromAddress), Qt::MatchContains); - if (fromIdx != -1) { ui->sendFromComboBox->setCurrentIndex(fromIdx); } // -1 means the cached from address doesn't have a balance in the newly selected property - - // populate balance for global wallet - ui->globalBalanceLabel->setText(QString::fromStdString("Wallet Balance (Available): " + FormatMP(propertyId, global_balance_money[propertyId]))); - -#if QT_VERSION >= 0x040700 - // update placeholder text - if (isPropertyDivisible(propertyId)) { ui->amountLineEdit->setPlaceholderText("Enter Divisible Amount"); } else { ui->amountLineEdit->setPlaceholderText("Enter Indivisible Amount"); } -#endif -} - -void SendMPDialog::sendMPTransaction() -{ - // get the property being sent and get divisibility - QString spId = ui->propertyComboBox->itemData(ui->propertyComboBox->currentIndex()).toString(); - if (spId.toStdString().empty()) { - QMessageBox::critical( this, "Unable to send transaction", - "The property selected is not valid.\n\nPlease double-check the transction details thoroughly before retrying your send transaction." ); - return; - } - uint32_t propertyId = spId.toUInt(); - bool divisible = isPropertyDivisible(propertyId); - - // obtain the selected sender address - string strFromAddress = ui->sendFromComboBox->currentText().toStdString(); - - // push recipient address into a CBitcoinAddress type and check validity - CBitcoinAddress fromAddress; - if (false == strFromAddress.empty()) { fromAddress.SetString(strFromAddress); } - if (!fromAddress.IsValid()) { - QMessageBox::critical( this, "Unable to send transaction", - "The sender address selected is not valid.\n\nPlease double-check the transction details thoroughly before retrying your send transaction." ); - return; - } - - // obtain the entered recipient address - string strRefAddress = ui->sendToLineEdit->text().toStdString(); - // push recipient address into a CBitcoinAddress type and check validity - CBitcoinAddress refAddress; - if (false == strRefAddress.empty()) { refAddress.SetString(strRefAddress); } - if (!refAddress.IsValid()) { - QMessageBox::critical( this, "Unable to send transaction", - "The recipient address entered is not valid.\n\nPlease double-check the transction details thoroughly before retrying your send transaction." ); - return; - } - - // warn if we have to truncate the amount due to a decimal amount for an indivisible property, but allow send to continue - string strAmount = ui->amountLineEdit->text().toStdString(); - if (!divisible) { - size_t pos = strAmount.find("."); - if (pos!=std::string::npos) { - string tmpStrAmount = strAmount.substr(0,pos); - string strMsgText = "The amount entered contains a decimal however the property being sent is indivisible.\n\nThe amount entered will be truncated as follows:\n"; - strMsgText += "Original amount entered: " + strAmount + "\nAmount that will be sent: " + tmpStrAmount + "\n\n"; - strMsgText += "Do you still wish to proceed with the transaction?"; - QString msgText = QString::fromStdString(strMsgText); - QMessageBox::StandardButton responseClick; - responseClick = QMessageBox::question(this, "Amount truncation warning", msgText, QMessageBox::Yes|QMessageBox::No); - if (responseClick == QMessageBox::No) { - QMessageBox::critical( this, "Send transaction cancelled", - "The send transaction has been cancelled.\n\nPlease double-check the transction details thoroughly before retrying your send transaction." ); - return; - } - strAmount = tmpStrAmount; - ui->amountLineEdit->setText(QString::fromStdString(strAmount)); - } - } - - // use strToInt64 function to get the amount, using divisibility of the property - int64_t sendAmount = StrToInt64(strAmount, divisible); - if (0>=sendAmount) { - QMessageBox::critical( this, "Unable to send transaction", - "The amount entered is not valid.\n\nPlease double-check the transction details thoroughly before retrying your send transaction." ); - return; - } - - // check if sending address has enough funds - int64_t balanceAvailable = getUserAvailableMPbalance(fromAddress.ToString(), propertyId); //getMPbalance(fromAddress.ToString(), propertyId, MONEY); - if (sendAmount>balanceAvailable) { - QMessageBox::critical( this, "Unable to send transaction", - "The selected sending address does not have a sufficient balance to cover the amount entered.\n\nPlease double-check the transction details thoroughly before retrying your send transaction." ); - return; - } - - // check if wallet is still syncing, as this will currently cause a lockup if we try to send - compare our chain to peers to see if we're up to date - // Bitcoin Core devs have removed GetNumBlocksOfPeers, switching to a time based best guess scenario - uint32_t intBlockDate = GetLatestBlockTime(); // uint32, not using time_t for portability - QDateTime currentDate = QDateTime::currentDateTime(); - int secs = QDateTime::fromTime_t(intBlockDate).secsTo(currentDate); - if(secs > 90*60) { - QMessageBox::critical( this, "Unable to send transaction", - "The client is still synchronizing. Sending transactions can currently be performed only when the client has completed synchronizing." ); - return; - } - - // validation checks all look ok, let's throw up a confirmation dialog - string strMsgText = "You are about to send the following transaction, please check the details thoroughly:\n\n"; - string propDetails = getPropertyName(propertyId).c_str(); - string spNum = strprintf("%d", propertyId); - propDetails += " (#" + spNum + ")"; - strMsgText += "From: " + fromAddress.ToString() + "\nTo: " + refAddress.ToString() + "\nProperty: " + propDetails + "\nAmount that will be sent: "; - if (divisible) { strMsgText += FormatDivisibleMP(sendAmount); } else { strMsgText += FormatIndivisibleMP(sendAmount); } - strMsgText += "\n\nAre you sure you wish to send this transaction?"; - QString msgText = QString::fromStdString(strMsgText); - QMessageBox::StandardButton responseClick; - responseClick = QMessageBox::question(this, "Confirm send transaction", msgText, QMessageBox::Yes|QMessageBox::No); - if (responseClick == QMessageBox::No) { - QMessageBox::critical( this, "Send transaction cancelled", - "The send transaction has been cancelled.\n\nPlease double-check the transction details thoroughly before retrying your send transaction." ); - return; - } - - // unlock the wallet - WalletModel::UnlockContext ctx(walletModel->requestUnlock()); - if(!ctx.isValid()) { - QMessageBox::critical( this, "Send transaction failed", - "The send transaction has been cancelled.\n\nThe wallet unlock process must be completed to send a transaction." ); - return; // unlock wallet was cancelled/failed - } - - // create a payload for the transaction - std::vector payload = CreatePayload_SimpleSend(propertyId, sendAmount); - - // request the wallet build the transaction (and if needed commit it) - note UI does not support added reference amounts currently - uint256 txid; - std::string rawHex; - int result = WalletTxBuilder(fromAddress.ToString(), refAddress.ToString(), "", 0, payload, txid, rawHex, autoCommit); - - // check error and return the txid (or raw hex depending on autocommit) - if (result != 0) { - QMessageBox::critical( this, "Send transaction failed", - "The send transaction has failed.\n\nThe error code was: " + QString::number(result) + "\nThe error message was:\n" + QString::fromStdString(error_str(result))); - return; - } else { - if (!autoCommit) { - PopulateSimpleDialog(rawHex, "Raw Hex (auto commit is disabled)", "Raw transaction hex"); - } else { - PendingAdd(txid, fromAddress.ToString(), ELYSIUM_TYPE_SIMPLE_SEND, propertyId, sendAmount); - PopulateTXSentDialog(txid.GetHex()); - } - } - clearFields(); -} - -void SendMPDialog::sendFromComboBoxChanged(int idx) -{ - updateFrom(); -} - -void SendMPDialog::propertyComboBoxChanged(int idx) -{ - updateProperty(); - updateFrom(); -} - -void SendMPDialog::clearButtonClicked() -{ - clearFields(); -} - -void SendMPDialog::sendButtonClicked() -{ - sendMPTransaction(); -} - -void SendMPDialog::balancesUpdated() -{ - updatePropSelector(); - updateProperty(); - updateFrom(); -} diff --git a/src/qt/sendmpdialog.h b/src/qt/sendmpdialog.h deleted file mode 100644 index 01693cae01..0000000000 --- a/src/qt/sendmpdialog.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef SENDMPDIALOG_H -#define SENDMPDIALOG_H - -#include "walletmodel.h" - -#include -#include - -class ClientModel; - -QT_BEGIN_NAMESPACE -class QWidget; -QT_END_NAMESPACE - -namespace Ui { - class SendMPDialog; -} - -/** Dialog for sending Master Protocol tokens */ -class SendMPDialog : public QDialog -{ - Q_OBJECT - -public: - explicit SendMPDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); - ~SendMPDialog(); - - void setClientModel(ClientModel *model); - void setWalletModel(WalletModel *model); - - void clearFields(); - void sendMPTransaction(); - void updateProperty(); - void updatePropSelector(); - -public Q_SLOTS: - void propertyComboBoxChanged(int idx); - void sendFromComboBoxChanged(int idx); - void clearButtonClicked(); - void sendButtonClicked(); - void balancesUpdated(); - void updateFrom(); - -private: - Ui::SendMPDialog *ui; - ClientModel *clientModel; - WalletModel *walletModel; - const PlatformStyle *platformStyle; - -Q_SIGNALS: - // Fired when a message should be reported to the user - void message(const QString &title, const QString &message, unsigned int style); -}; - -#endif // SENDMPDIALOG_H diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 48b7c44362..8f0276f063 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -20,9 +20,6 @@ #include "wallet/wallet.h" #endif -#include "elysium/version.h" -#include "elysium/utilsbitcoin.h" - #include #include #include diff --git a/src/qt/tradehistorydialog.cpp b/src/qt/tradehistorydialog.cpp deleted file mode 100755 index b4b36da867..0000000000 --- a/src/qt/tradehistorydialog.cpp +++ /dev/null @@ -1,571 +0,0 @@ -// Copyright (c) 2011-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "tradehistorydialog.h" -#include "ui_tradehistorydialog.h" - -#include "elysium_qtutils.h" - -#include "guiutil.h" -#include "ui_interface.h" -#include "walletmodel.h" -#include "clientmodel.h" -#include "platformstyle.h" - -#include "elysium/fetchwallettx.h" -#include "elysium/mdex.h" -#include "elysium/elysium.h" -#include "elysium/pending.h" -#include "elysium/rpc.h" -#include "elysium/rpctxobject.h" -#include "elysium/sp.h" -#include "elysium/tx.h" -#include "elysium/utilsbitcoin.h" -#include "elysium/walletcache.h" -#include "elysium/wallettxs.h" - -#include "amount.h" -#include "init.h" -#include "validation.h" -#include "primitives/transaction.h" -#include "sync.h" -#include "txdb.h" -#include "uint256.h" -#include "wallet/wallet.h" - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using std::ostringstream; -using std::string; - -using namespace elysium; - -bool hideInactiveTrades = false; - -TradeHistoryDialog::TradeHistoryDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::tradeHistoryDialog), - clientModel(0), - walletModel(0) -{ - // Setup the UI - ui->setupUi(this); - ui->tradeHistoryTable->setColumnCount(8); - // Note there are two hidden fields in tradeHistoryTable: 0=txid, 1=lastUpdateBlock - ui->tradeHistoryTable->setHorizontalHeaderItem(2, new QTableWidgetItem(" ")); - ui->tradeHistoryTable->setHorizontalHeaderItem(3, new QTableWidgetItem("Date")); - ui->tradeHistoryTable->setHorizontalHeaderItem(4, new QTableWidgetItem("Status")); - ui->tradeHistoryTable->setHorizontalHeaderItem(5, new QTableWidgetItem("Trade Details")); - ui->tradeHistoryTable->setHorizontalHeaderItem(6, new QTableWidgetItem("Sold")); - ui->tradeHistoryTable->setHorizontalHeaderItem(7, new QTableWidgetItem("Received")); - #if QT_VERSION < 0x050000 - ui->tradeHistoryTable->horizontalHeader()->setResizeMode(2, QHeaderView::Fixed); - ui->tradeHistoryTable->horizontalHeader()->setResizeMode(3, QHeaderView::Interactive); - ui->tradeHistoryTable->horizontalHeader()->setResizeMode(4, QHeaderView::Interactive); - ui->tradeHistoryTable->horizontalHeader()->setResizeMode(5, QHeaderView::Interactive); - ui->tradeHistoryTable->horizontalHeader()->setResizeMode(6, QHeaderView::Interactive); - ui->tradeHistoryTable->horizontalHeader()->setResizeMode(7, QHeaderView::Interactive); - #else - ui->tradeHistoryTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed); - ui->tradeHistoryTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Interactive); - ui->tradeHistoryTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Interactive); - ui->tradeHistoryTable->horizontalHeader()->setSectionResizeMode(5, QHeaderView::Interactive); - ui->tradeHistoryTable->horizontalHeader()->setSectionResizeMode(6, QHeaderView::Interactive); - ui->tradeHistoryTable->horizontalHeader()->setSectionResizeMode(7, QHeaderView::Interactive); - #endif - ui->tradeHistoryTable->setAlternatingRowColors(true); - ui->tradeHistoryTable->verticalHeader()->setVisible(false); - ui->tradeHistoryTable->setSelectionBehavior(QAbstractItemView::SelectRows); - ui->tradeHistoryTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->tradeHistoryTable->setSelectionMode(QAbstractItemView::SingleSelection); - ui->tradeHistoryTable->setContextMenuPolicy(Qt::CustomContextMenu); - ui->tradeHistoryTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->tradeHistoryTable->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - UpdateTradeHistoryTable(); // make sure we're populated before attempting to resize to contents - ui->tradeHistoryTable->setColumnHidden(0, true); - ui->tradeHistoryTable->setColumnHidden(1, true); - ui->tradeHistoryTable->setColumnWidth(2, 23); - ui->tradeHistoryTable->resizeColumnToContents(3); - ui->tradeHistoryTable->resizeColumnToContents(4); - ui->tradeHistoryTable->resizeColumnToContents(6); - ui->tradeHistoryTable->resizeColumnToContents(7); - ui->tradeHistoryTable->setSortingEnabled(true); - ui->tradeHistoryTable->horizontalHeader()->setSortIndicator(3, Qt::DescendingOrder); - - QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); - QAction *showDetailsAction = new QAction(tr("Show trade details"), this); - contextMenu = new QMenu(); - contextMenu->addAction(copyTxIDAction); - contextMenu->addAction(showDetailsAction); - connect(ui->tradeHistoryTable, &QWidget::customContextMenuRequested, this, &TradeHistoryDialog::contextualMenu); - connect(ui->tradeHistoryTable, &QAbstractItemView::doubleClicked, this, &TradeHistoryDialog::showDetails); - connect(ui->hideInactiveTrades, &QCheckBox::stateChanged, this, &TradeHistoryDialog::RepopulateTradeHistoryTable); - connect(copyTxIDAction, &QAction::triggered, this, &TradeHistoryDialog::copyTxID); - connect(showDetailsAction, &QAction::triggered, this, &TradeHistoryDialog::showDetails); -} - -TradeHistoryDialog::~TradeHistoryDialog() -{ - delete ui; -} - -void TradeHistoryDialog::ReinitTradeHistoryTable() -{ - ui->tradeHistoryTable->setRowCount(0); - tradeHistoryMap.clear(); - UpdateTradeHistoryTable(); -} - -// Repopulate tradeHistoryTable (eg in the case that we are hiding or revealing trades) -void TradeHistoryDialog::RepopulateTradeHistoryTable(int hide) -{ - ui->tradeHistoryTable->setRowCount(0); - if (hide) { - hideInactiveTrades = true; - } else { - hideInactiveTrades = false; - } - UpdateTradeHistoryTable(true); -} - -// The main function to update the UI tradeHistoryTable -void TradeHistoryDialog::UpdateTradeHistoryTable(bool forceUpdate) -{ - // Populate tradeHistoryMap - int newTXCount = PopulateTradeHistoryMap(); - - // Process any new transactions that were added to the map - if (forceUpdate || newTXCount > 0) { - ui->tradeHistoryTable->setSortingEnabled(false); // disable sorting while we update the table - QAbstractItemModel* tradeHistoryAbstractModel = ui->tradeHistoryTable->model(); - int chainHeight = GetHeight(); - - // Loop through tradeHistoryMap and search tradeHistoryTable for the transaction, adding it if not already there - for (TradeHistoryMap::iterator it = tradeHistoryMap.begin(); it != tradeHistoryMap.end(); ++it) { - uint256 txid = it->first; - TradeHistoryObject objTH = it->second; - - // ignore this trade if it's not active and we've elected to hide inactive trades - if (hideInactiveTrades && (objTH.status == "Cancelled" || objTH.status == "Filled" || objTH.status == "Part Cancel" || !objTH.valid)) continue; - - // search tradeHistoryTable for an existing row & skip if already there - QSortFilterProxyModel tradeHistoryProxy; - tradeHistoryProxy.setSourceModel(tradeHistoryAbstractModel); - tradeHistoryProxy.setFilterKeyColumn(0); - tradeHistoryProxy.setFilterFixedString(QString::fromStdString(txid.GetHex())); - QModelIndex rowIndex = tradeHistoryProxy.mapToSource(tradeHistoryProxy.index(0,0)); - if (rowIndex.isValid()) continue; - - // new entry is required, append a new row (sorting will take care of ordering) - int newRow = ui->tradeHistoryTable->rowCount(); - ui->tradeHistoryTable->insertRow(newRow); - - // Create the cells to be added to the new row and setup their formatting - QTableWidgetItem *dateCell = new QTableWidgetItem; - QDateTime txTime; - if (objTH.blockHeight > 0) { - LOCK(cs_main); - CBlockIndex* pBlkIdx = chainActive[objTH.blockHeight]; - if (NULL != pBlkIdx) txTime.setTime_t(pBlkIdx->GetBlockTime()); - dateCell->setData(Qt::DisplayRole, txTime); - } else { - dateCell->setData(Qt::DisplayRole, QString::fromStdString("Unconfirmed")); - } - QTableWidgetItem *lastUpdateBlockCell = new QTableWidgetItem(QString::fromStdString(FormatIndivisibleMP(chainHeight))); - QTableWidgetItem *statusCell = new QTableWidgetItem(QString::fromStdString(objTH.status)); - QTableWidgetItem *infoCell = new QTableWidgetItem(QString::fromStdString(objTH.info)); - QTableWidgetItem *amountOutCell = new QTableWidgetItem(QString::fromStdString(objTH.amountOut)); - QTableWidgetItem *amountInCell = new QTableWidgetItem(QString::fromStdString(objTH.amountIn)); - QTableWidgetItem *txidCell = new QTableWidgetItem(QString::fromStdString(txid.GetHex())); - QTableWidgetItem *iconCell = new QTableWidgetItem; - QIcon ic = QIcon(":/icons/elysium_meta_pending"); - if (objTH.status == "Cancelled") ic =QIcon(":/icons/elysium_meta_cancelled"); - if (objTH.status == "Part Cancel") ic = QIcon(":/icons/elysium_meta_partcancelled"); - if (objTH.status == "Filled") ic = QIcon(":/icons/elysium_meta_filled"); - if (objTH.status == "Open") ic = QIcon(":/icons/elysium_meta_open"); - if (objTH.status == "Part Filled") ic = QIcon(":/icons/elysium_meta_partfilled"); - if (!objTH.valid) { - ic = QIcon(":/icons/transaction_conflicted"); - objTH.status = "Invalid"; - } -// ic = platformStyle->SingleColorIcon(ic); - iconCell->setIcon(ic); - amountOutCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - amountOutCell->setForeground(QColor("#EE0000")); - amountInCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - amountInCell->setForeground(QColor("#00AA00")); - if (objTH.status == "Cancelled" || objTH.status == "Filled" || objTH.status == "Part Cancel" || !objTH.valid) { - // dull the colors for non-active trades - dateCell->setForeground(QColor("#707070")); - statusCell->setForeground(QColor("#707070")); - infoCell->setForeground(QColor("#707070")); - amountOutCell->setForeground(QColor("#993333")); - amountInCell->setForeground(QColor("#006600")); - } - if(objTH.amountIn.substr(0,2) == "0 " || objTH.amountIn == "---" ) amountInCell->setForeground(QColor("#000000")); - if(objTH.amountOut.substr(0,2) == "0 " || objTH.amountOut == "---" ) amountOutCell->setForeground(QColor("#000000")); - - // Set the cells in the new row accordingly - ui->tradeHistoryTable->setItem(newRow, 0, txidCell); - ui->tradeHistoryTable->setItem(newRow, 1, lastUpdateBlockCell); - ui->tradeHistoryTable->setItem(newRow, 2, iconCell); - ui->tradeHistoryTable->setItem(newRow, 3, dateCell); - ui->tradeHistoryTable->setItem(newRow, 4, statusCell); - ui->tradeHistoryTable->setItem(newRow, 5, infoCell); - ui->tradeHistoryTable->setItem(newRow, 6, amountOutCell); - ui->tradeHistoryTable->setItem(newRow, 7, amountInCell); - } - ui->tradeHistoryTable->setSortingEnabled(true); // re-enable sorting - } - - // Update any existing rows that may have changed data - UpdateData(); -} - -// Used to cache trades so we don't need to reparse all our transactions on every update -int TradeHistoryDialog::PopulateTradeHistoryMap() -{ - // TODO: locks may not be needed here -- looks like wallet lock can be removed - if (NULL == pwalletMain) return -1; - TRY_LOCK(cs_main,lckMain); - if (!lckMain) return -1; - TRY_LOCK(pwalletMain->cs_wallet, lckWallet); - if (!lckWallet) return -1; - - int64_t nProcessed = 0; // number of new entries, forms return code - - // ### START PENDING TRANSACTIONS PROCESSING ### - { - LOCK(cs_main); - - for (PendingMap::iterator it = my_pending.begin(); it != my_pending.end(); ++it) { - uint256 txid = it->first; - - // check historyMap, if this tx exists don't waste resources doing anymore work on it - TradeHistoryMap::iterator hIter = tradeHistoryMap.find(txid); - if (hIter != tradeHistoryMap.end()) continue; - - // grab pending object, extract details and skip if not a metadex trade - CMPPending *p_pending = &(it->second); - if (p_pending->type != ELYSIUM_TYPE_METADEX_TRADE) continue; - uint32_t propertyId = p_pending->prop; - int64_t amount = p_pending->amount; - - // create a TradeHistoryObject and populate it - TradeHistoryObject objTH; - objTH.blockHeight = 0; - objTH.valid = true; // all pending transactions are assumed to be valid - objTH.propertyIdForSale = propertyId; - objTH.propertyIdDesired = 0; // unknown at this stage & not needed for pending - objTH.amountForSale = amount; - objTH.status = "Pending"; - objTH.amountIn = "---"; - objTH.amountOut = "---"; - objTH.info = "Sell "; - if (isPropertyDivisible(propertyId)) { - objTH.info += FormatDivisibleShortMP(amount) + getTokenLabel(propertyId) + " (awaiting confirmation)"; - } else { - objTH.info += FormatIndivisibleMP(amount) + getTokenLabel(propertyId) + " (awaiting confirmation)"; - } - - // add the new TradeHistoryObject to the map - tradeHistoryMap.insert(std::make_pair(txid, objTH)); - nProcessed += 1; - } - } - // ### END PENDING TRANSACTIONS PROCESSING ### - - // ### START WALLET TRANSACTIONS PROCESSING ### - // obtain a sorted list of Elysium layer wallet transactions (including STO receipts and pending) - default last 65535 - std::map walletTransactions = FetchWalletElysiumTransactions(GetArg("-elysiumuiwalletscope", 65535L)); - - // reverse iterate over (now ordered) transactions and populate history map for each one - for (std::map::reverse_iterator it = walletTransactions.rbegin(); it != walletTransactions.rend(); it++) { - uint256 hash = it->second; - - // use levelDB to perform a fast check on whether it's a Firo or Elysium tx and whether it's a trade - std::string tempStrValue; - { - LOCK(cs_main); - if (!p_txlistdb->getTX(hash, tempStrValue)) continue; - } - std::vector vstr; - boost::split(vstr, tempStrValue, boost::is_any_of(":"), boost::token_compress_on); - if (vstr.size() > 2) { - if (atoi(vstr[2]) != ELYSIUM_TYPE_METADEX_TRADE) continue; - } - - // check historyMap, if this tx exists don't waste resources doing anymore work on it - TradeHistoryMap::iterator hIter = tradeHistoryMap.find(hash); - if (hIter != tradeHistoryMap.end()) { - // the tx is in historyMap, check if it has a blockheight of 0 (means a pending has confirmed & we should delete pending tx and add it again via parsing) - TradeHistoryObject *objTH = &(hIter->second); - if (objTH->blockHeight != 0) { - continue; - } else { - tradeHistoryMap.erase(hIter); - ui->tradeHistoryTable->setSortingEnabled(false); // disable sorting temporarily while we update the table (leaving enabled gives unexpected results) - QAbstractItemModel* tradeHistoryAbstractModel = ui->tradeHistoryTable->model(); - QSortFilterProxyModel tradeHistoryProxy; - tradeHistoryProxy.setSourceModel(tradeHistoryAbstractModel); - tradeHistoryProxy.setFilterKeyColumn(0); - tradeHistoryProxy.setFilterFixedString(QString::fromStdString(hash.GetHex())); - QModelIndex rowIndex = tradeHistoryProxy.mapToSource(tradeHistoryProxy.index(0,0)); // map to the row in the actual table - if(rowIndex.isValid()) ui->tradeHistoryTable->removeRow(rowIndex.row()); // delete the pending tx row, it'll be readded as a proper confirmed transaction - ui->tradeHistoryTable->setSortingEnabled(true); // re-enable sorting - } - } - - // tx not in historyMap, retrieve the transaction object - CTransactionRef wtx; - uint256 blockHash; - if (!GetTransaction(hash, wtx, Params().GetConsensus(), blockHash, true)) continue; - if (blockHash.IsNull() || NULL == GetBlockIndex(blockHash)) continue; - CBlockIndex* pBlockIndex = GetBlockIndex(blockHash); - if (NULL == pBlockIndex) continue; - int blockHeight = pBlockIndex->nHeight; - - // setup some variables - CMPTransaction mp_obj; - std::string statusText; - uint32_t propertyIdForSale = 0; - uint32_t propertyIdDesired = 0; - int64_t amountForSale = 0; - int64_t amountDesired = 0; - bool divisibleForSale = false; - bool divisibleDesired = false; - UniValue tradeArray(UniValue::VARR); - int64_t totalReceived = 0; - int64_t totalSold = 0; - bool orderOpen = false; - bool valid = false; - - // parse the transaction - if (0 != ParseTransaction(*wtx, blockHeight, 0, mp_obj)) continue; - if (mp_obj.interpret_Transaction()) { - valid = getValidMPTX(hash); - propertyIdForSale = mp_obj.getProperty(); - amountForSale = mp_obj.getAmount(); - divisibleForSale = isPropertyDivisible(propertyIdForSale); - CMPMetaDEx temp_metadexoffer(mp_obj); - propertyIdDesired = temp_metadexoffer.getDesProperty(); - divisibleDesired = isPropertyDivisible(propertyIdDesired); - amountDesired = temp_metadexoffer.getAmountDesired(); - { - LOCK(cs_main); - t_tradelistdb->getMatchingTrades(hash, propertyIdForSale, tradeArray, totalSold, totalReceived); - orderOpen = MetaDEx_isOpen(hash, propertyIdForSale); - } - } - - // work out status - bool partialFilled = false; - bool filled = false; - statusText = "Unknown"; - if (totalSold > 0) partialFilled = true; - if (totalSold >= amountForSale) filled = true; - if (!orderOpen && !partialFilled) statusText = "Cancelled"; - if (!orderOpen && partialFilled) statusText = "Part Cancel"; - if (!orderOpen && filled) statusText = "Filled"; - if (orderOpen && !partialFilled) statusText = "Open"; - if (orderOpen && partialFilled) statusText = "Part Filled"; - if (!valid) statusText = "Invalid"; - - // prepare display values - std::string displayText = "Sell "; - if (divisibleForSale) { displayText += FormatDivisibleShortMP(amountForSale); } else { displayText += FormatIndivisibleMP(amountForSale); } - displayText += getTokenLabel(propertyIdForSale) + " for "; - if (divisibleDesired) { displayText += FormatDivisibleShortMP(amountDesired); } else { displayText += FormatIndivisibleMP(amountDesired); } - displayText += getTokenLabel(propertyIdDesired); - std::string displayIn = ""; - std::string displayOut = "-"; - if(divisibleDesired) { displayIn += FormatDivisibleShortMP(totalReceived); } else { displayIn += FormatIndivisibleMP(totalReceived); } - if(divisibleForSale) { displayOut += FormatDivisibleShortMP(totalSold); } else { displayOut += FormatIndivisibleMP(totalSold); } - if(totalReceived == 0) displayIn = "0"; - if(totalSold == 0) displayOut = "0"; - displayIn += getTokenLabel(propertyIdDesired); - displayOut += getTokenLabel(propertyIdForSale); - - // create a TradeHistoryObject and populate it - TradeHistoryObject objTH; - objTH.blockHeight = blockHeight; - objTH.valid = valid; - objTH.propertyIdForSale = propertyIdForSale; - objTH.propertyIdDesired = propertyIdDesired; - objTH.amountForSale = amountForSale; - objTH.status = statusText; - objTH.amountIn = displayIn; - objTH.amountOut = displayOut; - objTH.info = displayText; - - // add the new TradeHistoryObject to the map - tradeHistoryMap.insert(std::make_pair(hash, objTH)); - nProcessed += 1; - } - // ### END WALLET TRANSACTIONS PROCESSING ### - - return nProcessed; -} - -// Each time an update is called it's feasible that the status and amounts traded for open trades may have changed -// This function will loop through each of the rows in tradeHistoryTable and check if the details need updating -void TradeHistoryDialog::UpdateData() -{ - int chainHeight = GetHeight(); - int rowCount = ui->tradeHistoryTable->rowCount(); - ui->tradeHistoryTable->setSortingEnabled(false); // disable sorting while we update the table - for (int row = 0; row < rowCount; row++) { - // check if we need to refresh the details for this row - int lastUpdateBlock = ui->tradeHistoryTable->item(row,1)->text().toInt(); - uint256 txid; - txid.SetHex(ui->tradeHistoryTable->item(row,0)->text().toStdString()); - TradeHistoryMap::iterator hIter = tradeHistoryMap.find(txid); - if (hIter == tradeHistoryMap.end()) { - PrintToLog("UI Error: Transaction %s appears in tradeHistoryTable but cannot be found in tradeHistoryMap.\n", txid.GetHex()); - continue; - } - TradeHistoryObject *tmpObjTH = &(hIter->second); - if (tmpObjTH->status == "Filled" || tmpObjTH->status == "Cancelled" || tmpObjTH->status == "Part Cancel" || tmpObjTH->status == "Invalid") continue; // once a trade hits this status the details should never change - if (tmpObjTH->blockHeight == 0) continue; // do not attempt to refresh details for a trade that's still pending - if (lastUpdateBlock == chainHeight) continue; // no new blocks since last update, don't waste compute looking for updates - - // at this point we have an active trade and there have been new block(s) since the last update - refresh status and amounts - uint32_t propertyIdForSale = tmpObjTH->propertyIdForSale; - uint32_t propertyIdDesired = tmpObjTH->propertyIdDesired; - int64_t amountForSale = tmpObjTH->amountForSale; - UniValue tradeArray(UniValue::VARR); - int64_t totalReceived = 0; - int64_t totalSold = 0; - bool orderOpen = false; - { - LOCK(cs_main); - t_tradelistdb->getMatchingTrades(txid, propertyIdForSale, tradeArray, totalSold, totalReceived); - orderOpen = MetaDEx_isOpen(txid, propertyIdForSale); - } - // work out new status & icon - bool partialFilled = false; - bool filled = false; - if (totalSold > 0) partialFilled = true; - if (totalSold >= amountForSale) filled = true; - std::string statusText = "Unknown"; - QIcon ic = QIcon(":/icons/transaction_0"); - if (!orderOpen && !partialFilled) { statusText = "Cancelled"; ic = QIcon(":/icons/meta_cancelled"); } - if (!orderOpen && partialFilled) { statusText = "Part Cancel"; ic = QIcon(":/icons/meta_partialclosed"); } - if (!orderOpen && filled) { statusText = "Filled"; ic = QIcon(":/icons/meta_filled"); } - if (orderOpen && !partialFilled) { statusText = "Open"; ic = QIcon(":/icons/meta_open"); } - if (orderOpen && partialFilled) { statusText = "Part Filled"; ic = QIcon(":/icons/meta_partial"); } - if (!tmpObjTH->valid) { statusText = "Invalid"; ic = QIcon(":/icons/transaction_invalid"); } - - // format new amounts - std::string displayIn = ""; - std::string displayOut = "-"; - if (isPropertyDivisible(propertyIdDesired)) { displayIn += FormatDivisibleShortMP(totalReceived); } else { displayIn += FormatIndivisibleMP(totalReceived); } - if (isPropertyDivisible(propertyIdForSale)) { displayOut += FormatDivisibleShortMP(totalSold); } else { displayOut += FormatIndivisibleMP(totalSold); } - if (totalReceived == 0) displayIn = "0"; - if (totalSold == 0) displayOut = "0"; - displayIn += getTokenLabel(propertyIdDesired); - displayOut += getTokenLabel(propertyIdForSale); - - // create and format replacement cells - QTableWidgetItem *lastUpdateBlockCell = new QTableWidgetItem(QString::fromStdString(FormatIndivisibleMP(chainHeight))); - QTableWidgetItem *statusCell = new QTableWidgetItem(QString::fromStdString(statusText)); - QTableWidgetItem *amountOutCell = new QTableWidgetItem(QString::fromStdString(displayOut)); - QTableWidgetItem *amountInCell = new QTableWidgetItem(QString::fromStdString(displayIn)); - QTableWidgetItem *iconCell = new QTableWidgetItem; - QTableWidgetItem *dateCell = new QTableWidgetItem; - dateCell->setData(Qt::DisplayRole, ui->tradeHistoryTable->item(row, 3)->data(Qt::DisplayRole)); // values don't change so can be copied - QTableWidgetItem *infoCell = new QTableWidgetItem(ui->tradeHistoryTable->item(row, 5)->text()); // as above - iconCell->setIcon(ic); - amountOutCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - amountOutCell->setForeground(QColor("#EE0000")); - amountInCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - amountInCell->setForeground(QColor("#00AA00")); - if (statusText == "Cancelled" || statusText == "Filled" || statusText == "Part Cancel" || statusText == "Invalid") { - // dull the colors for non-active trades - dateCell->setForeground(QColor("#707070")); - statusCell->setForeground(QColor("#707070")); - infoCell->setForeground(QColor("#707070")); - amountOutCell->setForeground(QColor("#993333")); - amountInCell->setForeground(QColor("#006600")); - } - if(displayIn.substr(0,2) == "0 ") amountInCell->setForeground(QColor("#000000")); - if(displayOut.substr(0,2) == "0 ") amountOutCell->setForeground(QColor("#000000")); - // replace cells in row accordingly - ui->tradeHistoryTable->setItem(row, 1, lastUpdateBlockCell); - ui->tradeHistoryTable->setItem(row, 2, iconCell); - ui->tradeHistoryTable->setItem(row, 3, dateCell); - ui->tradeHistoryTable->setItem(row, 4, statusCell); - ui->tradeHistoryTable->setItem(row, 5, infoCell); - ui->tradeHistoryTable->setItem(row, 6, amountOutCell); - ui->tradeHistoryTable->setItem(row, 7, amountInCell); - } - ui->tradeHistoryTable->setSortingEnabled(true); // re-enable sorting -} - -void TradeHistoryDialog::setWalletModel(WalletModel *model) -{ - this->walletModel = model; - if (model != NULL) { } // do nothing, signals from walletModel no longer needed -} - -void TradeHistoryDialog::setClientModel(ClientModel *model) -{ - this->clientModel = model; - if (model != NULL) { - connect(model, SIGNAL(refreshOmniBalance()), this, SLOT(UpdateTradeHistoryTable())); - connect(model, SIGNAL(reinitOmniState()), this, SLOT(ReinitTradeHistoryTable())); - } -} - -void TradeHistoryDialog::contextualMenu(const QPoint &point) -{ - QModelIndex index = ui->tradeHistoryTable->indexAt(point); - if(index.isValid()) contextMenu->exec(QCursor::pos()); -} - -void TradeHistoryDialog::copyTxID() -{ - GUIUtil::setClipboard(ui->tradeHistoryTable->item(ui->tradeHistoryTable->currentRow(),0)->text()); -} - -/* Opens a dialog containing the details of the selected trade and any associated matches - */ -void TradeHistoryDialog::showDetails() -{ - UniValue txobj(UniValue::VOBJ);; - uint256 txid; - txid.SetHex(ui->tradeHistoryTable->item(ui->tradeHistoryTable->currentRow(),0)->text().toStdString()); - std::string strTXText; - - if (!txid.IsNull()) { - // grab extended trade details via the RPC populator - int rc = populateRPCTransactionObject(txid, txobj, "", true); - if (rc >= 0) strTXText = txobj.write(true); - } - - if (!strTXText.empty()) { - PopulateSimpleDialog(strTXText, "Trade Information", "Trade Information"); - } -} diff --git a/src/qt/tradehistorydialog.h b/src/qt/tradehistorydialog.h deleted file mode 100755 index 9b3871c74d..0000000000 --- a/src/qt/tradehistorydialog.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef TRADEHISTORYDIALOG_H -#define TRADEHISTORYDIALOG_H - -#include "guiutil.h" -#include "uint256.h" - -#include - -class WalletModel; -class ClientModel; - -QT_BEGIN_NAMESPACE -class QMenu; -class QPoint; -class QResizeEvent; -class QString; -class QWidget; -QT_END_NAMESPACE - -namespace Ui { - class tradeHistoryDialog; -} - -class TradeHistoryObject -{ -public: - TradeHistoryObject() - : blockHeight(-1), valid(false) {}; - int blockHeight; // block transaction was mined in - bool valid; // whether the transaction is valid from an Omni perspective - uint32_t propertyIdForSale; // the property being sold - uint32_t propertyIdDesired; // the property being requested - int64_t amountForSale; // the amount being sold - std::string status; // string containing status of trade - std::string info; // string containing human readable description of trade - std::string amountOut; // string containing formatted amount out - std::string amountIn; // string containing formatted amount in -}; - -typedef std::map TradeHistoryMap; - -/** Dialog for looking up Master Protocol tokens */ -class TradeHistoryDialog : public QDialog -{ - Q_OBJECT - -public: - explicit TradeHistoryDialog(QWidget *parent = 0); - ~TradeHistoryDialog(); - void setWalletModel(WalletModel *model); - void setClientModel(ClientModel *model); - -private: - Ui::tradeHistoryDialog *ui; - ClientModel *clientModel; - WalletModel *walletModel; - QMenu *contextMenu; - TradeHistoryMap tradeHistoryMap; - -public Q_SLOTS: - void contextualMenu(const QPoint &point); - void showDetails(); - void copyTxID(); - -private Q_SLOTS: - int PopulateTradeHistoryMap(); - void UpdateData(); - void UpdateTradeHistoryTable(bool forceUpdate = false); - void RepopulateTradeHistoryTable(int hide); - void ReinitTradeHistoryTable(); - -Q_SIGNALS: - // Fired when a message should be reported to the user - void message(const QString &title, const QString &message, unsigned int style); -}; - -#endif // TRADEHISTORYDIALOG_H diff --git a/src/qt/txhistorydialog.cpp b/src/qt/txhistorydialog.cpp deleted file mode 100644 index b0d945e357..0000000000 --- a/src/qt/txhistorydialog.cpp +++ /dev/null @@ -1,553 +0,0 @@ -// Copyright (c) 2011-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "txhistorydialog.h" -#include "ui_txhistorydialog.h" - -#include "elysium_qtutils.h" - -#include "clientmodel.h" -#include "guiutil.h" -#include "walletmodel.h" -#include "platformstyle.h" - -#include "elysium/fetchwallettx.h" -#include "elysium/elysium.h" -#include "elysium/pending.h" -#include "elysium/rpc.h" -#include "elysium/rpctxobject.h" -#include "elysium/sp.h" -#include "elysium/tx.h" -#include "elysium/utilsbitcoin.h" -#include "elysium/walletcache.h" -#include "elysium/wallettxs.h" - -#include "init.h" -#include "validation.h" -#include "primitives/transaction.h" -#include "sync.h" -#include "txdb.h" -#include "uint256.h" -#include "wallet/wallet.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using std::string; -using namespace elysium; - -TXHistoryDialog::TXHistoryDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::txHistoryDialog), - clientModel(0), - walletModel(0) -{ - ui->setupUi(this); - // setup - ui->txHistoryTable->setColumnCount(7); - ui->txHistoryTable->setHorizontalHeaderItem(2, new QTableWidgetItem(" ")); - ui->txHistoryTable->setHorizontalHeaderItem(3, new QTableWidgetItem("Date")); - ui->txHistoryTable->setHorizontalHeaderItem(4, new QTableWidgetItem("Type")); - ui->txHistoryTable->setHorizontalHeaderItem(5, new QTableWidgetItem("Address")); - ui->txHistoryTable->setHorizontalHeaderItem(6, new QTableWidgetItem("Amount")); - - #if QT_VERSION < 0x050000 - ui->txHistoryTable->horizontalHeader()->setResizeMode(2, QHeaderView::Fixed); - ui->txHistoryTable->horizontalHeader()->setResizeMode(3, QHeaderView::Interactive); - ui->txHistoryTable->horizontalHeader()->setResizeMode(4, QHeaderView::Interactive); - ui->txHistoryTable->horizontalHeader()->setResizeMode(5, QHeaderView::Interactive); - ui->txHistoryTable->horizontalHeader()->setResizeMode(6, QHeaderView::Interactive); - #else - ui->txHistoryTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed); - ui->txHistoryTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Interactive); - ui->txHistoryTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Interactive); - ui->txHistoryTable->horizontalHeader()->setSectionResizeMode(5, QHeaderView::Interactive); - ui->txHistoryTable->horizontalHeader()->setSectionResizeMode(6, QHeaderView::Interactive); - #endif - ui->txHistoryTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->txHistoryTable->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - ui->txHistoryTable->verticalHeader()->setVisible(false); - ui->txHistoryTable->setSelectionBehavior(QAbstractItemView::SelectRows); - ui->txHistoryTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->txHistoryTable->setSelectionMode(QAbstractItemView::SingleSelection); - ui->txHistoryTable->setTabKeyNavigation(false); - ui->txHistoryTable->setContextMenuPolicy(Qt::CustomContextMenu); - // set alternating row colors via styling instead of manually - ui->txHistoryTable->setAlternatingRowColors(true); - // Actions - QAction *copyAddressAction = new QAction(tr("Copy address"), this); - QAction *copyAmountAction = new QAction(tr("Copy amount"), this); - QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); - QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); - contextMenu = new QMenu(); - contextMenu->addAction(copyAddressAction); - contextMenu->addAction(copyAmountAction); - contextMenu->addAction(copyTxIDAction); - contextMenu->addAction(showDetailsAction); - // Connect actions - connect(ui->txHistoryTable, &QWidget::customContextMenuRequested, this, &TXHistoryDialog::contextualMenu); - connect(ui->txHistoryTable, &QAbstractItemView::doubleClicked, this, &TXHistoryDialog::showDetails); - connect(ui->txHistoryTable->horizontalHeader(), &QHeaderView::sectionClicked, this, &TXHistoryDialog::checkSort); - connect(copyAddressAction, &QAction::triggered, this, &TXHistoryDialog::copyAddress); - connect(copyAmountAction, &QAction::triggered, this, &TXHistoryDialog::copyAmount); - connect(copyTxIDAction, &QAction::triggered, this, &TXHistoryDialog::copyTxID); - connect(showDetailsAction, &QAction::triggered, this, &TXHistoryDialog::showDetails); - // Perform initial population and update of history table - - UpdateHistory(); - // since there is no model we can't do this before we add some data, so now let's do the resizing - // *after* we've populated the initial content for the table - ui->txHistoryTable->setColumnWidth(2, 23); - ui->txHistoryTable->resizeColumnToContents(3); - ui->txHistoryTable->resizeColumnToContents(4); - ui->txHistoryTable->resizeColumnToContents(6); - ui->txHistoryTable->setColumnHidden(0, true); // hidden txid for displaying transaction details - ui->txHistoryTable->setColumnHidden(1, true); // hideen sort key - ui->txHistoryTable->setSortingEnabled(true); - ui->txHistoryTable->horizontalHeader()->setSortIndicator(1, Qt::DescendingOrder); // sort by hidden sort key -} - -TXHistoryDialog::~TXHistoryDialog() -{ - delete ui; -} - -void TXHistoryDialog::ReinitTXHistoryTable() -{ - ui->txHistoryTable->setRowCount(0); - txHistoryMap.clear(); - UpdateHistory(); -} - -void TXHistoryDialog::focusTransaction(const uint256& txid) -{ - QAbstractItemModel* historyAbstractModel = ui->txHistoryTable->model(); - QSortFilterProxyModel historyProxy; - historyProxy.setSourceModel(historyAbstractModel); - historyProxy.setFilterKeyColumn(0); - historyProxy.setFilterFixedString(QString::fromStdString(txid.GetHex())); - QModelIndex rowIndex = historyProxy.mapToSource(historyProxy.index(0,0)); - if(rowIndex.isValid()) { - ui->txHistoryTable->scrollTo(rowIndex); - ui->txHistoryTable->setCurrentIndex(rowIndex); - ui->txHistoryTable->setFocus(); - } -} - -void TXHistoryDialog::setClientModel(ClientModel *model) -{ - this->clientModel = model; - if (model != NULL) { - connect(model, &ClientModel::refreshElysiumBalance, this, &TXHistoryDialog::UpdateHistory); - connect(model, &ClientModel::numBlocksChanged, this, &TXHistoryDialog::UpdateConfirmations); - connect(model, &ClientModel::reinitElysiumState, this, &TXHistoryDialog::ReinitTXHistoryTable); - } -} - -void TXHistoryDialog::setWalletModel(WalletModel *model) -{ - this->walletModel = model; - if (model != NULL) { } // do nothing, signals from walletModel no longer needed -} - -int TXHistoryDialog::PopulateHistoryMap() -{ - // TODO: locks may not be needed here -- looks like wallet lock can be removed - if (NULL == pwalletMain) return 0; - // try and fix intermittent freeze on startup and while running by only updating if we can get required locks - TRY_LOCK(cs_main,lckMain); - if (!lckMain) return 0; - TRY_LOCK(pwalletMain->cs_wallet, lckWallet); - if (!lckWallet) return 0; - - int64_t nProcessed = 0; // counter for how many transactions we've added to history this time - - // obtain a sorted list of Elysium layer wallet transactions (including STO receipts and pending) - default last 65535 - std::map walletTransactions = FetchWalletElysiumTransactions(GetArg("-elysiumuiwalletscope", 65535L)); - - // reverse iterate over (now ordered) transactions and populate history map for each one - for (std::map::reverse_iterator it = walletTransactions.rbegin(); it != walletTransactions.rend(); it++) { - uint256 txHash = it->second; - // check historyMap, if this tx exists and isn't pending don't waste resources doing anymore work on it - HistoryMap::iterator hIter = txHistoryMap.find(txHash); - if (hIter != txHistoryMap.end()) { // the tx is in historyMap, if it's a confirmed transaction skip it - HistoryTXObject *temphtxo = &(hIter->second); - if (temphtxo->blockHeight != 0) continue; - { - LOCK(cs_main); - PendingMap::iterator pending_it = my_pending.find(txHash); - if (pending_it != my_pending.end()) continue; // transaction is still pending, do nothing - } - - // pending transaction has confirmed, remove temp pending object from map and allow it to be readded as an Elysium transaction - txHistoryMap.erase(hIter); - ui->txHistoryTable->setSortingEnabled(false); // disable sorting temporarily while we update the table (leaving enabled gives unexpected results) - QAbstractItemModel* historyAbstractModel = ui->txHistoryTable->model(); // get a model to work with - QSortFilterProxyModel historyProxy; - historyProxy.setSourceModel(historyAbstractModel); - historyProxy.setFilterKeyColumn(0); - historyProxy.setFilterFixedString(QString::fromStdString(txHash.GetHex())); - QModelIndex rowIndex = historyProxy.mapToSource(historyProxy.index(0,0)); // map to the row in the actual table - if(rowIndex.isValid()) ui->txHistoryTable->removeRow(rowIndex.row()); // delete the pending tx row, it'll be readded as a proper confirmed transaction - ui->txHistoryTable->setSortingEnabled(true); // re-enable sorting - } - - CTransactionRef wtx; - uint256 blockHash; - if (!GetTransaction(txHash, wtx, Params().GetConsensus(), blockHash, true)) continue; - if (blockHash.IsNull() || NULL == GetBlockIndex(blockHash)) { - // this transaction is unconfirmed, should be one of our pending transactions - LOCK(cs_main); - PendingMap::iterator pending_it = my_pending.find(txHash); - if (pending_it == my_pending.end()) continue; - const CMPPending& pending = pending_it->second; - HistoryTXObject htxo; - htxo.blockHeight = 0; - if (it->first.length() == 16) htxo.blockByteOffset = atoi(it->first.substr(6)); // use wallet position from key in lieu of block position - htxo.valid = true; // all pending transactions are assumed to be valid prior to confirmation (wallet would not send them otherwise) - htxo.address = pending.src; - htxo.amount = "-" + FormatShortMP(pending.prop, pending.amount) + getTokenLabel(pending.prop); - bool fundsMoved = true; - htxo.txType = shrinkTxType(pending.type, &fundsMoved); - if (pending.type == ELYSIUM_TYPE_METADEX_CANCEL_PRICE || pending.type == ELYSIUM_TYPE_METADEX_CANCEL_PAIR || - pending.type == ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM || pending.type == ELYSIUM_TYPE_SEND_ALL) { - htxo.amount = "N/A"; - } - - if (pending.type == ELYSIUM_TYPE_SIMPLE_SPEND) { - if (pending.dest && IsMyAddress(pending.dest.get())) { - htxo.amount = FormatShortMP(pending.prop, pending.amount) + getTokenLabel(pending.prop); - } - } - - txHistoryMap.insert(std::make_pair(txHash, htxo)); - nProcessed++; - continue; - } - - // parse the transaction and setup the new history object - CBlockIndex* pBlockIndex = GetBlockIndex(blockHash); - if (NULL == pBlockIndex) continue; - int blockHeight = pBlockIndex->nHeight; - CMPTransaction mp_obj; - int parseRC = ParseTransaction(*wtx, blockHeight, 0, mp_obj); - HistoryTXObject htxo; - if (it->first.length() == 16) { - htxo.blockHeight = atoi(it->first.substr(0,6)); - htxo.blockByteOffset = atoi(it->first.substr(6)); - } - - // positive RC means payment, potential DEx purchase - if (0 < parseRC) { - string tmpBuyer; - string tmpSeller; - uint64_t total = 0; - uint64_t tmpVout = 0; - uint64_t tmpNValue = 0; - uint64_t tmpPropertyId = 0; - bool bIsBuy = false; - int numberOfPurchases = 0; - { - LOCK(cs_main); - p_txlistdb->getPurchaseDetails(txHash, 1, &tmpBuyer, &tmpSeller, &tmpVout, &tmpPropertyId, &tmpNValue); - } - bIsBuy = IsMyAddress(tmpBuyer); - numberOfPurchases = p_txlistdb->getNumberOfSubRecords(txHash); - if (0 >= numberOfPurchases) continue; - for (int purchaseNumber = 1; purchaseNumber <= numberOfPurchases; purchaseNumber++) { - LOCK(cs_main); - p_txlistdb->getPurchaseDetails(txHash, purchaseNumber, &tmpBuyer, &tmpSeller, &tmpVout, &tmpPropertyId, &tmpNValue); - total += tmpNValue; - } - if (!bIsBuy) { - htxo.txType = "DEx Sell"; - htxo.address = tmpSeller; - } else { - htxo.txType = "DEx Buy"; - htxo.address = tmpBuyer; - } - htxo.valid = true; // only valid DEx payments are recorded in txlistdb - htxo.amount = (!bIsBuy ? "-" : "") + FormatDivisibleShortMP(total) + getTokenLabel(tmpPropertyId); - htxo.fundsMoved = true; - txHistoryMap.insert(std::make_pair(txHash, htxo)); - nProcessed++; - continue; - } - - // handle Elysium transaction - if (0 != parseRC) continue; - if (!mp_obj.interpret_Transaction()) continue; - int64_t amount = mp_obj.getAmount(); - int tmpBlock = 0; - uint32_t type = 0; - uint64_t amountNew = 0; - htxo.valid = getValidMPTX(txHash, &tmpBlock, &type, &amountNew); - if (htxo.valid && type == ELYSIUM_TYPE_TRADE_OFFER && amountNew > 0) amount = amountNew; // override for when amount for sale has been auto-adjusted - - if (htxo.valid && type == ELYSIUM_TYPE_SIMPLE_SPEND) { // override amount for spend - amount = mp_obj.getSpendAmount(); - } - - if (htxo.valid && type == ELYSIUM_TYPE_SIMPLE_MINT) { // override amount for mint - amount = mp_obj.getMintAmount(); - } - - std::string displayAmount = FormatShortMP(mp_obj.getProperty(), amount) + getTokenLabel(mp_obj.getProperty()); - htxo.fundsMoved = true; - htxo.txType = shrinkTxType(mp_obj.getType(), &htxo.fundsMoved); - if (!htxo.valid) htxo.fundsMoved = false; // funds never move in invalid txs - if (htxo.txType == "Send" && !IsMyAddress(mp_obj.getSender())) htxo.txType = "Receive"; // still a send transaction, but avoid confusion for end users - htxo.address = mp_obj.getSender(); - if (!IsMyAddress(mp_obj.getSender())) htxo.address = mp_obj.getReceiver(); - if (htxo.fundsMoved && IsMyAddress(mp_obj.getSender())) displayAmount = "-" + displayAmount; - - if (type == ELYSIUM_TYPE_SIMPLE_SPEND) { - htxo.address = "Spend"; - if (htxo.fundsMoved && !IsMyAddress(mp_obj.getReceiver())) { - displayAmount = "-" + displayAmount; - } - } - - // override - special case for property creation (getProperty cannot get ID as createdID not stored in obj) - if (type == ELYSIUM_TYPE_CREATE_PROPERTY_FIXED || type == ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE || type == ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL) { - displayAmount = "N/A"; - if (htxo.valid) { - uint32_t propertyId = _my_sps->findSPByTX(txHash); - if (type == ELYSIUM_TYPE_CREATE_PROPERTY_FIXED) displayAmount = FormatShortMP(propertyId, getTotalTokens(propertyId)) + getTokenLabel(propertyId); - } - } - - // override - hide display amount for transaction types below as we can't display amount/property as no prop exists - // - Unchanged balance sigma transactions - // - Cancels transactions - // - Unknown transactions - if (type == ELYSIUM_TYPE_METADEX_CANCEL_PRICE || type == ELYSIUM_TYPE_METADEX_CANCEL_PAIR || - type == ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM || type == ELYSIUM_TYPE_SEND_ALL || - type == ELYSIUM_TYPE_CREATE_DENOMINATION || htxo.txType == "Unknown") { - displayAmount = "N/A"; - } - - // override - display amount received not STO amount in packet (the total amount) for STOs I didn't send - if (type == ELYSIUM_TYPE_SEND_TO_OWNERS && !IsMyAddress(mp_obj.getSender())) { - UniValue receiveArray(UniValue::VARR); - uint64_t tmpAmount = 0, stoFee = 0; - LOCK(cs_main); - s_stolistdb->getRecipients(txHash, "", &receiveArray, &tmpAmount, &stoFee); - displayAmount = FormatShortMP(mp_obj.getProperty(), tmpAmount) + getTokenLabel(mp_obj.getProperty()); - } - - htxo.amount = displayAmount; - txHistoryMap.insert(std::make_pair(txHash, htxo)); - nProcessed++; - } - - return nProcessed; -} - -void TXHistoryDialog::UpdateConfirmations() -{ - int chainHeight = GetHeight(); // get the chain height - int rowCount = ui->txHistoryTable->rowCount(); - for (int row = 0; row < rowCount; row++) { - int confirmations = 0; - bool valid = false; - uint256 txid; - txid.SetHex(ui->txHistoryTable->item(row,0)->text().toStdString()); - // lookup transaction in the map and grab validity and blockheight details - HistoryMap::iterator hIter = txHistoryMap.find(txid); - if (hIter != txHistoryMap.end()) { - HistoryTXObject *temphtxo = &(hIter->second); - if (temphtxo->blockHeight>0) confirmations = (chainHeight+1) - temphtxo->blockHeight; - valid = temphtxo->valid; - } - int txBlockHeight = ui->txHistoryTable->item(row,1)->text().toInt(); - if (txBlockHeight>0) confirmations = (chainHeight+1) - txBlockHeight; - // setup the appropriate icon - QIcon ic = QIcon(":/icons/transaction_0"); - switch(confirmations) { - case 1: ic = QIcon(":/icons/transaction_1"); break; - case 2: ic = QIcon(":/icons/transaction_2"); break; - case 3: ic = QIcon(":/icons/transaction_3"); break; - case 4: ic = QIcon(":/icons/transaction_4"); break; - case 5: ic = QIcon(":/icons/transaction_5"); break; - } - if (confirmations > 5) ic = QIcon(":/icons/transaction_confirmed"); - if (!valid) ic = QIcon(":/icons/transaction_conflicted"); - QTableWidgetItem *iconCell = new QTableWidgetItem; -// ic = platformStyle->SingleColorIcon(ic); - iconCell->setIcon(ic); - ui->txHistoryTable->setItem(row, 2, iconCell); - } -} - -void TXHistoryDialog::UpdateHistory() -{ - // now moved to a new methodology where historical transactions are stored in a map in memory (effectively a cache) so we can compare our - // history table against the cache. This allows us to avoid reparsing transactions repeatedly and provides a diff to modify the table without - // repopuplating all the rows top to bottom each refresh. - - // first things first, call PopulateHistoryMap to add in any missing (ie new) transactions - int newTXCount = PopulateHistoryMap(); - // were any transactions added? - if(newTXCount > 0) { // there are new transactions (or a pending shifted to confirmed), refresh the table adding any that are in the map but not in the table - ui->txHistoryTable->setSortingEnabled(false); // disable sorting temporarily while we update the table (leaving enabled gives unexpected results) - QAbstractItemModel* historyAbstractModel = ui->txHistoryTable->model(); // get a model to work with - for(HistoryMap::iterator it = txHistoryMap.begin(); it != txHistoryMap.end(); ++it) { - uint256 txid = it->first; // grab txid - // search the history table for this transaction, here we're going to use a filter proxy because it's a little quicker - QSortFilterProxyModel historyProxy; - historyProxy.setSourceModel(historyAbstractModel); - historyProxy.setFilterKeyColumn(0); - historyProxy.setFilterFixedString(QString::fromStdString(txid.GetHex())); - QModelIndex rowIndex = historyProxy.mapToSource(historyProxy.index(0,0)); - if(!rowIndex.isValid()) { // this transaction doesn't exist in the history table, add it - HistoryTXObject htxo = it->second; // grab the tranaaction - int workingRow = ui->txHistoryTable->rowCount(); - ui->txHistoryTable->insertRow(workingRow); // append a new row (sorting will take care of ordering) - QDateTime txTime; - QTableWidgetItem *dateCell = new QTableWidgetItem; - if (htxo.blockHeight>0) { - LOCK(cs_main); - CBlockIndex* pBlkIdx = chainActive[htxo.blockHeight]; - if (NULL != pBlkIdx) txTime.setTime_t(pBlkIdx->GetBlockTime()); - dateCell->setData(Qt::DisplayRole, txTime); - } else { - dateCell->setData(Qt::DisplayRole, QString::fromStdString("Unconfirmed")); - } - QTableWidgetItem *typeCell = new QTableWidgetItem(QString::fromStdString(htxo.txType)); - QTableWidgetItem *addressCell = new QTableWidgetItem(QString::fromStdString(htxo.address)); - QTableWidgetItem *amountCell = new QTableWidgetItem(QString::fromStdString(htxo.amount)); - QTableWidgetItem *iconCell = new QTableWidgetItem; - QTableWidgetItem *txidCell = new QTableWidgetItem(QString::fromStdString(txid.GetHex())); - std::string sortKey = strprintf("%06d%010d",htxo.blockHeight,htxo.blockByteOffset); - if(htxo.blockHeight == 0) sortKey = strprintf("%06d%010D",999999,htxo.blockByteOffset); // spoof the hidden value to ensure pending txs are sorted top - QTableWidgetItem *sortKeyCell = new QTableWidgetItem(QString::fromStdString(sortKey)); - addressCell->setTextAlignment(Qt::AlignLeft + Qt::AlignVCenter); - addressCell->setForeground(QColor("#707070")); - amountCell->setTextAlignment(Qt::AlignRight + Qt::AlignVCenter); - amountCell->setForeground(QColor("#00AA00")); - if (htxo.amount.length() > 0) { // protect against an empty value - if (htxo.amount.substr(0,1) == "-") amountCell->setForeground(QColor("#EE0000")); // outbound - } - if (!htxo.fundsMoved) amountCell->setForeground(QColor("#404040")); - ui->txHistoryTable->setItem(workingRow, 0, txidCell); - ui->txHistoryTable->setItem(workingRow, 1, sortKeyCell); - ui->txHistoryTable->setItem(workingRow, 2, iconCell); - ui->txHistoryTable->setItem(workingRow, 3, dateCell); - ui->txHistoryTable->setItem(workingRow, 4, typeCell); - ui->txHistoryTable->setItem(workingRow, 5, addressCell); - ui->txHistoryTable->setItem(workingRow, 6, amountCell); - } - } - ui->txHistoryTable->setSortingEnabled(true); // re-enable sorting - } - UpdateConfirmations(); -} - -void TXHistoryDialog::contextualMenu(const QPoint &point) -{ - QModelIndex index = ui->txHistoryTable->indexAt(point); - if(index.isValid()) - { - contextMenu->exec(QCursor::pos()); - } -} - -void TXHistoryDialog::copyAddress() -{ - GUIUtil::setClipboard(ui->txHistoryTable->item(ui->txHistoryTable->currentRow(),5)->text()); -} - -void TXHistoryDialog::copyAmount() -{ - GUIUtil::setClipboard(ui->txHistoryTable->item(ui->txHistoryTable->currentRow(),6)->text()); -} - -void TXHistoryDialog::copyTxID() -{ - GUIUtil::setClipboard(ui->txHistoryTable->item(ui->txHistoryTable->currentRow(),0)->text()); -} - -void TXHistoryDialog::checkSort(int column) -{ - // a header has been clicked on the tx history table, see if it's the status column and override the sort if necessary - // we may wish to be a bit smarter about this longer term, so we can spoof a sort indicator display and perhaps allow both - // directions, but for now will provide the core functionality needed - if (column == 2) { // ignore any other column sorts and allow them to progress normally - ui->txHistoryTable->horizontalHeader()->setSortIndicator(1, Qt::DescendingOrder); - } -} - -void TXHistoryDialog::showDetails() -{ - UniValue txobj(UniValue::VOBJ); - uint256 txid; - txid.SetHex(ui->txHistoryTable->item(ui->txHistoryTable->currentRow(),0)->text().toStdString()); - std::string strTXText; - - if (!txid.IsNull()) { - // grab extended transaction details via the RPC populator - int rc = populateRPCTransactionObject(txid, txobj, "", true); - if (rc >= 0) strTXText = txobj.write(true); - } - - if (!strTXText.empty()) { - PopulateSimpleDialog(strTXText, "Transaction Information", "Transaction Information"); - } -} - -std::string TXHistoryDialog::shrinkTxType(int txType, bool *fundsMoved) -{ - string displayType = "Unknown"; - switch (txType) { - case ELYSIUM_TYPE_SIMPLE_SEND: displayType = "Send"; break; - case ELYSIUM_TYPE_RESTRICTED_SEND: displayType = "Rest. Send"; break; - case ELYSIUM_TYPE_SEND_TO_OWNERS: displayType = "Send To Owners"; break; - case ELYSIUM_TYPE_SEND_ALL: displayType = "Send All"; break; - case ELYSIUM_TYPE_SAVINGS_MARK: displayType = "Mark Savings"; *fundsMoved = false; break; - case ELYSIUM_TYPE_SAVINGS_COMPROMISED: ; displayType = "Lock Savings"; break; - case ELYSIUM_TYPE_RATELIMITED_MARK: displayType = "Rate Limit"; break; - case ELYSIUM_TYPE_AUTOMATIC_DISPENSARY: displayType = "Auto Dispense"; break; - case ELYSIUM_TYPE_TRADE_OFFER: displayType = "DEx Trade"; *fundsMoved = false; break; - case ELYSIUM_TYPE_ACCEPT_OFFER_BTC: displayType = "DEx Accept"; *fundsMoved = false; break; - case ELYSIUM_TYPE_METADEX_TRADE: displayType = "MetaDEx Trade"; *fundsMoved = false; break; - case ELYSIUM_TYPE_METADEX_CANCEL_PRICE: - case ELYSIUM_TYPE_METADEX_CANCEL_PAIR: - case ELYSIUM_TYPE_METADEX_CANCEL_ECOSYSTEM: - displayType = "MetaDEx Cancel"; *fundsMoved = false; break; - case ELYSIUM_TYPE_CREATE_PROPERTY_FIXED: displayType = "Create Property"; break; - case ELYSIUM_TYPE_CREATE_PROPERTY_VARIABLE: displayType = "Create Property"; *fundsMoved = false; break; - case ELYSIUM_TYPE_PROMOTE_PROPERTY: displayType = "Promo Property"; break; - case ELYSIUM_TYPE_CLOSE_CROWDSALE: displayType = "Close Crowdsale"; *fundsMoved = false; break; - case ELYSIUM_TYPE_CREATE_PROPERTY_MANUAL: displayType = "Create Property"; *fundsMoved = false; break; - case ELYSIUM_TYPE_GRANT_PROPERTY_TOKENS: displayType = "Grant Tokens"; break; - case ELYSIUM_TYPE_REVOKE_PROPERTY_TOKENS: displayType = "Revoke Tokens"; break; - case ELYSIUM_TYPE_CHANGE_ISSUER_ADDRESS: displayType = "Change Issuer"; *fundsMoved = false; break; - case ELYSIUM_TYPE_SIMPLE_SPEND: displayType = "Sigma Spend"; break; - case ELYSIUM_TYPE_CREATE_DENOMINATION: displayType = "Create Sigma Denomination"; *fundsMoved = false; break; - case ELYSIUM_TYPE_SIMPLE_MINT: displayType = "Sigma Mint"; break; - } - return displayType; -} diff --git a/src/qt/txhistorydialog.h b/src/qt/txhistorydialog.h deleted file mode 100644 index a0e6b70de1..0000000000 --- a/src/qt/txhistorydialog.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef TXHISTORYDIALOG_H -#define TXHISTORYDIALOG_H - -#include "guiutil.h" -#include "uint256.h" - -#include - -#include - -class ClientModel; -class WalletModel; - -QT_BEGIN_NAMESPACE -class QMenu; -class QModelIndex; -class QPoint; -class QResizeEvent; -class QString; -class QWidget; -QT_END_NAMESPACE - -namespace Ui { - class txHistoryDialog; -} - -class HistoryTXObject -{ -public: - HistoryTXObject() - : blockHeight(-1), blockByteOffset(0), valid(false), fundsMoved(true) {}; - int blockHeight; // block transaction was mined in - int blockByteOffset; // byte offset the tx is stored in the block (used for ordering multiple txs same block) - bool valid; // whether the transaction is valid from an Omni perspective - bool fundsMoved; // whether tokens actually moved in this transaction - std::string txType; // human readable string containing type - std::string address; // the address to be displayed (usually sender or recipient) - std::string amount; // string containing formatted amount -}; - -typedef std::map HistoryMap; - -/** Dialog for looking up Master Protocol tokens */ -class TXHistoryDialog : public QDialog -{ - Q_OBJECT - -public: - explicit TXHistoryDialog(QWidget *parent = 0); - ~TXHistoryDialog(); - - void setClientModel(ClientModel *model); - void setWalletModel(WalletModel *model); - - std::string shrinkTxType(int txType, bool *fundsMoved); - -private: - Ui::txHistoryDialog *ui; - ClientModel *clientModel; - WalletModel *walletModel; - QMenu *contextMenu; - HistoryMap txHistoryMap; - -private Q_SLOTS: - void contextualMenu(const QPoint &point); - void showDetails(); - void copyAddress(); - void copyAmount(); - void copyTxID(); - void UpdateHistory(); - int PopulateHistoryMap(); - void UpdateConfirmations(); - void checkSort(int column); - -public Q_SLOTS: - void focusTransaction(const uint256& txid); - void ReinitTXHistoryTable(); - -Q_SIGNALS: - void doubleClicked(const QModelIndex& idx); - // Fired when a message should be reported to the user - void message(const QString &title, const QString &message, unsigned int style); -}; - -#endif // TXHISTORYDIALOG_H diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 3ede407713..21cf5b0302 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -118,15 +118,6 @@ void WalletFrame::gotoOverviewPage() i.value()->gotoOverviewPage(); } -#ifdef ENABLE_ELYSIUM -void WalletFrame::gotoElyAssetsPage() -{ - QMap::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->gotoElyAssetsPage(); -} -#endif - void WalletFrame::gotoHistoryPage() { QMap::const_iterator i; @@ -134,15 +125,6 @@ void WalletFrame::gotoHistoryPage() i.value()->gotoHistoryPage(); } -#ifdef ENABLE_ELYSIUM -void WalletFrame::gotoElysiumHistoryTab() -{ - QMap::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->gotoElysiumHistoryTab(); -} -#endif - void WalletFrame::gotoBitcoinHistoryTab() { QMap::const_iterator i; @@ -150,15 +132,6 @@ void WalletFrame::gotoBitcoinHistoryTab() i.value()->gotoBitcoinHistoryTab(); } -#ifdef ENABLE_ELYSIUM -void WalletFrame::gotoToolboxPage() -{ - QMap::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->gotoToolboxPage(); -} -#endif - void WalletFrame::gotoMasternodePage() { QMap::const_iterator i; diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 10a547f8e5..4addb0552b 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -68,14 +68,6 @@ class WalletFrame : public QFrame public Q_SLOTS: /** Switch to overview (home) page */ void gotoOverviewPage(); -#ifdef ENABLE_ELYSIUM - /** Switch to ElyAssets page */ - void gotoElyAssetsPage(); - /** Switch to utility page */ - void gotoToolboxPage(); - /** Switch directory to Elysium tx history tab */ - void gotoElysiumHistoryTab(); -#endif /** Switch to history (transactions) page */ void gotoHistoryPage(); /** Switch directory to bitcoin tx history tab */ diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index f9c2625fc0..abaf8c4871 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -15,31 +15,18 @@ #include "lelantusdialog.h" #include "lelantusmodel.h" #include "sparkmodel.h" -#include "metadexcanceldialog.h" -#include "metadexdialog.h" #include "optionsmodel.h" #include "overviewpage.h" #include "platformstyle.h" #include "receivecoinsdialog.h" #include "sendcoinsdialog.h" #include "signverifymessagedialog.h" -#include "tradehistorydialog.h" #include "transactiontablemodel.h" #include "transactionview.h" #include "walletmodel.h" #include "ui_interface.h" -#ifdef ENABLE_ELYSIUM -#include "lookupaddressdialog.h" -#include "lookupspdialog.h" -#include "lookuptxdialog.h" -#include "sendmpdialog.h" -#include "txhistorydialog.h" - -#include "../elysium/elysium.h" -#endif - #include #include #include @@ -57,12 +44,6 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): clientModel(0), walletModel(0), overviewPage(0), -#ifdef ENABLE_ELYSIUM - elysiumTransactionsView(0), - transactionTabs(0), - sendElysiumView(0), - sendCoinsTabs(0), -#endif lelantusView(0), // blankLelantusView(0), firoTransactionsView(0), @@ -70,9 +51,6 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): { overviewPage = new OverviewPage(platformStyle); transactionsPage = new QWidget(this); -#ifdef ENABLE_ELYSIUM - elyAssetsPage = new ElyAssetsDialog(); -#endif receiveCoinsPage = new ReceiveCoinsDialog(platformStyle); createPcodePage = new CreatePcodeDialog(platformStyle); usedSendingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::SendingTab, this); @@ -80,9 +58,6 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): lelantusPage = new QWidget(this); sendCoinsPage = new QWidget(this); -#ifdef ENABLE_ELYSIUM - toolboxPage = new QWidget(this); -#endif masternodeListPage = new MasternodeList(platformStyle); automintNotification = new AutomintNotification(this); @@ -93,31 +68,18 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): setupTransactionPage(); setupSendCoinPage(); -#ifdef ENABLE_ELYSIUM - setupToolboxPage(); -#endif setupLelantusPage(); addWidget(overviewPage); -#ifdef ENABLE_ELYSIUM - addWidget(elyAssetsPage); -#endif addWidget(transactionsPage); addWidget(receiveCoinsPage); addWidget(createPcodePage); addWidget(sendCoinsPage); addWidget(lelantusPage); -#ifdef ENABLE_ELYSIUM - addWidget(toolboxPage); -#endif addWidget(masternodeListPage); // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page connect(overviewPage, &OverviewPage::transactionClicked, this, &WalletView::focusBitcoinHistoryTab); - -#ifdef ENABLE_ELYSIUM - connect(overviewPage, &OverviewPage::elysiumTransactionClicked, this, &WalletView::focusElysiumTransaction); -#endif } WalletView::~WalletView() @@ -157,25 +119,8 @@ void WalletView::setupTransactionPage() firoTransactionsView = new QWidget(); firoTransactionsView->setLayout(firoLayout); -#ifdef ENABLE_ELYSIUM - // Create tabs for transaction categories - if (isElysiumEnabled()) { - elysiumTransactionsView = new TXHistoryDialog(); - - transactionTabs = new QTabWidget(); - transactionTabs->addTab(firoTransactionsView, tr("Firo")); - transactionTabs->addTab(elysiumTransactionsView, tr("Elysium")); - } -#endif - // Set layout for transaction page auto pageLayout = new QVBoxLayout(); - -#ifdef ENABLE_ELYSIUM - if (transactionTabs) { - pageLayout->addWidget(transactionTabs); - } else -#endif pageLayout->addWidget(firoTransactionsView); transactionsPage->setLayout(pageLayout); @@ -187,25 +132,8 @@ void WalletView::setupSendCoinPage() connect(sendFiroView, &SendCoinsDialog::message, this, &WalletView::message); -#ifdef ENABLE_ELYSIUM - // Create tab for coin type - if (isElysiumEnabled()) { - sendElysiumView = new SendMPDialog(platformStyle); - - sendCoinsTabs = new QTabWidget(); - sendCoinsTabs->addTab(sendFiroView, tr("Firo")); - sendCoinsTabs->addTab(sendElysiumView, tr("Elysium")); - } -#endif - // Set layout for send coin page auto pageLayout = new QVBoxLayout(); - -#ifdef ENABLE_ELYSIUM - if (sendCoinsTabs) { - pageLayout->addWidget(sendCoinsTabs); - } else -#endif pageLayout->addWidget(sendFiroView); sendCoinsPage->setLayout(pageLayout); @@ -228,37 +156,12 @@ void WalletView::setupLelantusPage() lelantusPage->setLayout(pageLayout); } -#ifdef ENABLE_ELYSIUM -void WalletView::setupToolboxPage() -{ - // Create tools widget - auto lookupAddress = new LookupAddressDialog(); - auto lookupProperty = new LookupSPDialog(); - auto lookupTransaction = new LookupTXDialog(); - - // Create tab for each tool - auto tabs = new QTabWidget(); - - tabs->addTab(lookupAddress, tr("Lookup Address")); - tabs->addTab(lookupProperty, tr("Lookup Property")); - tabs->addTab(lookupTransaction, tr("Lookup Transaction")); - - // Set layout for toolbox page - auto pageLayout = new QVBoxLayout(); - pageLayout->addWidget(tabs); - toolboxPage->setLayout(pageLayout); -} -#endif - void WalletView::setBitcoinGUI(BitcoinGUI *gui) { if (gui) { // Clicking on a transaction on the overview page simply sends you to transaction history page connect(overviewPage, &OverviewPage::transactionClicked, gui, &BitcoinGUI::gotoHistoryPage); -#ifdef ENABLE_ELYSIUM - connect(overviewPage, &OverviewPage::elysiumTransactionClicked, gui, &BitcoinGUI::gotoElysiumHistoryTab); -#endif // Receive and report messages connect(this, &WalletView::message, [gui](const QString &title, const QString &message, unsigned int style) { @@ -283,22 +186,10 @@ void WalletView::setClientModel(ClientModel *_clientModel) overviewPage->setClientModel(clientModel); sendFiroView->setClientModel(clientModel); masternodeListPage->setClientModel(clientModel); -#ifdef ENABLE_ELYSIUM - elyAssetsPage->setClientModel(clientModel); -#endif + if (pwalletMain->IsHDSeedAvailable()) { lelantusView->setClientModel(clientModel); } - -#ifdef ENABLE_ELYSIUM - if (elysiumTransactionsView) { - elysiumTransactionsView->setClientModel(clientModel); - } - - if (sendElysiumView) { - sendElysiumView->setClientModel(clientModel); - } -#endif } void WalletView::setWalletModel(WalletModel *_walletModel) @@ -321,17 +212,6 @@ void WalletView::setWalletModel(WalletModel *_walletModel) sendFiroView->setModel(_walletModel); automintNotification->setModel(_walletModel); automintSparkNotification->setModel(_walletModel); -#ifdef ENABLE_ELYSIUM - elyAssetsPage->setWalletModel(walletModel); - - if (elysiumTransactionsView) { - elysiumTransactionsView->setWalletModel(walletModel); - } - - if (sendElysiumView) { - sendElysiumView->setWalletModel(walletModel); - } -#endif if (_walletModel) { @@ -402,52 +282,15 @@ void WalletView::gotoOverviewPage() setCurrentWidget(overviewPage); } -#ifdef ENABLE_ELYSIUM -void WalletView::gotoElyAssetsPage() -{ - setCurrentWidget(elyAssetsPage); -} -#endif - void WalletView::gotoHistoryPage() { setCurrentWidget(transactionsPage); } -#ifdef ENABLE_ELYSIUM -void WalletView::gotoElysiumHistoryTab() -{ - if (!transactionTabs) { - return; - } - - setCurrentWidget(transactionsPage); - transactionTabs->setCurrentIndex(1); -} -#endif - void WalletView::gotoBitcoinHistoryTab() { setCurrentWidget(transactionsPage); - -#ifdef ENABLE_ELYSIUM - if (transactionTabs) { - transactionTabs->setCurrentIndex(0); - } -#endif -} - -#ifdef ENABLE_ELYSIUM -void WalletView::focusElysiumTransaction(const uint256& txid) -{ - if (!elysiumTransactionsView) { - return; - } - - gotoElysiumHistoryTab(); - elysiumTransactionsView->focusTransaction(txid); } -#endif void WalletView::focusBitcoinHistoryTab(const QModelIndex &idx) { @@ -475,13 +318,6 @@ void WalletView::gotoLelantusPage() setCurrentWidget(lelantusPage); } -#ifdef ENABLE_ELYSIUM -void WalletView::gotoToolboxPage() -{ - setCurrentWidget(toolboxPage); -} -#endif - void WalletView::gotoSendCoinsPage(QString addr) { setCurrentWidget(sendCoinsPage); @@ -517,12 +353,6 @@ void WalletView::gotoVerifyMessageTab(QString addr) bool WalletView::handlePaymentRequest(const SendCoinsRecipient& recipient) { -#ifdef ENABLE_ELYSIUM - if (sendCoinsTabs) { - sendCoinsTabs->setCurrentIndex(0); - } -#endif - return sendFiroView->handlePaymentRequest(recipient); } diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 1b8e2517e5..4e94074fa0 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -15,10 +15,6 @@ #include "masternodelist.h" #include "lelantusdialog.h" -#ifdef ENABLE_ELYSIUM -#include "elyassetsdialog.h" -#endif - #include class BitcoinGUI; @@ -28,16 +24,8 @@ class PlatformStyle; class ReceiveCoinsDialog; class CreatePcodeDialog; class SendCoinsDialog; -class SendMPDialog; -class TradeHistoryDialog; -class LookupSPDialog; -class LookupTXDialog; -class LookupAddressDialog; -class MetaDExDialog; -class MetaDExCancelDialog; class SendCoinsRecipient; class TransactionView; -class TXHistoryDialog; class WalletModel; class AddressBookPage; @@ -81,9 +69,6 @@ class WalletView : public QStackedWidget private: void setupTransactionPage(); void setupSendCoinPage(); -#ifdef ENABLE_ELYSIUM - void setupToolboxPage(); -#endif void setupLelantusPage(); private: @@ -91,14 +76,6 @@ class WalletView : public QStackedWidget WalletModel *walletModel; OverviewPage *overviewPage; -#ifdef ENABLE_ELYSIUM - ElyAssetsDialog *elyAssetsPage; - QWidget *toolboxPage; - TXHistoryDialog *elysiumTransactionsView; - QTabWidget *transactionTabs; - SendMPDialog *sendElysiumView; - QTabWidget *sendCoinsTabs; -#endif QWidget *transactionsPage; QWidget *smartPropertyPage; ReceiveCoinsDialog *receiveCoinsPage; @@ -107,9 +84,6 @@ class WalletView : public QStackedWidget AddressBookPage *usedReceivingAddressesPage; QWidget *sendCoinsPage; SendCoinsDialog *sendFiroView; - TradeHistoryDialog *tradeHistoryTab; - MetaDExDialog *metaDExTab; - MetaDExCancelDialog *cancelTab; LelantusDialog *lelantusView; QWidget *lelantusPage; TransactionView *firoTransactionList; @@ -125,16 +99,6 @@ class WalletView : public QStackedWidget public Q_SLOTS: /** Switch to overview (home) page */ void gotoOverviewPage(); -#ifdef ENABLE_ELYSIUM - /** Switch to ExoAssets page */ - void gotoElyAssetsPage(); - /** Switch to utility page */ - void gotoToolboxPage(); - /** Switch specifically to elysium tx history tab */ - void gotoElysiumHistoryTab(); - /** Switch to elysium tx history tab and focus on specific transaction */ - void focusElysiumTransaction(const uint256& txid); -#endif /** Switch to history (transactions) page */ void gotoHistoryPage(); /** Switch specifically to bitcoin tx history tab */ diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 6ae630cad0..bfbdf2f22f 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -200,155 +200,6 @@ static const CRPCConvertParam vRPCConvertParams[] = { "spendspark", 0 }, { "spendspark", 1 }, - /* Elysium - data retrieval calls */ - { "elysium_gettradehistoryforaddress", 1 }, - { "elysium_gettradehistoryforaddress", 2 }, - { "elysium_gettradehistoryforpair", 0 }, - { "elysium_gettradehistoryforpair", 1 }, - { "elysium_gettradehistoryforpair", 2 }, - { "elysium_setautocommit", 0 }, - { "elysium_getcrowdsale", 0 }, - { "elysium_getcrowdsale", 1 }, - { "elysium_getgrants", 0 }, - { "elysium_getbalance", 1 }, - { "elysium_getproperty", 0 }, - { "elysium_listtransactions", 1 }, - { "elysium_listtransactions", 2 }, - { "elysium_listtransactions", 3 }, - { "elysium_listtransactions", 4 }, - { "elysium_listmints", 0 }, - { "elysium_listmints", 1 }, - { "elysium_listmints", 2 }, - { "elysium_getallbalancesforid", 0 }, - { "elysium_listblocktransactions", 0 }, - { "elysium_getorderbook", 0 }, - { "elysium_getorderbook", 1 }, - { "elysium_getseedblocks", 0 }, - { "elysium_getseedblocks", 1 }, - { "elysium_getmetadexhash", 0 }, - { "elysium_getfeecache", 0 }, - { "elysium_getfeeshare", 1 }, - { "elysium_getfeetrigger", 0 }, - { "elysium_getfeedistribution", 0 }, - { "elysium_getfeedistributions", 0 }, - { "elysium_getbalanceshash", 0 }, - - /* Elysium - transaction calls */ - { "elysium_send", 2 }, - { "elysium_sendsto", 1 }, - { "elysium_sendsto", 4 }, - { "elysium_sendall", 2 }, - { "elysium_sendtrade", 1 }, - { "elysium_sendtrade", 3 }, - { "elysium_sendcanceltradesbyprice", 1 }, - { "elysium_sendcanceltradesbyprice", 3 }, - { "elysium_sendcanceltradesbypair", 1 }, - { "elysium_sendcanceltradesbypair", 2 }, - { "elysium_sendcancelalltrades", 1 }, - { "elysium_sendissuancefixed", 1 }, - { "elysium_sendissuancefixed", 2 }, - { "elysium_sendissuancefixed", 3 }, - { "elysium_sendissuancefixed", 10 }, - { "elysium_sendissuancemanaged", 1 }, - { "elysium_sendissuancemanaged", 2 }, - { "elysium_sendissuancemanaged", 3 }, - { "elysium_sendissuancemanaged", 9 }, - { "elysium_sendissuancecrowdsale", 1 }, - { "elysium_sendissuancecrowdsale", 2 }, - { "elysium_sendissuancecrowdsale", 3 }, - { "elysium_sendissuancecrowdsale", 9 }, - { "elysium_sendissuancecrowdsale", 11 }, - { "elysium_sendissuancecrowdsale", 12 }, - { "elysium_sendissuancecrowdsale", 13 }, - { "elysium_senddexsell", 1 }, - { "elysium_senddexsell", 4 }, - { "elysium_senddexsell", 6 }, - { "elysium_senddexaccept", 2 }, - { "elysium_senddexaccept", 4 }, - { "elysium_sendclosecrowdsale", 1 }, - { "elysium_sendgrant", 2 }, - { "elysium_sendrevoke", 1 }, - { "elysium_sendchangeissuer", 2 }, - { "elysium_sendenablefreezing", 1 }, - { "elysium_senddisablefreezing", 1 }, - { "elysium_sendfreeze", 2 }, - { "elysium_sendunfreeze", 2 }, - { "elysium_senddeactivation", 1 }, - { "elysium_sendactivation", 1 }, - { "elysium_sendactivation", 2 }, - { "elysium_sendactivation", 3 }, - { "elysium_sendalert", 1 }, - { "elysium_sendalert", 2 }, - { "elysium_sendcreatedenomination", 1 }, - { "elysium_sendmint", 1 }, - { "elysium_sendmint", 2 }, - { "elysium_sendmint", 3 }, - { "elysium_sendspend", 1 }, - { "elysium_sendspend", 2 }, - - /* Elysium - raw transaction calls */ - { "elysium_decodetransaction", 1 }, - { "elysium_decodetransaction", 2 }, - { "elysium_createrawtx_reference", 2 }, - { "elysium_createrawtx_input", 2 }, - { "elysium_createrawtx_change", 1 }, - { "elysium_createrawtx_change", 3 }, - { "elysium_createrawtx_change", 4 }, - - /* Elysium - payload creation */ - { "elysium_createpayload_simplesend", 0 }, - { "elysium_createpayload_sendall", 0 }, - { "elysium_createpayload_dexsell", 0 }, - { "elysium_createpayload_dexsell", 3 }, - { "elysium_createpayload_dexsell", 5 }, - { "elysium_createpayload_dexaccept", 0 }, - { "elysium_createpayload_sto", 0 }, - { "elysium_createpayload_sto", 2 }, - { "elysium_createpayload_issuancefixed", 0 }, - { "elysium_createpayload_issuancefixed", 1 }, - { "elysium_createpayload_issuancefixed", 2 }, - { "elysium_createpayload_issuancemanaged", 0 }, - { "elysium_createpayload_issuancemanaged", 1 }, - { "elysium_createpayload_issuancemanaged", 2 }, - { "elysium_createpayload_issuancecrowdsale", 0 }, - { "elysium_createpayload_issuancecrowdsale", 1 }, - { "elysium_createpayload_issuancecrowdsale", 2 }, - { "elysium_createpayload_issuancecrowdsale", 8 }, - { "elysium_createpayload_issuancecrowdsale", 10 }, - { "elysium_createpayload_issuancecrowdsale", 11 }, - { "elysium_createpayload_issuancecrowdsale", 12 }, - { "elysium_createpayload_closecrowdsale", 0 }, - { "elysium_createpayload_grant", 0 }, - { "elysium_createpayload_revoke", 0 }, - { "elysium_createpayload_changeissuer", 0 }, - { "elysium_createpayload_trade", 0 }, - { "elysium_createpayload_trade", 2 }, - { "elysium_createpayload_canceltradesbyprice", 0 }, - { "elysium_createpayload_canceltradesbyprice", 2 }, - { "elysium_createpayload_canceltradesbypair", 0 }, - { "elysium_createpayload_canceltradesbypair", 1 }, - { "elysium_createpayload_cancelalltrades", 0 }, - - /* Elysium - backwards compatibility */ - { "getcrowdsale_MP", 0 }, - { "getcrowdsale_MP", 1 }, - { "getgrants_MP", 0 }, - { "send_MP", 2 }, - { "getbalance_MP", 1 }, - { "sendtoowners_MP", 1 }, - { "getproperty_MP", 0 }, - { "listtransactions_MP", 1 }, - { "listtransactions_MP", 2 }, - { "listtransactions_MP", 3 }, - { "listtransactions_MP", 4 }, - { "getallbalancesforid_MP", 0 }, - { "listblocktransactions_MP", 0 }, - { "getorderbook_MP", 0 }, - { "getorderbook_MP", 1 }, - { "trade_MP", 1 }, // deprecated - { "trade_MP", 3 }, // deprecated - { "trade_MP", 5 }, // deprecated - /* Evo spork */ { "spork", 2, "features"}, /* BIP47 */ diff --git a/src/rpc/register.h b/src/rpc/register.h index 0f7ff5da06..819ff6c55f 100644 --- a/src/rpc/register.h +++ b/src/rpc/register.h @@ -11,10 +11,6 @@ #include "util.h" -#ifdef ENABLE_ELYSIUM -#include "../elysium/elysium.h" -#endif - /** These are in one header file to avoid creating tons of single-function * headers for everything under src/rpc/ */ class CRPCTable; @@ -36,17 +32,6 @@ void RegisterEvoRPCCommands(CRPCTable &tableRPC); /** Register Quorums RPC commands */ void RegisterQuorumsRPCCommands(CRPCTable &tableRPC); -/** Register Elysium data retrieval RPC commands */ -void RegisterElysiumDataRetrievalRPCCommands(CRPCTable &tableRPC); -#ifdef ENABLE_WALLET -/** Register Elysium transaction creation RPC commands */ -void RegisterElysiumTransactionCreationRPCCommands(CRPCTable &tableRPC); -#endif -/** Register Elysium payload creation RPC commands */ -void RegisterElysiumPayloadCreationRPCCommands(CRPCTable &tableRPC); -/** Register Elysium raw transaction RPC commands */ -void RegisterElysiumRawTransactionRPCCommands(CRPCTable &tableRPC); - static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) { RegisterBlockchainRPCCommands(tableRPC); @@ -58,18 +43,6 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) RegisterEvoRPCCommands(tableRPC); RegisterQuorumsRPCCommands(tableRPC); - -#ifdef ENABLE_ELYSIUM - if (isElysiumEnabled()) { - RegisterElysiumDataRetrievalRPCCommands(tableRPC); - RegisterElysiumPayloadCreationRPCCommands(tableRPC); - RegisterElysiumRawTransactionRPCCommands(tableRPC); - -#ifdef ENABLE_WALLET - RegisterElysiumTransactionCreationRPCCommands(tableRPC); -#endif - } -#endif } #endif diff --git a/src/test/mbstring_tests.cpp b/src/test/mbstring_tests.cpp index 8b7905a615..b9c53e3281 100644 --- a/src/test/mbstring_tests.cpp +++ b/src/test/mbstring_tests.cpp @@ -478,39 +478,6 @@ BOOST_AUTO_TEST_CASE(valid_ascii) SanitizeInvalidUTF8("`abcdefghijklmnopqrstuvwxyz{|}~")); } -BOOST_AUTO_TEST_CASE(elysium_getproperty_2147483662) -{ - BOOST_CHECK_EQUAL( - "{" - " \"propertyid\" : 2147483662," - " \"name\" : \"Test?\"," - " \"category\" : \"Test?\"," - " \"subcategory\" : \"Test?\"," - " \"data\" : \"n/a\"," - " \"url\" : \"n/a\"," - " \"divisible\" : false," - " \"issuer\" : \"1EHdm4svRkVHf9vu7EvJ6aWjwhw7sHUchN\"," - " \"creationtxid\" : \"9e8ffcbdc021ffef16f7f694220a3fb18e037e7ecc53ce6039f9841dfa410cbd\"," - " \"fixedissuance\" : false," - " \"totaltokens\" : \"63\"" - "}", - SanitizeInvalidUTF8( - "{" - " \"propertyid\" : 2147483662," - " \"name\" : \"Test\x8b\"," - " \"category\" : \"Test\x8b\"," - " \"subcategory\" : \"Test\x8b\"," - " \"data\" : \"n/a\"," - " \"url\" : \"n/a\"," - " \"divisible\" : false," - " \"issuer\" : \"1EHdm4svRkVHf9vu7EvJ6aWjwhw7sHUchN\"," - " \"creationtxid\" : \"9e8ffcbdc021ffef16f7f694220a3fb18e037e7ecc53ce6039f9841dfa410cbd\"," - " \"fixedissuance\" : false," - " \"totaltokens\" : \"63\"" - "}" - )); -} - BOOST_AUTO_TEST_CASE(various_valid_strings) { BOOST_CHECK_EQUAL("a€b€c€d@", diff --git a/src/test/spark_state_test.cpp b/src/test/spark_state_test.cpp index f4178e6347..01d63727d2 100644 --- a/src/test/spark_state_test.cpp +++ b/src/test/spark_state_test.cpp @@ -75,7 +75,12 @@ BOOST_AUTO_TEST_CASE(add_mints_to_state) GenerateBlocks(1100); std::vector txs; - auto mints = GenerateMints({1 * COIN, 2 * COIN, 1 * CENT}, txs); + auto mints = GenerateMints({1 * COIN, 2 * COIN, 3 * COIN}, txs); + + sort(mints.begin(), mints.end(), + [](const CSparkMintMeta& a, const CSparkMintMeta& b)->bool { + return a.v < b.v; + }); mempool.clear(); auto blockIdx1 = GenerateBlock({txs[0]}); diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 4ab45d56c7..72ed006b2b 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -33,11 +33,6 @@ #include "wallet/db.h" #include "wallet/wallet.h" #include - -#ifdef ENABLE_ELYSIUM -#include "../elysium/elysium.h" -#endif - #include #include #include @@ -139,9 +134,7 @@ TestingSetup::~TestingSetup() UnregisterNodeSignals(GetNodeSignals()); llmq::InterruptLLMQSystem(); llmq::DestroyLLMQSystem(); -#ifdef ENABLE_ELYSIUM - elysium_shutdown(); -#endif + threadGroup.interrupt_all(); threadGroup.join_all(); UnloadBlockIndex(); diff --git a/src/ui_interface.h b/src/ui_interface.h index 7c47637491..69a139b78d 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -120,18 +120,6 @@ class CClientUIInterface /** Additional data sync progress changed */ boost::signals2::signal NotifyAdditionalDataSyncProgressChanged; - - /** Elysium balances have been updated. */ - boost::signals2::signal ElysiumBalanceChanged; - - /** Elysium state has been changed. */ - boost::signals2::signal ElysiumStateChanged; - - /** Elysium pending status has been changed */ - boost::signals2::signal ElysiumPendingChanged; - - /** Elysium state has been invalidated due to a reorg */ - boost::signals2::signal ElysiumStateInvalidated; }; /** Show warning message **/ diff --git a/src/util.cpp b/src/util.cpp index 2eb872995c..41d549f678 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -130,9 +130,6 @@ bool fSkipMnpayoutCheck = false; std::atomic fReopenDebugLog(false); CTranslationInterface translationInterface; -/** Flag to indicate, whether the Elysium log file should be reopened. */ -std::atomic fReopenElysiumLog(false); - /** Init OpenSSL library multithreading support */ static CCriticalSection** ppmutexOpenSSL; void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS diff --git a/src/util.h b/src/util.h index d64a84421c..65b1804a85 100644 --- a/src/util.h +++ b/src/util.h @@ -64,9 +64,6 @@ extern bool fLogIPs; extern std::atomic fReopenDebugLog; extern CTranslationInterface translationInterface; -/** Flag to indicate, whether the Elysium log file should be reopened. */ -extern std::atomic fReopenElysiumLog; - extern const char * const BITCOIN_CONF_FILENAME; extern const char * const BITCOIN_PID_FILENAME; diff --git a/src/validation.cpp b/src/validation.cpp index 4d932554db..abcb55e0ff 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -59,10 +59,6 @@ #include "sigma/coinspend.h" #include "warnings.h" -#ifdef ENABLE_ELYSIUM -#include "elysium/elysium.h" -#endif - #include "masternode-payments.h" #include "evo/specialtx.h" @@ -3749,31 +3745,11 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara } } #endif - -#ifdef ENABLE_ELYSIUM - //! Elysium: begin block disconnect notification - auto fElysium = isElysiumEnabled(); - - if (fElysium) { - LogPrint("handler", "Elysium handler: block disconnect begin [height: %d, reindex: %d]\n", GetHeight(), (int)fReindex); - elysium_handler_disc_begin(GetHeight(), pindexDelete); - } -#endif - // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: for (const auto& tx : block.vtx) { GetMainSignals().SyncTransaction(*tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK); } - -#ifdef ENABLE_ELYSIUM - //! Elysium: end of block disconnect notification - if (fElysium) { - LogPrint("handler", "Elysium handler: block disconnect end [height: %d, reindex: %d]\n", GetHeight(), (int)fReindex); - elysium_handler_disc_end(GetHeight(), pindexDelete); - } -#endif - return true; } @@ -3845,37 +3821,12 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); -#ifdef ENABLE_ELYSIUM - bool fElysium = isElysiumEnabled(); - - //! Elysium: transaction position within the block - unsigned int nTxIdx = 0; - //! Elysium: number of meta transactions found - unsigned int nNumMetaTxs = 0; - - //! Elysium: begin block connect notification - if (fElysium) { - LogPrint("handler", "Elysium handler: block connect begin [height: %d]\n", GetHeight()); - elysium_handler_block_begin(GetHeight(), pindexNew); - } -#endif - // Remove conflicting transactions from the mempool.; txpools.removeForBlock(blockConnecting.vtx, pindexNew->nHeight); // Update chainActive & related variables. UpdateTip(pindexNew, chainparams); -#ifdef ENABLE_ELYSIUM - //! Elysium: new confirmed transaction notification - if (fElysium) { - BOOST_FOREACH(CTransactionRef tx, blockConnecting.vtx) { - LogPrint("handler", "Elysium handler: new confirmed transaction [height: %d, idx: %u]\n", GetHeight(), nTxIdx); - if (elysium_handler_tx(*tx, GetHeight(), nTxIdx++, pindexNew)) ++nNumMetaTxs; - } - } -#endif - #ifdef ENABLE_WALLET // Sync with HDMint wallet @@ -3912,15 +3863,6 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, } } #endif - -#ifdef ENABLE_ELYSIUM - //! Elysium: end of block connect notification - if (fElysium) { - LogPrint("handler", "Elysium handler: block connect end [new height: %d, found: %u txs]\n", GetHeight(), nNumMetaTxs); - elysium_handler_block_end(GetHeight(), pindexNew, nNumMetaTxs); - } -#endif - int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index d1ab5eea0f..ab6e98fd7d 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -102,10 +102,7 @@ const uint32_t BIP44_INDEX = 0x2C; const uint32_t BIP44_TEST_INDEX = 0x1; // https://github.com/satoshilabs/slips/blob/master/slip-0044.md#registered-coin-types const uint32_t BIP44_FIRO_INDEX = 0x88; // https://github.com/satoshilabs/slips/blob/master/slip-0044.md#registered-coin-types const uint32_t BIP44_MINT_INDEX = 0x2; -#ifdef ENABLE_ELYSIUM -const uint32_t BIP44_ELYSIUM_MINT_INDEX_V0 = 0x3; -const uint32_t BIP44_ELYSIUM_MINT_INDEX_V1 = 0x4; -#endif + const uint32_t BIP44_MINT_VALUE_INDEX = 0x5; class CBlockIndex; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index f794d598c6..d56f1c8672 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -81,7 +81,7 @@ class CHDChain static const int VERSION_WITH_BIP44 = 10; static const int VERSION_WITH_BIP39 = 11; static const int CURRENT_VERSION = VERSION_WITH_BIP39; - static const int N_CHANGES = 5; // standard = 0/1, mint = 2, elysium = 3, elysiumv1 = 4 + static const int N_CHANGES = 5; // standard = 0/1, mint = 2 int nVersion; CHDChain() { SetNull(); } @@ -323,154 +323,6 @@ class CWalletDB : public CDB static void IncrementUpdateCounter(); static unsigned int GetUpdateCounter(); -#ifdef ENABLE_ELYSIUM - -public: - template - bool ReadElysiumMintPoolV0(MintPool &mintPool) - { - return Read(std::string("exodus_mint_pool"), mintPool); - } - - template - bool WriteElysiumMintPoolV0(MintPool const &mintPool) - { - return Write(std::string("exodus_mint_pool"), mintPool, true); - } - - bool HasElysiumMintPoolV0() - { - return Exists(std::string("exodus_mint_pool")); - } - - template - bool ReadElysiumMintIdV0(const Key& k, MintID &id) - { - return Read(std::make_pair(std::string("exodus_mint_id"), k), id); - } - - template - bool WriteElysiumMintIdV0(const Key& k, const MintID &id) - { - return Write(std::make_pair(std::string("exodus_mint_id"), k), id); - } - - template - bool HasElysiumMintIdV0(const Key& k) - { - return Exists(std::make_pair(std::string("exodus_mint_id"), k)); - } - - template - bool EraseElysiumMintIdV0(const Key& k) - { - return Erase(std::make_pair(std::string("exodus_mint_id"), k)); - } - - template - bool ReadElysiumMintV0(const K& k, V& v) - { - return Read(std::make_pair(std::string("exodus_mint"), k), v); - } - - template - bool HasElysiumMintV0(const K& k) - { - return Exists(std::make_pair(std::string("exodus_mint"), k)); - } - - template - bool WriteElysiumMintV0(const K &k, const V &v) - { - return Write(std::make_pair(std::string("exodus_mint"), k), v, true); - } - - template - bool EraseElysiumMintV0(const K& k) - { - return Erase(std::make_pair(std::string("exodus_mint"), k)); - } - - template - void ListElysiumMintsV0(InsertF insertF) - { - ListEntries(std::string("exodus_mint"), insertF); - } - - // version 1 - template - bool ReadElysiumMintPoolV1(MintPool &mintPool) - { - return Read(std::string("exodus_mint_pool_v1"), mintPool); - } - - template - bool WriteElysiumMintPoolV1(MintPool const &mintPool) - { - return Write(std::string("exodus_mint_pool_v1"), mintPool, true); - } - - bool HasElysiumMintPoolV1() - { - return Exists(std::string("exodus_mint_pool_v1")); - } - - template - bool ReadElysiumMintIdV1(const Key& k, MintID &id) - { - return Read(std::make_pair(std::string("exodus_mint_id_v1"), k), id); - } - - template - bool WriteElysiumMintIdV1(const Key& k, const MintID &id) - { - return Write(std::make_pair(std::string("exodus_mint_id_v1"), k), id); - } - - template - bool HasElysiumMintIdV1(const Key& k) - { - return Exists(std::make_pair(std::string("exodus_mint_id_v1"), k)); - } - - template - bool EraseElysiumMintIdV1(const Key& k) - { - return Erase(std::make_pair(std::string("exodus_mint_id_v1"), k)); - } - - template - bool ReadElysiumMintV1(const K& k, V& v) - { - return Read(std::make_pair(std::string("exodus_mint_v1"), k), v); - } - - template - bool HasElysiumMintV1(const K& k) - { - return Exists(std::make_pair(std::string("exodus_mint_v1"), k)); - } - - template - bool WriteElysiumMintV1(const K &k, const V &v) - { - return Write(std::make_pair(std::string("exodus_mint_v1"), k), v, true); - } - - template - bool EraseElysiumMintV1(const K& k) - { - return Erase(std::make_pair(std::string("exodus_mint_v1"), k)); - } - - template - void ListElysiumMintsV1(InsertF insertF) - { - ListEntries(std::string("exodus_mint_v1"), insertF); - } - -#endif - //bip47 data bool WriteBip47Account(bip47::CAccountReceiver const & account); bool WriteBip47Account(bip47::CAccountSender const & account);