diff --git a/.gitignore b/.gitignore index d139071e0..a4396df73 100644 --- a/.gitignore +++ b/.gitignore @@ -132,6 +132,7 @@ src/cc/rogue/rogue src/cc/rogue/rogue.so src/cc/rogue/test.zip +src/cc/dapps/a.out src/checkfile src/foo.zip @@ -145,8 +146,6 @@ src/rogue.530623577502174316.pack src/rogue.530623577502174316.player -src/cc/rogue/config.h - src/cc/rogue/config.h src/ROGUE.conf diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a7354b240..2a06081f3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,6 +40,7 @@ build:ubuntu: - mkdir ${PACKAGE_DIR_LINUX} - cp src/komodod src/komodo-cli + zcutil/fetch-params.sh ${PACKAGE_DIR_LINUX} - chmod +x ${PACKAGE_DIR_LINUX}/komodod - chmod +x ${PACKAGE_DIR_LINUX}/komodo-cli @@ -71,10 +72,8 @@ build:windows: - cp src/komodod.exe src/komodo-cli.exe src/komodo-tx.exe - src/cc/rogue/rogue.exe + zcutil/wget64.exe zcutil/fetch-params.bat - src/cc/rogue/x86_64-w64-mingw32/bin/libcurl-4.dll - src/cc/rogue/x86_64-w64-mingw32/bin/libncursesw6.dll ${PACKAGE_DIR_WINDOWS} - zip -r ${PACKAGE_DIR_WINDOWS}.zip ${PACKAGE_DIR_WINDOWS} - md5sum ${AGAMA_ARTIFACTS_WINDOWS} > ${AGAMA_ARTIFACTS_WINDOWS_CHECKSUM} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..b7ff449d6 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,62 @@ + +# Komodo Core (komodod) Software Contribution Guidelines + +Thank you for reaching out and trying to make Komodo an even better software application and blockchain platform. These contribution guidelines shall help you figuring out where you can be helpful and how to easily get started. + +## Table of Contents + +0. [Types of contributions we're looking for](#types-of-contributions-were-looking-for) +0. [Ground rules & expectations](#ground-rules--expectations) +0. [How to contribute](#how-to-contribute) +0. [Style guide](#style-guide) +0. [Setting up your environment](#setting-up-your-environment) +0. [Contribution review process](#contribution-review-process) +0. [Community](#community) + +## Types of contributions we're looking for +There are many ways you can directly contribute to Komodo: + +* Debug and test the Komodo Core code +* Find and fix bugs +* Improve suboptimal code +* Extend our software +* Perform a secure code review of Komodo Core and other Komodo-related software + +Interested in making a contribution? Read on! + +## Ground rules & expectations + +Before we get started, here are a few things we expect from you (and that you should expect from others): + +* Be kind and thoughtful in your conversations around this project. We all come from different backgrounds and projects, which means we likely have different perspectives on "how open source is done." Try to listen to others rather than convince them that your way is correct. +* Open Source Guides are released with a [Contributor Code of Conduct](./code_of_conduct.md). By participating in this project, you agree to abide by its terms. +* If you open a pull request, please ensure that your contribution passes all tests. If there are test failures, you will need to address them before we can merge your contribution. +* When adding content, please consider if it is widely valuable. Please don't add references or links to things you or your employer have created as others will do so if they appreciate it. + +## How to contribute + +If you'd like to contribute, start by searching through the [issues](https://github.com/komodoplatform/komodo/issues) and [pull requests](https://github.com/komodoplatform/komodo/pulls) to see whether someone else has raised a similar idea or question. + +If you don't see your idea listed, and you think it can contribute to Komodo, do one of the following: +* **If your contribution is minor,** such as a fixing a typo, open a pull request. +* **If your contribution is major,** such as a new feature or bugfix, start by opening an issue first. That way, other contributors can weigh in on the discussion before you do any work. + +## Style guide +Write clear, clean and consistent code. Follow well-known and established style guidelines like [Google's C++ Style Guide](https://google.github.io/styleguide/cppguide.html) or [Bjarne Stroustrup's C++ Style FAQ](http://www.stroustrup.com/bs_faq2.html). + +## Setting up your environment + +The Komodo Core (komodod) is mainly written in C++ with specific modules written in C. Follow the [Getting Started](https://github.com/komodoplatform/komodo#getting-started) instructions to build komodod from sources. For more informations about the Komodo Platform and a full API documentation please visit the official [Komodo developer documentation](https://docs.komodoplatform.com/). + +## Contribution review process + +Our team and community will review your contribution and start a transparent testing and quality assurance process. As soon as your contribution has undergone sucessful review and QA signoff it gets merged into the Komodo sourcecode. + +## Community + +Discussions about Komodo's development take place on our [discord server](https://discord.gg/yhfzqsg). Anybody is welcome to join these conversations. There is also a [newsletter](http://komodoplatform.com) with regular updates. + +Wherever possible, do not take these conversations to private channels, including contacting the maintainers directly. Keeping communication public means everybody can benefit and learn from the conversation. + + +This contribution guideline is adapted from the Open Source Guides. diff --git a/README.md b/README.md index 6c0002ba4..d12521765 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ This is the official Komodo sourcecode repository based on https://github.com/jl ## Tech Specification - Max Supply: 200 million KMD -- Block Time: 1m 2s +- Block Time: 60 seconds - Block Reward: 3 KMD - Mining Algorithm: Equihash @@ -84,7 +84,7 @@ brew update brew upgrade brew tap discoteq/discoteq; brew install flock brew install autoconf autogen automake -brew install gcc@6 +brew update && brew install gcc@8 brew install binutils brew install protobuf brew install coreutils diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..6bcbe7706 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,30 @@ +## Reporting a Vulnerability + +Please use the below [contact data](https://komodoplatform.com/.well-known/security.txt.asc) to report vulnerabilities. We kindly ask you to not publish or exploit any found vulnerabilities. + +``` +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +Contact: security@komodoplatform.com +Contact: ca333@komodoplatform.com +Contact: noashh@komodoplatform.com +Encryption: http://pgp.key-server.io:11371/0x379287998EE6CF47 +-----BEGIN PGP SIGNATURE----- + +iQJNBAEBCAA3FiEEVez5U2AlPa805zvqN5KHmY7mz0cFAlz6EuMZHGNhMzMzQGtv +bW9kb3BsYXRmb3JtLmNvbQAKCRA3koeZjubPR8cIEACP+JjyXDIzjgIewMMi/02b +tsYswPyQ+9bAoEJnis3r94d1FP1rqXmt4oNz6VwFTqQLEa5opW+gvvaxBTFJSPb0 +UzbS+1PjfAOox5cnT3Dnv9kcy4ECslnW/G+mH+85BUgz1HuqYc8A3kNQJL7KqLoi +YeD0Hd09KtlG+B4PWdnqLw/uvfbavSKdMn6WSIU6adNZWX0ewSubWPXvrWea5cI2 +yKDdMcDqB8Sc9J4JR2L9zW8NqPQuaxfLQbkCt2tg9QjlClrAqQgb8OZQJgY9f1T/ +kBlVXoA4ZUZeifvjSKxQ/3TdRFP+jbV9xsb6sr14zTx+Wcoqtgsh3l9F4+T3V2m8 +/c/iS4mFlK31pJtwYyrJAq9hpggqymdCVi0Pa3yLZsEj3orBPaPWbmq2v7xeF3J8 +y8vqAkt3M3T6251aZAKEcaN5RXYJW70CTseadwp0tmrAL2nIVmziNCMOF+Bufyxi +HddkasTcNX8VYfPCLWqBwrocx8d3n3E7dBGeS2x2iwuRVQ85pH5d+imxaMftcbqm +YrNuiqcI/0XDGk9pS6f1gpu5Eh5Q2QXGmOoRlfosfkAEfgFxfaMvmcu5Ay1s0gSR +MsTn0PrQyMYC3t3KpyP47C8ui9x7FtJFltR/QT4yzBF1QyDmINnK86ldQqSui402 +2+gQFt7YFvLIBUiy1fh1Jw== +=UITq +-----END PGP SIGNATURE----- +``` diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index f9b066fcf..cbbc5a667 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -1,5 +1,5 @@ -build_darwin_CC = gcc-6 -build_darwin_CXX = g++-6 +build_darwin_CC = gcc-8 +build_darwin_CXX = g++-8 build_darwin_AR: = $(shell xcrun -f ar) build_darwin_RANLIB: = $(shell xcrun -f ranlib) build_darwin_STRIP: = $(shell xcrun -f strip) @@ -10,8 +10,8 @@ build_darwin_SHA256SUM = shasum -a 256 build_darwin_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -f -o #darwin host on darwin builder. overrides darwin host preferences. -darwin_CC= gcc-6 -darwin_CXX= g++-6 +darwin_CC= gcc-8 +darwin_CXX= g++-8 darwin_AR:=$(shell xcrun -f ar) darwin_RANLIB:=$(shell xcrun -f ranlib) darwin_STRIP:=$(shell xcrun -f strip) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index d01e8b5a3..7be744aeb 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,9 +1,9 @@ -OSX_MIN_VERSION=10.8 -OSX_SDK_VERSION=10.11 +OSX_MIN_VERSION=10.12 +OSX_SDK_VERSION=10.12 OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk LD64_VERSION=253.9 -darwin_CC=gcc-6 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -darwin_CXX=g++-6 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) +darwin_CC=gcc-8 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) +darwin_CXX=g++-8 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) darwin_CFLAGS=-pipe darwin_CXXFLAGS=$(darwin_CFLAGS) diff --git a/qa/rpc-tests/cryptoconditions_oracles.py b/qa/rpc-tests/cryptoconditions_oracles.py index 953df5ca9..1db33bef7 100755 --- a/qa/rpc-tests/cryptoconditions_oracles.py +++ b/qa/rpc-tests/cryptoconditions_oracles.py @@ -3,7 +3,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. - from test_framework.test_framework import CryptoconditionsTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_greater_than, \ @@ -11,13 +10,11 @@ from test_framework.util import assert_equal, assert_greater_than, \ stop_nodes, sync_blocks, sync_mempools, wait_bitcoinds, rpc_port, assert_raises from cryptoconditions import assert_success, assert_error, generate_random_string - class CryptoconditionsOraclesTest(CryptoconditionsTestFramework): def run_oracles_tests(self): rpc = self.nodes[0] rpc1 = self.nodes[1] - result = rpc1.oraclesaddress() result = rpc.oraclesaddress() @@ -54,159 +51,197 @@ class CryptoconditionsOraclesTest(CryptoconditionsTestFramework): too_long_description = generate_random_string(4100) result = rpc.oraclescreate("Test", too_long_description, "s") assert_error(result) + + # need uxtos to create oracle? Crashes if without generate + rpc.generate(2) + # valid creating oracles of different types # using such naming to re-use it for data publishing / reading (e.g. oracle_s for s type) + valid_formats = ["s", "S", "d", "D", "c", "C", "t", "T", "i", "I", "l", "L", "h", "Ihh"] for f in valid_formats: - result = rpc.oraclescreate("Test", "Test", f) + result = rpc.oraclescreate("Test_"+f, "Test_"+f, f) assert_success(result) globals()["oracle_{}".format(f)] = self.send_and_mine(result['hex'], rpc) # trying to register with negative datafee - for f in valid_formats: result = rpc.oraclesregister(globals()["oracle_{}".format(f)], "-100") assert_error(result) # trying to register with zero datafee - for f in valid_formats: result = rpc.oraclesregister(globals()["oracle_{}".format(f)], "0") assert_error(result) # trying to register with datafee less than txfee - for f in valid_formats: result = rpc.oraclesregister(globals()["oracle_{}".format(f)], "500") assert_error(result) - # trying to register valid - for f in valid_formats: + # trying to register valid (unfunded) result = rpc.oraclesregister(globals()["oracle_{}".format(f)], "10000") + assert_error(result) + + # Fund the oracles + result = rpc.oraclesfund(globals()["oracle_{}".format(f)]) + assert_success(result) + fund_txid = self.send_and_mine(result["hex"], rpc) + assert fund_txid, "got txid" + + # trying to register valid (funded) + result = rpc.oraclesregister(globals()["oracle_{}".format(f)], "10000") + print(f) assert_success(result) register_txid = self.send_and_mine(result["hex"], rpc) assert register_txid, "got txid" # TODO: for most of the non valid oraclesregister and oraclessubscribe transactions generating and broadcasting now # so trying only valid oraclessubscribe atm - for f in valid_formats: result = rpc.oraclessubscribe(globals()["oracle_{}".format(f)], self.pubkey, "1") assert_success(result) subscribe_txid = self.send_and_mine(result["hex"], rpc) assert register_txid, "got txid" + rpc.generate(1) + # now lets publish and read valid data for each oracle type # s type result = rpc.oraclesdata(globals()["oracle_{}".format("s")], "05416e746f6e") assert_success(result) - # baton - oraclesdata_s = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("s")], oraclesdata_s, "1") - assert_equal("[u'Anton']", str(result["samples"][0]), "Data match") + oraclesdata_s = self.send_and_mine(result["hex"], rpc) + info = rpc.oraclesinfo(globals()["oracle_{}".format("s")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("s")], batonaddr, "1") + assert_equal("[u'Anton']", str(result["samples"][0]['data']), "Data match") # S type result = rpc.oraclesdata(globals()["oracle_{}".format("S")], "000161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161") assert_success(result) - # baton oraclesdata_S = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("S")], oraclesdata_S, "1") - assert_equal("[u'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("S")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("S")], batonaddr, "1") + assert_equal("[u'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']", str(result["samples"][0]['data']), "Data match") # d type result = rpc.oraclesdata(globals()["oracle_{}".format("d")], "0101") assert_success(result) # baton oraclesdata_d = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("d")], oraclesdata_d, "1") - assert_equal("[u'01']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("d")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("d")], batonaddr, "1") + assert_equal("[u'01']", str(result["samples"][0]['data']), "Data match") # D type result = rpc.oraclesdata(globals()["oracle_{}".format("D")], "010001") assert_success(result) # baton oraclesdata_D = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("D")], oraclesdata_D, "1") - assert_equal("[u'01']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("D")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("D")], batonaddr, "1") + assert_equal("[u'01']", str(result["samples"][0]['data']), "Data match") # c type result = rpc.oraclesdata(globals()["oracle_{}".format("c")], "ff") assert_success(result) # baton oraclesdata_c = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("c")], oraclesdata_c, "1") - assert_equal("[u'-1']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("c")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("c")], batonaddr, "1") + assert_equal("[u'-1']", str(result["samples"][0]['data']), "Data match") # C type result = rpc.oraclesdata(globals()["oracle_{}".format("C")], "ff") assert_success(result) # baton oraclesdata_C = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("C")], oraclesdata_C, "1") - assert_equal("[u'255']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("C")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("C")], batonaddr, "1") + assert_equal("[u'255']", str(result["samples"][0]['data']), "Data match") # t type result = rpc.oraclesdata(globals()["oracle_{}".format("t")], "ffff") assert_success(result) # baton oraclesdata_t = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("t")], oraclesdata_t, "1") - assert_equal("[u'-1']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("t")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("t")], batonaddr, "1") + assert_equal("[u'-1']", str(result["samples"][0]['data']), "Data match") # T type result = rpc.oraclesdata(globals()["oracle_{}".format("T")], "ffff") assert_success(result) # baton oraclesdata_T = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("T")], oraclesdata_T, "1") - assert_equal("[u'65535']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("T")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("T")], batonaddr, "1") + assert_equal("[u'65535']", str(result["samples"][0]['data']), "Data match") # i type result = rpc.oraclesdata(globals()["oracle_{}".format("i")], "ffffffff") assert_success(result) # baton oraclesdata_i = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("i")], oraclesdata_i, "1") - assert_equal("[u'-1']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("i")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("i")], batonaddr, "1") + assert_equal("[u'-1']", str(result["samples"][0]['data']), "Data match") # I type result = rpc.oraclesdata(globals()["oracle_{}".format("I")], "ffffffff") assert_success(result) # baton oraclesdata_I = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("I")], oraclesdata_I, "1") - assert_equal("[u'4294967295']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("I")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("I")], batonaddr, "1") + assert_equal("[u'4294967295']", str(result["samples"][0]['data']), "Data match") # l type result = rpc.oraclesdata(globals()["oracle_{}".format("l")], "00000000ffffffff") assert_success(result) # baton oraclesdata_l = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("l")], oraclesdata_l, "1") - # TODO: working not correct now! - #assert_equal("[u'-4294967296']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("l")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("l")], batonaddr, "1") + assert_equal("[u'-4294967296']", str(result["samples"][0]['data']), "Data match") # L type result = rpc.oraclesdata(globals()["oracle_{}".format("L")], "00000000ffffffff") assert_success(result) # baton oraclesdata_L = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("L")], oraclesdata_L, "1") - assert_equal("[u'18446744069414584320']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("L")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("L")], batonaddr, "1") + assert_equal("[u'18446744069414584320']", str(result["samples"][0]['data']), "Data match") # h type result = rpc.oraclesdata(globals()["oracle_{}".format("h")], "00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff") assert_success(result) # baton oraclesdata_h = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("h")], oraclesdata_h, "1") - assert_equal("[u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000']", str(result["samples"][0]), "Data match") + info = rpc.oraclesinfo(globals()["oracle_{}".format("h")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("h")], batonaddr, "1") + assert_equal("[u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000']", str(result["samples"][0]['data']), "Data match") # Ihh type result = rpc.oraclesdata(globals()["oracle_{}".format("Ihh")], "ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff") assert_success(result) # baton oraclesdata_Ihh = self.send_and_mine(result["hex"], rpc) - result = rpc.oraclessamples(globals()["oracle_{}".format("Ihh")], oraclesdata_Ihh, "1") - assert_equal("[u'4294967295', u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000', u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000']", str(result["samples"][0]), "Data match") - + info = rpc.oraclesinfo(globals()["oracle_{}".format("Ihh")]) + batonaddr = info['registered'][0]['baton'] + result = rpc.oraclessamples(globals()["oracle_{}".format("Ihh")], batonaddr, "1") + print(result) + assert_equal("[u'4294967295', u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000', u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000']", str(result["samples"][0]['data']), "Data match") def run_test(self): print("Mining blocks...") diff --git a/src/Makefile.am b/src/Makefile.am index e6c1fbb14..a7dd21be8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -599,11 +599,19 @@ if ENABLE_PROTON komodod_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS) endif +# [+] Decker: use static linking for libstdc++.6.dylib, libgomp.1.dylib, libgcc_s.1.dylib +if TARGET_DARWIN +komodod_LDFLAGS += -static-libgcc +endif + # bitcoin-cli binary # komodo_cli_SOURCES = bitcoin-cli.cpp komodo_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) komodo_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) komodo_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +if TARGET_DARWIN +komodo_cli_LDFLAGS += -static-libgcc +endif # wallet-utility binary # if ENABLE_WALLET diff --git a/src/ac/k64 b/src/ac/k64 new file mode 100755 index 000000000..a3b3bc835 --- /dev/null +++ b/src/ac/k64 @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=K64 $1 $2 $3 $4 $5 $6 diff --git a/src/ac/zex b/src/ac/zex deleted file mode 100755 index f4573c093..000000000 --- a/src/ac/zex +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -./komodo-cli -ac_name=ZEX $1 $2 $3 $4 $5 $6 diff --git a/src/ac/zexo b/src/ac/zexo new file mode 100755 index 000000000..b6fd508f2 --- /dev/null +++ b/src/ac/zexo @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=ZEXO $1 $2 $3 $4 $5 $6 diff --git a/src/assetchains.json b/src/assetchains.json index 99c6557b6..86dc77565 100644 --- a/src/assetchains.json +++ b/src/assetchains.json @@ -159,18 +159,6 @@ "136.243.102.225" ] }, - { - "ac_name": "MGNX", - "ac_supply": "12465003", - "ac_staked": "90", - "ac_reward": "2000000000", - "ac_halving": "525960", - "ac_cc": "2", - "ac_end": "2629800", - "addnode": [ - "142.93.27.180" - ] - }, { "ac_name": "PGT", "ac_supply": "10000000", @@ -202,17 +190,6 @@ "144.76.217.232" ] }, - { - "ac_name": "ZEX", - "ac_founders": "1", - "ac_reward": "13000000000", - "ac_halving": "525600", - "ac_cc": "2", - "ac_pubkey": "039d4a50cc70d1184e462a22edb3b66385da97cc8059196f8305c184a3e21440af", - "addnode": [ - "5.9.102.210" - ] - }, { "ac_name": "KSB", "ac_supply": "1000000000", @@ -268,5 +245,28 @@ "ac_name": "KOIN", "ac_supply": "125000000", "addnode": ["3.0.32.10"] + }, + { + "ac_name": "ZEXO", + "ac_reward": "1478310502", + "ac_halving": "525600", + "ac_cc": "42", + "ac_ccenable": "236", + "ac_supply": "100000000", + "ac_perc": "77700", + "ac_staked": "93", + "ac_pubkey": "02713bd85e054db923694b6b7a85306264edf4d6bd6d331814f2b40af444b3ebbc", + "ac_public": "1", + "addnode": [ + "195.201.20.230", + "80.240.17.222" + ] + }, + { + "ac_name": "K64", + "ac_reward": "0", + "ac_supply": "64000777", + "ac_staked": "10", + "addnode": ["18.197.20.21"] } ] diff --git a/src/assetchains.old b/src/assetchains.old index fd472eff9..4cf427c4d 100755 --- a/src/assetchains.old +++ b/src/assetchains.old @@ -39,11 +39,10 @@ echo $pubkey ./komodod -pubkey=$pubkey -ac_name=SEC -ac_cc=333 -ac_supply=1000000000 -addnode=185.148.145.43 & ./komodod -pubkey=$pubkey -ac_name=CCL -ac_supply=200000000 -ac_end=1 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=142.93.136.89 -addnode=195.201.22.89 & ./komodod -pubkey=$pubkey -ac_name=PIRATE -ac_supply=0 -ac_reward=25600000000 -ac_halving=77777 -ac_private=1 -addnode=178.63.77.56 & -./komodod -pubkey=$pubkey -ac_name=MGNX -ac_supply=12465003 -ac_staked=90 -ac_reward=2000000000 -ac_halving=525960 -ac_cc=2 -ac_end=2629800 -addnode=142.93.27.180 & +#./komodod -pubkey=$pubkey -ac_name=MGNX -ac_supply=12465003 -ac_staked=90 -ac_reward=2000000000 -ac_halving=525960 -ac_cc=2 -ac_end=2629800 -addnode=142.93.27.180 & ./komodod -pubkey=$pubkey -ac_name=PGT -ac_supply=10000000 -ac_end=1 -addnode=190.114.254.104 & ./komodod -pubkey=$pubkey -ac_name=KMDICE -ac_supply=10500000 -ac_reward=2500000000 -ac_halving=210000 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=144.76.217.232 & ./komodod -pubkey=$pubkey -ac_name=DION -ac_supply=3900000000 -ac_reward=22260000000 -ac_staked=100 -ac_cc=1 -ac_end=4300000000 -addnode=51.75.124.34 & -./komodod -pubkey=$pubkey -ac_name=ZEX -ac_cc=2 -ac_founders=1 -ac_halving=525600 -ac_reward=13000000000 -ac_pubkey=039d4a50cc70d1184e462a22edb3b66385da97cc8059196f8305c184a3e21440af -addnode=5.9.102.210 & ./komodod -pubkey=$pubkey -ac_name=KSB -ac_supply=1000000000 -ac_end=1 -ac_public=1 -addnode=37.187.225.231 & ./komodod -pubkey=$pubkey -ac_name=OUR -ac_reward=1478310502 -ac_halving=525600 -ac_cc=42 -ac_supply=100000000 -ac_perc=77700 -ac_staked=93 -ac_pubkey=02652a3f3e00b3a1875a918314f0bac838d6dd189a346fa623f5efe9541ac0b98c -ac_public=1 -addnode=51.255.195.65 -addnode=217.182.129.38 -addnode=37.187.225.231 & ./komodod -pubkey=$pubkey -ac_name=ILN -ac_supply=10000000000 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=51.75.122.83 & @@ -51,4 +50,5 @@ echo $pubkey ./komodod -pubkey=$pubkey -ac_name=MORTY -ac_supply=90000000000 -ac_reward=100000000 -ac_cc=3 -addnode=138.201.136.145 & ./komodod -pubkey=$pubkey -ac_name=VOTE2019 -ac_supply=123651638 -ac_public=1 -addnode=95.213.238.98 & ./komodod -pubkey=$pubkey -ac_name=KOIN -ac_supply=125000000 -addnode=3.0.32.10 & -~/hush3/src/komodod -pubkey=$pubkey -ac_name=HUSH3 -ac_sapling=1 -ac_reward=0,1125000000,562500000 -ac_halving=129,340000,840000 -ac_end=128,340000,5422111 -ac_eras=3 -ac_blocktime=150 -ac_cc=2 -ac_ccenable=228,234,235,236,241 -ac_founders=1 -ac_supply=6178674 -ac_perc=11111111 -clientname=GoldenSandtrout -addnode=188.165.212.101 -ac_cclib=hush3 -ac_script=76a9145eb10cf64f2bab1b457f1f25e658526155928fac88ac & +./komodod -pubkey=$pubkey -ac_name=ZEXO -ac_supply=100000000 -ac_reward=1478310502 -ac_halving=525600 -ac_cc=42 -ac_ccenable=236 -ac_perc=77700 -ac_staked=93 -ac_pubkey=02713bd85e054db923694b6b7a85306264edf4d6bd6d331814f2b40af444b3ebbc -ac_public=1 -addnode=80.240.17.222 & +./komodod -pubkey=$pubkey -ac_name=K64 -ac_supply=64000777 -ac_reward=0 -ac_staked=10 -addnode=18.197.20.211 & diff --git a/src/cc/CCOracles.h b/src/cc/CCOracles.h index 7f952e5f5..2f2b702f4 100644 --- a/src/cc/CCOracles.h +++ b/src/cc/CCOracles.h @@ -21,12 +21,13 @@ bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format); +std::string OracleFund(int64_t txfee,uint256 oracletxid); std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee); std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount); std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector data); - // CCcustom -UniValue OracleDataSamples(uint256 reforacletxid,uint256 batontxid,int32_t num); +UniValue OracleDataSample(uint256 reforacletxid,uint256 txid); +UniValue OracleDataSamples(uint256 reforacletxid,char* batonaddr,int32_t num); UniValue OracleInfo(uint256 origtxid); UniValue OraclesList(); diff --git a/src/cc/CCPayments.h b/src/cc/CCPayments.h index effa837f2..ac5f22c47 100644 --- a/src/cc/CCPayments.h +++ b/src/cc/CCPayments.h @@ -22,7 +22,7 @@ #include #define PAYMENTS_TXFEE 10000 -#define PAYMENTS_MERGEOFSET 10 // 100? +#define PAYMENTS_MERGEOFSET 60 // 1H extra. extern std::vector > vAddressSnapshot; extern int32_t lastSnapShotHeight; diff --git a/src/cc/CCPrices.h b/src/cc/CCPrices.h index 238131d59..3779111a6 100644 --- a/src/cc/CCPrices.h +++ b/src/cc/CCPrices.h @@ -38,8 +38,12 @@ extern CScript KOMODO_EARLYTXID_SCRIPTPUB; #define PRICES_MMM (KOMODO_MAXPRICES * 7) // 0011 1000 0000 0000 #define PRICES_DDD (KOMODO_MAXPRICES * 8) // 0100 0000 0000 0000 -#define PRICES_NORMFACTOR (int64_t)(SATOSHIDEN) -#define PRICES_POINTFACTOR (int64_t)10000 +//#define PRICES_NORMFACTOR (int64_t)(SATOSHIDEN) +//#define PRICES_POINTFACTOR (int64_t)10000 + +#define PRICES_REVSHAREDUST 10000 +#define PRICES_SUBREVSHAREFEE(amount) ((amount) * 199 / 200) // revshare fee percentage == 0.005 +#define PRICES_MINAVAILFUNDFRACTION 0.1 // leveraged bet limit < fund fraction bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); @@ -52,6 +56,7 @@ UniValue PricesCashout(int64_t txfee,uint256 bettxid); UniValue PricesInfo(uint256 bettxid,int32_t refheight); UniValue PricesList(uint32_t filter, CPubKey mypk); UniValue PricesGetOrderbook(); +UniValue PricesRefillFund(int64_t amount); #endif diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 75d804df5..1d8cf669e 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -59,6 +59,8 @@ one other technical note is that komodod has the insight-explorer extensions bui #define SMALLVAL 0.000000000000001 #define SATOSHIDEN ((uint64_t)100000000L) #define dstr(x) ((double)(x) / SATOSHIDEN) +#define CCDISABLEALL memset(ASSETCHAINS_CCDISABLES,1,sizeof(ASSETCHAINS_CCDISABLES)) +#define CCENABLE(x) ASSETCHAINS_CCDISABLES[((uint8_t)x)] = 0 #ifndef _BITS256 #define _BITS256 @@ -251,7 +253,7 @@ void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, c int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode); bool IsCCInput(CScript const& scriptSig); -bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime); +bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime,int64_t &actualtxfee); int32_t unstringbits(char *buf,uint64_t bits); uint64_t stringbits(char *str); uint256 revuint256(uint256 txid); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 023858dc2..5de5ed0db 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -150,7 +150,7 @@ bool IsCCInput(CScript const& scriptSig) return true; } -bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime) +bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime, int64_t &actualtxfee) { LOCK(mempool.cs); CCoinsView dummy; @@ -159,9 +159,10 @@ bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_ CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); view.SetBackend(viewMemPool); valuein = view.GetValueIn(height,&interest,tx,blocktime); - if ( valuein-tx.GetValueOut() > txfee ) + actualtxfee = valuein-tx.GetValueOut(); + if ( actualtxfee > txfee ) { - //fprintf(stderr, "txfee.%li vs txfee.%li\n", valuein-tx.GetValueOut(), txfee); + //fprintf(stderr, "actualtxfee.%li vs txfee.%li\n", actualtxfee, txfee); return false; } return true; diff --git a/src/cc/Makefile_custom b/src/cc/Makefile_custom new file mode 100755 index 000000000..79219ec96 --- /dev/null +++ b/src/cc/Makefile_custom @@ -0,0 +1,38 @@ +SHELL = /bin/sh +CC = gcc +CC_DARWIN = g++-8 +CC_WIN = x86_64-w64-mingw32-gcc-posix +CFLAGS_DARWIN = -DBUILD_CUSTOMCC -std=c++11 -arch x86_64 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib +CFLAGS = -Wno-write-strings -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared +CFLAGS_WIN = -Wno-write-strings -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../../depends/x86_64-w64-mingw32/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared +DEBUGFLAGS = -O0 -D _DEBUG +RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program +$(info $(OS)) +OS := $(shell uname -s) +$(info $(OS)) +TARGET = customcc.so +TARGET_DARWIN = customcc.dylib +TARGET_WIN = customcc.dll +SOURCES = cclib.cpp +#HEADERS = $(shell echo ../cryptoconditions/include/*.h) -I/usr/local/Cellar/gcc\@8/8.3.0/include/c++/8.3.0/ + +all: $(TARGET) + +$(TARGET): $(SOURCES) + $(info Building cclib to src/) +ifeq ($(OS),Darwin) + $(CC_DARWIN) $(CFLAGS_DARWIN) $(DEBUGFLAGS) -o $(TARGET_DARWIN) -c $(SOURCES) + cp $(TARGET_DARWIN) ../libcc.dylib +else ifeq ($(HOST),x86_64-w64-mingw32) + $(info WINDOWS) + $(CC_WIN) $(CFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) -c $(SOURCES) + cp $(TARGET_WIN) ../libcc.dll +#else ifeq ($(WIN_HOST),True) - todo: pass ENV var from build.sh if WIN host +else + $(info LINUX) + $(CC) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) -c $(SOURCES) + cp $(TARGET) ../libcc.so +endif + +clean: + rm -rf $(TARGET) diff --git a/src/cc/Makefile_rogue b/src/cc/Makefile_rogue index baf8767aa..3b2f65e00 100644 --- a/src/cc/Makefile_rogue +++ b/src/cc/Makefile_rogue @@ -1,6 +1,6 @@ SHELL = /bin/sh CC = gcc -CC_DARWIN = g++-6 +CC_DARWIN = g++-8 CC_WIN = x86_64-w64-mingw32-gcc-posix CFLAGS_DARWIN = -DBUILD_ROGUE -std=c++11 -arch x86_64 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib CFLAGS = -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared @@ -14,7 +14,7 @@ TARGET = librogue.so TARGET_DARWIN = librogue.dylib TARGET_WIN = librogue.dll SOURCES = cclib.cpp -#HEADERS = $(shell echo ../cryptoconditions/include/*.h) -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/ +#HEADERS = $(shell echo ../cryptoconditions/include/*.h) -I/usr/local/Cellar/gcc\@8/8.3.0/include/c++/8.3.0/ all: $(TARGET) diff --git a/src/cc/crypto777/OS_portable.h b/src/cc/crypto777/OS_portable.h index d6abc98c5..e0b185cbc 100755 --- a/src/cc/crypto777/OS_portable.h +++ b/src/cc/crypto777/OS_portable.h @@ -206,12 +206,12 @@ void OS_nonportable_randombytes(uint8_t *x,long xlen); int32_t OS_nonportable_init(); #endif -void OS_portable_init(); -void OS_init(); +void OS_portable_init(void); +void OS_init(void); int32_t sortds(double *buf,uint32_t num,int32_t size); int32_t revsortds(double *buf,uint32_t num,int32_t size); -double OS_portable_milliseconds(); +double OS_portable_milliseconds(void); void OS_portable_randombytes(uint8_t *x,long xlen); int32_t OS_portable_truncate(char *fname,long filesize); char *OS_portable_path(char *str); @@ -256,7 +256,7 @@ int32_t OS_removefile(char *fname,int32_t scrubflag); void *OS_mapfile(char *fname,long *filesizep,int32_t enablewrite); int32_t OS_releasemap(void *ptr,unsigned long filesize); -double OS_milliseconds(); +double OS_milliseconds(void); void OS_randombytes(uint8_t *x,long xlen); //int32_t OS_syncmap(struct OS_mappedptr *mp,long len); @@ -309,11 +309,11 @@ char *uppercase_str(char *buf,char *str); char *lowercase_str(char *buf,char *str); int32_t strsearch(char *strs[],int32_t num,char *name); int32_t OS_getline(int32_t waitflag,char *line,int32_t max,char *dispstr); -int32_t sort64s(uint64_t *buf,uint32_t num,int32_t size); -int32_t revsort64s(uint64_t *buf,uint32_t num,int32_t size); +void sort64s(uint64_t *buf,uint32_t num,int32_t size); +void revsort64s(uint64_t *buf,uint32_t num,int32_t size); int decode_base32(uint8_t *token,uint8_t *tokenstr,int32_t len); int init_base32(char *tokenstr,uint8_t *token,int32_t len); -char *OS_mvstr(); +char *OS_mvstr(void); long _stripwhite(char *buf,int accept); int32_t is_DST(int32_t datenum); @@ -381,7 +381,7 @@ double dxblend(double *destp,double val,double decay); uint64_t calc_ipbits(char *ip_port); void expand_ipbits(char *ipaddr,uint64_t ipbits); void escape_code(char *escaped,char *str); -void SaM_PrepareIndices(); +void SaM_PrepareIndices(void); // iguana_serdes.c #ifndef IGUANA_LOG2PACKETSIZE diff --git a/src/cc/dapps/cJSON.c b/src/cc/dapps/cJSON.c index 62f46444c..e1d7801a1 100644 --- a/src/cc/dapps/cJSON.c +++ b/src/cc/dapps/cJSON.c @@ -40,7 +40,10 @@ long stripquotes(char *str) return(0); len = strlen(str); if ( str[0] == '"' && str[len-1] == '"' ) - str[len-1] = 0, offset = 1; + { + str[len-1] = 0; + offset = 1; + } else offset = 0; return(offset); } diff --git a/src/cc/dapps/zmigrate.c b/src/cc/dapps/zmigrate.c index 33d776650..f7d9e3feb 100644 --- a/src/cc/dapps/zmigrate.c +++ b/src/cc/dapps/zmigrate.c @@ -315,6 +315,8 @@ cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char { long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[256]; sprintf(fname,"/tmp/zmigrate.%s",method); + //if ( (acname == 0 || acname[0] == 0) && strcmp(refcoin,"KMD") != 0 ) + // acname = refcoin; if ( acname[0] != 0 ) { if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 ) @@ -938,7 +940,508 @@ int32_t have_pending_opid(char *coinstr,int32_t clearresults) return(pending); } +int64_t utxo_value(char *refcoin,char *srcaddr,bits256 txid,int32_t v) +{ + cJSON *txjson,*vouts,*vout,*sobj,*array; int32_t numvouts,numaddrs; int64_t val,value = 0; char *addr,str[65]; + srcaddr[0] = 0; + if ( (txjson= get_rawtransaction(refcoin,"",txid)) != 0 ) + { + if ( (vouts= jarray(&numvouts,txjson,"vout")) != 0 && v < numvouts ) + { + vout = jitem(vouts,v); + if ( (val= jdouble(vout,"value")*SATOSHIDEN) != 0 && (sobj= jobj(vout,"scriptPubKey")) != 0 ) + { + if ( (array= jarray(&numaddrs,sobj,"addresses")) != 0 && numaddrs == 1 && (addr= jstri(array,0)) != 0 && strlen(addr) < 64 ) + { + strcpy(srcaddr,addr); + value = val; + } else printf("couldnt get unique address for %s/%d\n",bits256_str(str,txid),v); + } else printf("error getting value for %s/v%d\n",bits256_str(str,txid),v); + } + } + return(value); +} + +int32_t verify_vin(char *refcoin,bits256 txid,int32_t v,char *cmpaddr) +{ + cJSON *txjson,*vins,*vin; int32_t numvins; char vinaddr[64],str[65]; + vinaddr[0] = 0; + if ( (txjson= get_rawtransaction(refcoin,"",txid)) != 0 ) + { + if ( (vins= jarray(&numvins,txjson,"vin")) != 0 && v < numvins ) + { + vin = jitem(vins,v); + if ( utxo_value(refcoin,vinaddr,jbits256(vin,"txid"),jint(vin,"vout")) > 0 && strcmp(vinaddr,cmpaddr) == 0 ) + return(0); + printf("mismatched vinaddr.(%s) vs %s\n",vinaddr,cmpaddr); + } + } + return(-1); +} + +int32_t txid_in_vins(char *refcoin,bits256 txid,bits256 cmptxid) +{ + cJSON *txjson,*vins,*vin; int32_t numvins,v,vinvout; bits256 vintxid; char str[65]; + if ( (txjson= get_rawtransaction(refcoin,"",txid)) != 0 ) + { + if ( (vins= jarray(&numvins,txjson,"vin")) != 0 ) + { + for (v=0; vrefundvalue < 0 ) + return(-1); + // change "kmd" -> %s, tolowerstr(refcoin) + sprintf(url,"https://kmd.explorer.dexstats.info/insight-api-komodo/addr/%s",item->destaddr); + if ( (retstr= send_curl(url,"/tmp/itemvalid")) != 0 ) + { + if ( (curljson= cJSON_Parse(retstr)) != 0 ) + { + if ( (txids= jarray(&numtxids,curljson,"transactions")) != 0 ) + { + for (i=0; itxid) == 0 ) + { + printf("found item->txid %s inside %s\n",bits256_str(str,item->txid),bits256_str(str2,txid)); + item->approved = 1; + break; + } + } + } + free_json(curljson); + } + printf("%s\n",retstr); + free(retstr); + } + if ( item->approved != 0 ) + return(1); + *waitingp = item->refundvalue; + return(-1); +} + +void scan_claims(int32_t issueflag,char *refcoin,int32_t batchid) +{ + char str[65]; int32_t i,num,numstolen=0,numcandidates=0,numinvalids=0,numrefunded=0,numwaiting=0; struct claimitem *item; int64_t batchmin,batchmax,waiting,refunded,possiblerefund=0,possiblestolen = 0,invalidsum=0,totalrefunded=0,waitingsum=0; + if ( batchid == 0 ) + { + batchmin = 0; + batchmax = 7 * SATOSHIDEN; + } + else if ( batchid == 1 ) + { + batchmin = 7 * SATOSHIDEN; + batchmax = 777 * SATOSHIDEN; + } + else if ( batchid == 2 ) + { + batchmin = 1;//777 * SATOSHIDEN; + batchmax = 5000 * SATOSHIDEN; + } + else if ( batchid == 3 ) + { + batchmin = 1;//117777 * SATOSHIDEN; + batchmax = 10000000 * SATOSHIDEN; + } + for (i=0; irefundvalue < batchmin || item->refundvalue >= batchmax ) + continue; + printf("check.%d %s %.8f vs refund %.8f -> %s\n",batchid,item->oldaddr,dstr(item->total),dstr(item->refundvalue),item->destaddr); + if ( itemvalid(refcoin,&refunded,&waiting,item) < 0 ) + { + if ( refunded != 0 ) + { + numrefunded++; + totalrefunded += refunded; + } + else if ( waiting != 0 ) + { + numwaiting++; + waitingsum += waiting; + } + else + { + invalidsum += item->refundvalue; + numinvalids++; + } + continue; + } + if ( item->total > item->refundvalue*1.1 + 10*SATOSHIDEN ) + { + printf("possible.%d stolen %s %.8f vs refund %.8f -> %.8f\n",batchid,item->oldaddr,dstr(item->total),dstr(item->refundvalue),dstr(item->total)-dstr(item->refundvalue)); + numstolen++; + possiblestolen += (item->total - item->refundvalue); + item->approved = 0; + } + else + { + printf("candidate.%d %s %.8f vs refund %.8f -> %s\n",batchid,item->oldaddr,dstr(item->total),dstr(item->refundvalue),item->destaddr); + numcandidates++; + possiblerefund += item->refundvalue; + } + } + printf("batchid.%d TOTAL exposure %d %.8f, possible refund %d %.8f, invalids %d %.8f, numrefunded %d %.8f, waiting %d %.8f\n",batchid,numstolen,dstr(possiblestolen),numcandidates,dstr(possiblerefund),numinvalids,dstr(invalidsum),numrefunded,dstr(totalrefunded),numwaiting,dstr(waitingsum)); + for (i=num=0; iapproved != 0 ) + { + printf("%d.%d: approved.%d %s %.8f vs refund %.8f -> %s\n",i,num,batchid,item->oldaddr,dstr(item->total),dstr(item->refundvalue),item->destaddr); + num++; + if ( issueflag != 0 ) + { + static FILE *fp; char cmd[1024]; + if ( fp == 0 ) + fp = fopen("refund.log","wb"); + genrefund(cmd,refcoin,item->txid,item->destaddr,item->refundvalue); + if ( fp != 0 ) + { + fprintf(fp,"%s,%s,%s,%s,%s,%.8f,%s\n",item->username,refcoin,bits256_str(str,item->txid),item->oldaddr,item->destaddr,dstr(item->refundvalue),cmd); + fflush(fp); + } + memset(&SECONDVIN,0,sizeof(SECONDVIN)); + SECONDVOUT = 1; +//printf(">>>>>>>>>>>>>>>>>> getchar after (%s)\n",cmd); +//getchar(); + } + } + } +} + +int32_t update_claimvalue(int32_t *disputedp,char *addr,int64_t amount,bits256 txid) +{ + int32_t i; struct claimitem *item; + *disputedp = 0; + for (i=0; irefundvalue = amount; + if ( bits256_nonz(item->txid) != 0 ) + printf("disputed.%d (%s) %s claimed %.8f vs %.8f\n",item->disputed,item->username,addr,dstr(item->total),dstr(amount)); + item->txid = txid; + if ( item->disputed != 0 ) + *disputedp = 1; + return(i); + } + } + return(-1); +} + +int64_t update_claimstats(char *username,char *oldaddr,char *destaddr,int64_t amount) +{ + int32_t i; struct claimitem *item; + printf("claim user.(%s) (%s) -> (%s) %.8f\n",username,oldaddr,destaddr,dstr(amount)); + for (i=0; idestaddr) != 0 )//|| strcmp(username,item->username) != 0 ) + { + item->disputed++; + printf("disputed.%d claim.%-4d: (%36s -> [%36s] %s) vs. (%36s -> [%36s] %s) \n",item->disputed,i,oldaddr,destaddr,username,item->oldaddr,item->destaddr,item->username); + } + item->numutxos++; + item->total += amount; + return(amount); + } + } + item = &CLAIMS[NUM_CLAIMS++]; + item->total = amount; + item->numutxos = 1; + strncpy(item->oldaddr,oldaddr,sizeof(item->oldaddr)); + strncpy(item->destaddr,destaddr,sizeof(item->destaddr)); + strncpy(item->username,username,sizeof(item->username)); + printf("new claim.%-4d: %36s %16.8f -> %36s %s\n",NUM_CLAIMS,oldaddr,dstr(amount),destaddr,username); + return(amount); +} + +int32_t update_addrstats(char *srcaddr,int64_t amount) +{ + int32_t i; struct addritem *item; + for (i=0; itotal = amount; + item->numutxos = 1; + strcpy(item->addr,srcaddr); + printf("%d new address %s\n",NUM_ADDRESSES,srcaddr); + return(-1); +} + +int64_t sum_of_vins(char *refcoin,int32_t *totalvinsp,int32_t *uniqaddrsp,bits256 txid) +{ + cJSON *txjson,*vins,*vin; char str[65],srcaddr[64]; int32_t i,numarray; int64_t amount,total = 0; + if ( (txjson= get_rawtransaction(refcoin,"",txid)) != 0 ) + { + if ( (vins= jarray(&numarray,txjson,"vin")) != 0) + { + for (i=0; i 0 ) + { + printf("%d.(%s)\n",numlines,buf); + str = buf; + n = i = 0; + memset(fields,0,sizeof(fields)); + while ( *str != 0 ) + { + if ( *str == ',' || *str == '\n' || *str == '\r' ) + { + fields[n][i] = 0; + i = 0; + if ( n > 1 ) + { + printf("(%16s) ",fields[n]); + } + n++; + if ( *str == '\n' || *str == '\r' ) + break; + } + if ( *str == ',' || *str == ' ' ) + str++; + else fields[n][i++] = *str++; + } + printf("%s\n",fields[1]); + total += update_claimstats(fields[1],fields[3],fields[5 + (strcmp("KMD",refcoin)==0)],atof(fields[4])*SATOSHIDEN + 0.0000000049); + numlines++; + } + fclose(fp); + } + printf("total claims %.8f\n",dstr(total)); +} + int32_t main(int32_t argc,char **argv) +{ + char *coinstr,*acstr,*addr,buf[64],srcaddr[64],str[65]; cJSON *retjson,*item; int32_t i,n,disputed,numdisputed,numsmall=0,numpayouts=0,numclaims=0,num=0,totalvins=0,uniqaddrs=0; int64_t amount,total = 0,total2 = 0,payout,maxpayout,smallpayout=0,totalpayout = 0,totaldisputed = 0,totaldisputed2 = 0,fundingamount = 0; + if ( argc != 2 ) + { + printf("argc needs to be 2: coin\n"); + return(-1); + } + if ( strcmp(argv[1],"KMD") == 0 ) + { + REFCOIN_CLI = "./komodo-cli"; + coinstr = clonestr("KMD"); + acstr = ""; + } + else if ( strcmp(argv[1],"CHIPS") == 0 ) + { + REFCOIN_CLI = "./chips-cli"; + coinstr = clonestr("CHIPS"); + acstr = ""; + } + else + { + sprintf(buf,"./komodo-cli -ac_name=%s",argv[1]); + REFCOIN_CLI = clonestr(buf); + coinstr = clonestr(argv[1]); + acstr = coinstr; + } + if ( 1 )//strcmp(coinstr,"KMD") == 0 ) + { + sprintf(buf,"%s-Claims.csv",coinstr); + reconcile_claims(coinstr,buf); + for (i=0; i 0 ) + { + for (i=0; i fundingamount ) + { + fundingamount = amount; + SECONDVIN = jbits256(item,"txid"); + SECONDVOUT = jint(item,"vout"); + printf("set SECONDVIN to %s/v%d %.8f\n",bits256_str(str,SECONDVIN),SECONDVOUT,dstr(amount)); + } + continue; + } + if ( strcmp(coinstr,"KMD") == 0 && verify_vin(coinstr,jbits256(item,"txid"),0,"R9JCEd6xnCxNUSpLrHEWvzPSh7CNXm7z75") < 0 ) + { + printf("WARNING: imposter dust detected! %s\n",bits256_str(str,jbits256(item,"txid"))); + continue; + } + else if ( strcmp(coinstr,"KMD") != 0 && verify_vin(coinstr,jbits256(item,"txid"),0,"R9MUnxXijovvSeT9sFuUX23TiFtVvZEGjT") < 0 ) + { + printf("WARNING: imposter dust detected! %s\n",bits256_str(str,jbits256(item,"txid"))); + continue; + } + amount = (utxo_value(coinstr,srcaddr,jbits256(item,"txid"),0) - 20000) * SATOSHIDEN; + //printf("%d: %s claimvalue %.8f\n",num,srcaddr,dstr(amount)); + num++; + total2 += amount; + if ( update_claimvalue(&disputed,srcaddr,amount,jbits256(item,"txid")) >= 0 ) + { + if ( disputed != 0 ) + { + totaldisputed2 += amount; + numdisputed++; + } + else + { + numclaims++; + total += amount; + } + } + } + } + } + free_json(retjson); + printf("remaining refunds.%d %.8f, numclaims.%d %.8f, numdisputed.%d %.8f\n",num,dstr(total2),numclaims,dstr(total),numdisputed,dstr(totaldisputed2)); + } + //scan_claims(0,coinstr,0); + //scan_claims(0,coinstr,1); + //scan_claims(0,coinstr,2); + scan_claims(1,coinstr,3); + } + else if ( (retjson= get_listunspent(coinstr,acstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(retjson)) > 0 ) + { + for (i=0; i= SATOSHIDEN ) + { + payout = ADDRESSES[i].total / SATOSHIDEN; + if ( payout > maxpayout ) + maxpayout = payout; + totalpayout += payout; + numpayouts++; + //if ( payout >= 7 ) + //{ + // numsmall++; + //smallpayout += payout; + genpayout(coinstr,ADDRESSES[i].addr,payout); + //} + //printf("%-4d: %-64s numutxos.%-4lld %llu\n",i,ADDRESSES[i].addr,ADDRESSES[i].numutxos,(long long)payout); + } + } + printf("num.%d total %.8f vs vintotal %.8f, totalvins.%d uniqaddrs.%d:%d totalpayout %llu maxpayout %llu numpayouts.%d numsmall.%d %llu\n",num,dstr(total),dstr(total2),totalvins,uniqaddrs,NUM_ADDRESSES,(long long)totalpayout,(long long)maxpayout,numpayouts,numsmall,(long long)smallpayout); + } +} + +int32_t zmigratemain(int32_t argc,char **argv) { char buf[1024],*zsaddr,*coinstr; if ( argc != 3 ) diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index a23a7b16c..c580753cf 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -78,8 +78,13 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) uint8_t ecode = cond->code[0]; if ( ASSETCHAINS_CCDISABLES[ecode] != 0 ) { - fprintf(stderr,"%s evalcode.%d %02x\n",txTo.GetHash().GetHex().c_str(),ecode,ecode); - return Invalid("disabled-code, -ac_ccenables didnt include this ecode"); + // check if a height activation has been set. + if ( mapHeightEvalActivate[ecode] == 0 || this->GetCurrentHeight() == 0 || mapHeightEvalActivate[ecode] > this->GetCurrentHeight() ) + { + fprintf(stderr,"%s evalcode.%d %02x\n",txTo.GetHash().GetHex().c_str(),ecode,ecode); + fprintf(stderr, "ac_ccactivateht: evalcode.%i activates at height.%i vs current height.%i\n", ecode, mapHeightEvalActivate[ecode], this->GetCurrentHeight()); + return Invalid("disabled-code, -ac_ccenables didnt include this ecode"); + } } std::vector vparams(cond->code+1, cond->code+cond->codeLength); if ( ecode >= EVAL_FIRSTUSER && ecode <= EVAL_LASTUSER ) diff --git a/src/cc/includes/curve25519.h b/src/cc/includes/curve25519.h index 19abe8d10..657fab4d0 100755 --- a/src/cc/includes/curve25519.h +++ b/src/cc/includes/curve25519.h @@ -48,7 +48,7 @@ bits320 crecip(const bits320 z); bits256 curve25519(bits256 mysecret,bits256 basepoint); void OS_randombytes(unsigned char *x,long xlen); bits256 rand256(int32_t privkeyflag); -bits256 curve25519_basepoint9(); +bits256 curve25519_basepoint9(void); bits256 curve25519_keypair(bits256 *pubkeyp); void vcalc_sha256(char hashstr[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len); diff --git a/src/cc/makecustom b/src/cc/makecustom index 154be4f31..7f1c789c9 100755 --- a/src/cc/makecustom +++ b/src/cc/makecustom @@ -1,6 +1,7 @@ #!/bin/sh -gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp -cp customcc.so ../libcc.so -cd .. -make -cd cc +if make -f Makefile_custom "$@"; then + echo CUSTOMCC BUILD SUCCESSFUL +else + echo CUSTOMCC BUILD FAILED + exit 1 +fi diff --git a/src/cc/oracles.cpp b/src/cc/oracles.cpp index a5d61d404..bdd01ccfa 100644 --- a/src/cc/oracles.cpp +++ b/src/cc/oracles.cpp @@ -92,10 +92,11 @@ vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format */ +extern int32_t komodo_currentheight(); +#define PUBKEY_SPOOFING_FIX_ACTIVATION 1563148800 +#define CC_MARKER_VALUE 10000 // start of consensus code - - CScript EncodeOraclesCreateOpRet(uint8_t funcid,std::string name,std::string description,std::string format) { CScript opret; uint8_t evalcode = EVAL_ORACLES; @@ -124,6 +125,7 @@ uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,s CScript EncodeOraclesOpRet(uint8_t funcid,uint256 oracletxid,CPubKey pk,int64_t num) { CScript opret; uint8_t evalcode = EVAL_ORACLES; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << pk << num); return(opret); } @@ -131,11 +133,12 @@ CScript EncodeOraclesOpRet(uint8_t funcid,uint256 oracletxid,CPubKey pk,int64_t uint8_t DecodeOraclesOpRet(const CScript &scriptPubKey,uint256 &oracletxid,CPubKey &pk,int64_t &num) { std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey,vopret); script = (uint8_t *)vopret.data(); if ( vopret.size() > 2 && script[0] == EVAL_ORACLES ) { - if (script[0] == EVAL_ORACLES && (script[1]== 'R' || script[1] == 'S') && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> oracletxid; ss >> pk; ss >> num)!=0) + if (script[0] == EVAL_ORACLES && (script[1]== 'R' || script[1] == 'S' || script[1] == 'F') && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> oracletxid; ss >> pk; ss >> num)!=0) return(f); else return(script[1]); } @@ -633,9 +636,17 @@ bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransactio else return(true); } +int32_t GetLatestTimestamp(int32_t height) +{ + return(komodo_heightstamp(height)); +} + bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { - uint256 txid,oracletxid,batontxid; uint64_t txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts; uint8_t *script; std::vector vopret,data; CScript scriptPubKey; CPubKey publisher; + uint256 oracletxid,batontxid; uint64_t txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts; int64_t amount; uint256 hashblock; + uint8_t *script; std::vector vopret,data; CPubKey publisher,tmppk,oraclespk; char tmpaddress[64],vinaddress[64],oraclesaddr[64]; + CTransaction tmptx; std::string name,desc,format; + numvins = tx.vin.size(); numvouts = tx.vout.size(); preventCCvins = preventCCvouts = -1; @@ -643,10 +654,11 @@ bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t return eval->Invalid("no vouts"); else { - txid = tx.GetHash(); GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); if ( vopret.size() > 2 ) - { + { + oraclespk=GetUnspendable(cp,0); + Getscriptaddress(oraclesaddr,CScript() << ParseHex(HexStr(oraclespk)) << OP_CHECKSIG); script = (uint8_t *)vopret.data(); switch ( script[1] ) { @@ -657,13 +669,45 @@ bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t // vout.n-1: opreturn with name and description and format for data return eval->Invalid("unexpected OraclesValidate for create"); break; - case 'R': // register + case 'F': // fund (activation on Jul 15th 2019 00:00) // vins.*: normal inputs + // vout.0: txfee to oracle CC address of users pubkey + // vout.1: change, if any + // vout.n-1: opreturn with createtxid, pubkey and amount + return eval->Invalid("unexpected OraclesValidate for create"); + break; + case 'R': // register + // vin.0: normal inputs + // vin.n-1: CC input from pubkeys oracle CC addres - to prove that register came from pubkey that is registred (activation on Jul 15th 2019 00:00) // vout.0: txfee tag to normal marker address // vout.1: baton CC utxo - // vout.2: change, if any + // vout.2: marker from oraclesfund tx to normal pubkey address (activation on Jul 15th 2019 00:00) + // vout.n-2: change, if any // vout.n-1: opreturn with createtxid, pubkey and price per data point - return eval->Invalid("unexpected OraclesValidate for register"); + if (GetLatestTimestamp(eval->GetCurrentHeight())>PUBKEY_SPOOFING_FIX_ACTIVATION) + { + if ((numvouts=tx.vout.size()) < 1 || DecodeOraclesOpRet(tx.vout[numvouts-1].scriptPubKey,oracletxid,tmppk,amount)!='R') + return eval->Invalid("invalid oraclesregister OP_RETURN data!"); + else if (myGetTransaction(oracletxid,tmptx,hashblock) == 0) + return eval->Invalid("invalid oraclescreate txid!"); + else if ((numvouts=tmptx.vout.size()) < 1 || DecodeOraclesCreateOpRet(tmptx.vout[numvouts-1].scriptPubKey,name,desc,format)!='C') + return eval->Invalid("invalid oraclescreate OP_RETURN data!"); + else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 ) + return eval->Invalid("vin.0 is normal for oraclescreate!"); + else if (ConstrainVout(tmptx.vout[0],0,oraclesaddr,txfee)==0) + return eval->Invalid("invalid marker for oraclescreate!"); + else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + return eval->Invalid("vin.0 is normal for oraclesregister!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 + || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE || !Getscriptaddress(vinaddress,tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].scriptPubKey) + || !GetCCaddress(cp,tmpaddress,tmppk) || strcmp(tmpaddress,vinaddress)!=0) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC for oraclesregister or pubkey not same as vin pubkey, register must be done from owner of pubkey that registers to oracle!!"); + else if (CCtxidaddr(tmpaddress,oracletxid).IsValid() && ConstrainVout(tx.vout[0],0,tmpaddress,txfee)==0) + return eval->Invalid("invalid marker for oraclesregister!"); + else if (!Getscriptaddress(tmpaddress,CScript() << ParseHex(HexStr(tmppk)) << OP_CHECKSIG) || ConstrainVout(tx.vout[2],0,tmpaddress,CC_MARKER_VALUE)==0) + return eval->Invalid("pubkey in OP_RETURN and in vout.2 not matching, register must be done from owner of pubkey that registers to oracle!"); + } + else return eval->Invalid("unexpected OraclesValidate for register"); break; case 'S': // subscribe // vins.*: normal inputs @@ -762,6 +806,45 @@ int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubK return(total); } +int64_t AddMyOraclesFunds(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 oracletxid) +{ + char coinaddr[64],funcid; int64_t nValue,tmpamount; uint256 tmporacletxid,txid,hashBlock,ignoretxid; int32_t numvouts,vout,ignorevin; + std::vector > unspentOutputs; CTransaction vintx; CPubKey tmppk; + + GetCCaddress(cp,coinaddr,pk); + SetCCunspents(unspentOutputs,coinaddr,true); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + nValue = it->second.satoshis; + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 && (numvouts=vintx.vout.size())>0) + { + if ((funcid=DecodeOraclesOpRet(vintx.vout[numvouts-1].scriptPubKey,tmporacletxid,tmppk,tmpamount))!=0 && funcid=='F' && tmppk==pk + && tmporacletxid==oracletxid && tmpamount==nValue && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout)==0) + { + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + return (nValue); + } + } else fprintf(stderr,"couldnt find transaction\n"); + } + + BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) + { + const CTransaction &txmempool = e.GetTx(); + const uint256 &hash = txmempool.GetHash(); + nValue=txmempool.vout[0].nValue; + + if ((funcid=DecodeOraclesOpRet(txmempool.vout[txmempool.vout.size()-1].scriptPubKey,tmporacletxid,tmppk,tmpamount))!=0 && funcid=='F' + && tmppk==pk && tmporacletxid==oracletxid && tmpamount==nValue && myIsutxo_spentinmempool(ignoretxid,ignorevin,hash,0)==0) + { + mtx.vin.push_back(CTxIn(hash,0,CScript())); + return (nValue); + } + } + return (0); +} + std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); @@ -802,10 +885,36 @@ std::string OracleCreate(int64_t txfee,std::string name,std::string description, return(""); } +std::string OracleFund(int64_t txfee,uint256 oracletxid) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,oraclespk; struct CCcontract_info *cp,C; + + if (GetLatestTimestamp(komodo_currentheight())evalcode,CC_MARKER_VALUE,mypk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('F',oracletxid,mypk,CC_MARKER_VALUE))); + } + CCerror = strprintf("error adding normal inputs"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); +} + std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64]; + CPubKey mypk,markerpubkey,batonpk,oraclespk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64]; + cp = CCinit(&C,EVAL_ORACLES); if ( txfee == 0 ) txfee = 10000; @@ -816,12 +925,20 @@ std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee) return(""); } mypk = pubkey2pk(Mypubkey()); + oraclespk = GetUnspendable(cp,0); batonpk = OracleBatonPk(batonaddr,cp); markerpubkey = CCtxidaddr(markeraddr,oracletxid); - if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 ) + if (AddNormalinputs(mtx,mypk,3*txfee,4)) { + if (GetLatestTimestamp(komodo_currentheight())>PUBKEY_SPOOFING_FIX_ACTIVATION && AddMyOraclesFunds(cp,mtx,mypk,oracletxid)!=CC_MARKER_VALUE) + { + CCerror = strprintf("error adding inputs from your Oracles CC address, please fund it first with oraclesfund rpc!"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk)); + if (GetLatestTimestamp(komodo_currentheight())>PUBKEY_SPOOFING_FIX_ACTIVATION) mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('R',oracletxid,mypk,datafee))); } CCerror = strprintf("error adding normal inputs"); @@ -929,39 +1046,97 @@ UniValue OracleFormat(uint8_t *data,int32_t datalen,char *format,int32_t formatl { str[0] = 0; j = oracle_format(&hash,&val,str,format[i],data,j,datalen); + obj.push_back(str); if ( j < 0 ) break; - obj.push_back(str); if ( j >= datalen ) break; } - return(str); + return(obj); } -UniValue OracleDataSamples(uint256 reforacletxid,uint256 batontxid,int32_t num) +UniValue OracleDataSample(uint256 reforacletxid,uint256 txid) { - UniValue result(UniValue::VOBJ),b(UniValue::VARR); CTransaction tx,oracletx; uint256 hashBlock,btxid,oracletxid; - CPubKey pk; std::string name,description,format; int32_t numvouts,n=0; std::vector data; char str[67], *formatstr = 0; + UniValue result(UniValue::VOBJ); CTransaction tx,oracletx; uint256 hashBlock,btxid,oracletxid; std::string error; + CPubKey pk; std::string name,description,format; int32_t numvouts; std::vector data; char str[67], *formatstr = 0; result.push_back(Pair("result","success")); if ( GetTransaction(reforacletxid,oracletx,hashBlock,false) != 0 && (numvouts=oracletx.vout.size()) > 0 ) { if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' ) { - while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 ) + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 ) { if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid ) + { + if ( (formatstr= (char *)format.c_str()) == 0 ) + formatstr = (char *)""; + result.push_back(Pair("txid",uint256_str(str,txid))); + result.push_back(Pair("data",OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size()))); + return(result); + } + else error="invalid data tx"; + } + else error="cannot find data txid"; + } + else error="invalid oracles txid"; + } + else error="cannot find oracles txid"; + result.push_back(Pair("result","error")); + result.push_back(Pair("error",error)); + return(result); +} + +UniValue OracleDataSamples(uint256 reforacletxid,char* batonaddr,int32_t num) +{ + UniValue result(UniValue::VOBJ),b(UniValue::VARR); CTransaction tx,oracletx; uint256 txid,hashBlock,btxid,oracletxid; + CPubKey pk; std::string name,description,format; int32_t numvouts,n=0,vout; std::vector data; char *formatstr = 0; + std::vector > addressIndex; int64_t nValue; + + result.push_back(Pair("result","success")); + if ( GetTransaction(reforacletxid,oracletx,hashBlock,false) != 0 && (numvouts=oracletx.vout.size()) > 0 ) + { + if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' ) + { + BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) + { + const CTransaction &txmempool = e.GetTx(); + const uint256 &hash = txmempool.GetHash(); + if ((numvouts=txmempool.vout.size())>0 && DecodeOraclesData(txmempool.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid ) { if ( (formatstr= (char *)format.c_str()) == 0 ) formatstr = (char *)""; - UniValue a(UniValue::VARR); - a.push_back(OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size())); - a.push_back(uint256_str(str,batontxid)); + UniValue a(UniValue::VOBJ); + a.push_back(Pair("txid",hash.GetHex())); + a.push_back(Pair("data",OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size()))); b.push_back(a); - batontxid = btxid; if ( ++n >= num && num != 0) break; - } else break; + } + } + SetCCtxids(addressIndex,batonaddr,true); + if (addressIndex.size()>0) + { + for (std::vector >::const_iterator it=addressIndex.end()-1; it!=addressIndex.begin(); it--) + { + txid=it->first.txhash; + vout = (int32_t)it->first.index; + nValue = (int64_t)it->second; + if (vout==1 && nValue==10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 ) + { + if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid ) + { + if ( (formatstr= (char *)format.c_str()) == 0 ) + formatstr = (char *)""; + UniValue a(UniValue::VOBJ); + a.push_back(Pair("txid",txid.GetHex())); + a.push_back(Pair("data",OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size()))); + b.push_back(a); + if ( ++n >= num && num != 0) + break; + } + } + } } } } @@ -972,10 +1147,12 @@ UniValue OracleDataSamples(uint256 reforacletxid,uint256 batontxid,int32_t num) UniValue OracleInfo(uint256 origtxid) { UniValue result(UniValue::VOBJ),a(UniValue::VARR); - std::vector > unspentOutputs; + std::vector > unspentOutputs; int32_t height; CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; + CTransaction tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector data; + std::map> publishers; + cp = CCinit(&C,EVAL_ORACLES); CCtxidaddr(markeraddr,origtxid); if ( GetTransaction(origtxid,tx,hashBlock,false) == 0 ) @@ -999,28 +1176,38 @@ UniValue OracleInfo(uint256 origtxid) for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; - if ( GetTransaction(txid,regtx,hashBlock,false) != 0 ) + height = (int32_t)it->second.blockHeight; + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && + DecodeOraclesOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid ) { - if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid ) + if (publishers.find(pk)==publishers.end() || height>publishers[pk].second) { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("publisher",pubkey33_str(str,(uint8_t *)pk.begin()))); - Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey); - batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data); - obj.push_back(Pair("baton",batonaddr)); - obj.push_back(Pair("batontxid",uint256_str(str,batontxid))); - funding = LifetimeOraclesFunds(cp,oracletxid,pk); - sprintf(numstr,"%.8f",(double)funding/COIN); - obj.push_back(Pair("lifetime",numstr)); - funding = AddOracleInputs(cp,mtx,oracletxid,pk,0,0); - sprintf(numstr,"%.8f",(double)funding/COIN); - obj.push_back(Pair("funds",numstr)); - sprintf(numstr,"%.8f",(double)datafee/COIN); - obj.push_back(Pair("datafee",numstr)); - a.push_back(obj); + publishers[pk].first=txid; + publishers[pk].second=height; } } } + for (std::map>::iterator it = publishers.begin(); it != publishers.end(); ++it) + { + if ( GetTransaction(it->second.first,tx,hashBlock,false) != 0 && DecodeOraclesOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R') + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("publisher",pubkey33_str(str,(uint8_t *)pk.begin()))); + Getscriptaddress(batonaddr,tx.vout[1].scriptPubKey); + batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data); + obj.push_back(Pair("baton",batonaddr)); + obj.push_back(Pair("batontxid",uint256_str(str,batontxid))); + funding = LifetimeOraclesFunds(cp,oracletxid,pk); + sprintf(numstr,"%.8f",(double)funding/COIN); + obj.push_back(Pair("lifetime",numstr)); + funding = AddOracleInputs(cp,mtx,oracletxid,pk,0,0); + sprintf(numstr,"%.8f",(double)funding/COIN); + obj.push_back(Pair("funds",numstr)); + sprintf(numstr,"%.8f",(double)datafee/COIN); + obj.push_back(Pair("datafee",numstr)); + a.push_back(obj); + } + } result.push_back(Pair("registered",a)); } } @@ -1045,4 +1232,3 @@ UniValue OraclesList() } return(result); } - diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 5d6383c29..b6e85480c 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -137,6 +137,26 @@ uint8_t DecodePaymentsMergeOpRet(CScript scriptPubKey,uint256 &checktxid) return(0); } +CScript EncodePaymentsReleaseOpRet(uint256 checktxid, int64_t amountReleased) +{ + CScript opret; uint8_t evalcode = EVAL_PAYMENTS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'R' << checktxid << amountReleased); + return(opret); +} + +uint8_t DecodePaymentsReleaseOpRet(CScript scriptPubKey,uint256 &checktxid,int64_t &amountReleased) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> checktxid; ss >> amountReleased) != 0 ) + { + if ( e == EVAL_PAYMENTS && f == 'R' ) + return(f); + } + return(0); +} + CScript EncodePaymentsOpRet(int32_t lockedblocks,int32_t minrelease,int64_t totalallocations,std::vector txidoprets) { CScript opret; uint8_t evalcode = EVAL_PAYMENTS; @@ -200,7 +220,6 @@ uint8_t DecodePaymentsTokensOpRet(CScript scriptPubKey,int32_t &lockedblocks,int int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr, CScript &ccopret) { char destaddr[64]; - //if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) if ( getCCopret(tx.vout[v].scriptPubKey, ccopret) ) { if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && (cmpaddr[0] == 0 || strcmp(destaddr,cmpaddr) == 0) ) @@ -209,22 +228,6 @@ int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t return(0); } -void pub2createtxid(char *str) -{ - int i,n; - char *rev; - n = (int32_t)strlen(str); - rev = (char *)malloc(n + 1); - for (i=0; i> &excludeScriptPubKeys, mpz_t &mpzTotalAllocations, std::vector &scriptPubKeys, std::vector &allocations) +{ + mpz_t mpzAllocation; int32_t i =0; + for (int32_t j = bottom; j < vAddressSnapshot.size(); j++) + { + auto &address = vAddressSnapshot[j]; + CScript scriptPubKey = GetScriptForDestination(address.second); + bool skip = false; + // skip excluded addresses. + for ( auto skipkey : excludeScriptPubKeys ) + { + if ( scriptPubKey == CScript(skipkey.begin(), skipkey.end()) ) + skip = true; + } + if ( !skip ) + { + mpz_init(mpzAllocation); + i++; + //fprintf(stderr, "address: %s nValue.%li \n", CBitcoinAddress(address.second).ToString().c_str(), address.first); + scriptPubKeys.push_back(scriptPubKey); + allocations.push_back(address.first); + mpz_set_si(mpzAllocation,address.first); + mpz_add(mpzTotalAllocations,mpzTotalAllocations,mpzAllocation); + mpz_clear(mpzAllocation); + } + if ( i+bottom == top ) + break; // we reached top amount to pay, it can be less than this, if less address exist on chain, return the number we got. + } + return(i); +} + +int32_t payments_gettokenallocations(int32_t top, int32_t bottom, const std::vector> &excludeScriptPubKeys, uint256 tokenid, mpz_t &mpzTotalAllocations, std::vector &scriptPubKeys, std::vector &allocations) +{ + /* + - check tokenid exists. + - iterate tokenid address and extract all pubkeys, add to map. + - rewind to last notarized height for balances? see main.cpp: line# 660. + - convert balances to mpz_t and add up totalallocations + - sort the map into a vector, then convert to the correct output. + */ + return(0); +} + bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { - // one of two addresses - // change must go to 1of2 txidaddr - // change is/must be in vout[0] - // only 'F' or 1of2 txidaddr can be spent - // all vouts must match exactly - char temp[128], coinaddr[64]={0}, txidaddr[64]; std::string scriptpubkey; uint256 createtxid, blockhash, tokenid; CTransaction plantx; int8_t funcid=0, fixedAmount=0; - int32_t i,lockedblocks,minrelease; int64_t change,totalallocations; std::vector txidoprets; bool fHasOpret = false,fIsMerge = false; CPubKey txidpk,Paymentspk; - int32_t top,bottom=0,minimum=10000; std::vector> excludeScriptPubKeys; bool fFixedAmount = false; CScript ccopret; - mpz_t mpzTotalAllocations, mpzAllocation;; mpz_init(mpzTotalAllocations); - // user marker vout to get the createtxid - if ( tx.vout.size() == 1 ) + char temp[128], txidaddr[64]={0}; std::string scriptpubkey; uint256 createtxid, blockhash, tokenid; CTransaction plantx; int8_t funcid=0, fixedAmount=0; + int32_t i,lockedblocks,minrelease,blocksleft,dust = 0, top,bottom=0,minimum=10000; int64_t change,totalallocations,actualtxfee,amountReleased=0; std::vector txidoprets; bool fHasOpret = false,fIsMerge = false; CPubKey txidpk,Paymentspk; + std::vector> excludeScriptPubKeys; bool fFixedAmount = false; CScript ccopret; + mpz_t mpzTotalAllocations,mpzAllocation,mpzCheckamount; + mpz_init(mpzCheckamount); mpz_init(mpzTotalAllocations); + // Check change is in vout[0], and also fetch the ccopret to determine what type of tx this is. txidaddr is unknown, recheck this later. + if ( (change= IsPaymentsvout(cp,tx,0,txidaddr,ccopret)) != 0 && ccopret.size() > 2 ) { - if ( IsPaymentsvout(cp,tx,0,coinaddr,ccopret) != 0 && ccopret.size() > 2 && DecodePaymentsMergeOpRet(ccopret,createtxid) ) - { + // get the checktxid and the amount released if doing release tx. + if ( DecodePaymentsMergeOpRet(ccopret,createtxid) == 'M' ) fIsMerge = true; - } else return(eval->Invalid("not enough vouts")); - } - else if ( tx.vout.back().scriptPubKey[0] == OP_RETURN ) - { - scriptpubkey = HexStr(tx.vout[tx.vout.size()-2].scriptPubKey.begin()+2, tx.vout[tx.vout.size()-2].scriptPubKey.end()-1); - fHasOpret = true; - } - else scriptpubkey = HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin()+2,tx.vout[tx.vout.size()-1].scriptPubKey.end()-1); - if ( !fIsMerge ) - { - strcpy(temp, scriptpubkey.c_str()); - pub2createtxid(temp); - createtxid = Parseuint256(temp); - } - //printf("createtxid.%s\n",createtxid.ToString().c_str()); + else if ( DecodePaymentsReleaseOpRet(ccopret,createtxid,amountReleased) != 'R' ) + return(eval->Invalid("could not decode ccopret")); + mpz_set_si(mpzCheckamount,amountReleased); + } else return(eval->Invalid("could not decode ccopret")); // use the createtxid to fetch the tx and all of the plans info. if ( myGetTransaction(createtxid,plantx,blockhash) != 0 && plantx.vout.size() > 0 ) @@ -297,25 +328,30 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return(eval->Invalid("minimum must be over 10000")); Paymentspk = GetUnspendable(cp,0); txidpk = CCtxidaddr(txidaddr,createtxid); - GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk); + GetCCaddress1of2(cp,txidaddr,Paymentspk,txidpk); //fprintf(stderr, "lockedblocks.%i minrelease.%i totalallocations.%i txidopret1.%s txidopret2.%s\n",lockedblocks, minrelease, totalallocations, txidoprets[0].ToString().c_str(), txidoprets[1].ToString().c_str() ); - if ( !CheckTxFee(tx, PAYMENTS_TXFEE+1, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) + if ( !CheckTxFee(tx, PAYMENTS_TXFEE+1, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime, actualtxfee) ) return eval->Invalid("txfee is too high"); - // make sure change is in vout 0 and is paying to the contract address. - if ( (change= IsPaymentsvout(cp,tx,0,coinaddr,ccopret)) == 0 ) - return(eval->Invalid("change is in wrong vout or is wrong tx type")); - + // Check that the change vout is playing the txid address. + if ( IsPaymentsvout(cp,tx,0,txidaddr,ccopret) == 0 ) + return eval->Invalid("change pays wrong address"); + if ( !fIsMerge ) { + if ( amountReleased < minrelease*COIN ) + { + fprintf(stderr, "does not meet minrelease amount.%li minrelease.%li\n",amountReleased, (int64_t)minrelease*COIN); + return(eval->Invalid("amount is too small")); + } // Get all the script pubkeys and allocations std::vector allocations; std::vector scriptPubKeys; - int64_t checkallocations = 0; i = 0; if ( funcid == 'C' ) { // normal payment - for (const uint256& txidopret : txidoprets) + int64_t checkallocations = 0; + for ( auto txidopret : txidoprets) { CTransaction tx0; std::vector scriptPubKey,opret; int64_t allocation; if ( myGetTransaction(txidopret,tx0,blockhash) != 0 && tx0.vout.size() > 1 && DecodePaymentsTxidOpRet(tx0.vout[tx0.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) @@ -341,10 +377,14 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & } i++; } + //fprintf(stderr, "totalallocations.%li checkallocations.%li\n",totalallocations, checkallocations); + if ( totalallocations != checkallocations ) + return(eval->Invalid("allocation missmatch")); mpz_set_si(mpzTotalAllocations,totalallocations); } - else if ( funcid == 'S' ) + else if ( funcid == 'S' || funcid == 'O' ) { + // snapshot payment if ( KOMODO_SNAPSHOT_INTERVAL == 0 ) return(eval->Invalid("snapshots not activated on this chain")); if ( vAddressSnapshot.size() == 0 ) @@ -360,132 +400,116 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { fFixedAmount = true; } - for (int32_t j = bottom; j < vAddressSnapshot.size(); j++) + if ( funcid == 'S' ) + payments_getallocations(top, bottom, excludeScriptPubKeys, mpzTotalAllocations, scriptPubKeys, allocations); + else { - auto &address = vAddressSnapshot[j]; - CScript scriptPubKey = GetScriptForDestination(address.second); bool skip = false; - for ( auto skipkey : excludeScriptPubKeys ) - { - if ( scriptPubKey == CScript(skipkey.begin(), skipkey.end()) ) - { - skip = true; - //fprintf(stderr, "SKIPPED::: %s\n", CBitcoinAddress(address.second).ToString().c_str()); - } - } - if ( !skip ) - { - mpz_init(mpzAllocation); - i++; - scriptPubKeys.push_back(scriptPubKey); - allocations.push_back(address.first); - mpz_set_si(mpzAllocation,address.first); - mpz_add(mpzTotalAllocations,mpzTotalAllocations,mpzAllocation); - mpz_clear(mpzAllocation); - } - if ( i+bottom == top ) // we reached top amount to pay, it can be less than this! - break; + // token snapshot + // payments_gettokenallocations(top, bottom, excludeScriptPubKeys, tokenid, mpzTotalAllocations, scriptPubKeys, allocations); + return(eval->Invalid("tokens not yet implemented")); } - if ( i != tx.vout.size()-2 ) - return(eval->Invalid("pays wrong amount of recipients")); - } - else if ( funcid == 'O' ) - { - // tokens snapshot. } // sanity check to make sure we got all the required info, skip for merge type tx //fprintf(stderr, " allocations.size().%li scriptPubKeys.size.%li\n",allocations.size(), scriptPubKeys.size()); if ( (allocations.size() == 0 || scriptPubKeys.size() == 0 || allocations.size() != scriptPubKeys.size()) ) return(eval->Invalid("missing data cannot validate")); - - //fprintf(stderr, "totalallocations.%li checkallocations.%li\n",totalallocations, checkallocations); - if ( funcid == 'C' && totalallocations != checkallocations ) // only check for normal payments release. - return(eval->Invalid("allocation missmatch")); // Check vouts go to the right place and pay the right amounts. - int64_t amount = 0, checkamount; int32_t n = 0; - checkamount = tx.GetValueOut() - change - PAYMENTS_TXFEE; - mpz_t mpzCheckamount; mpz_init(mpzCheckamount); mpz_set_si(mpzCheckamount,checkamount); - for (i = 1; i < (fHasOpret ? tx.vout.size()-2 : tx.vout.size()-1); i++) + int64_t amount = 0; int32_t n = 0; + // We place amount released into ccopret, so that these calcualtion are accurate! + // If you change the amount released in the RPC these calcs will be wrong, and validation will fail. + for (i = 1; i < (fHasOpret ? tx.vout.size()-1 : tx.vout.size()); i++) { + int64_t test; if ( scriptPubKeys[n] != tx.vout[i].scriptPubKey ) { fprintf(stderr, "pays wrong destination destscriptPubKey.%s voutscriptPubKey.%s\n", HexStr(scriptPubKeys[n].begin(),scriptPubKeys[n].end()).c_str(), HexStr(tx.vout[i].scriptPubKey.begin(),tx.vout[i].scriptPubKey.end()).c_str()); return(eval->Invalid("pays wrong address")); } - int64_t test; if ( fFixedAmount ) { - test = checkamount / (top-bottom); + if ( (top-bottom) > 0 ) + test = amountReleased / (top-bottom); + else + return(eval->Invalid("top/bottom range is illegal")); } else { mpz_init(mpzAllocation); mpz_set_si(mpzAllocation,allocations[n]); mpz_mul(mpzAllocation,mpzAllocation,mpzCheckamount); - mpz_cdiv_q(mpzAllocation,mpzAllocation,mpzTotalAllocations); + mpz_tdiv_q(mpzAllocation,mpzAllocation,mpzTotalAllocations); test = mpz_get_si(mpzAllocation); mpz_clear(mpzAllocation); } - // Vairance of 1 sat is allowed, for rounding errors. - if ( test >= tx.vout[i].nValue+1 && test <= tx.vout[i].nValue-1 ) + //fprintf(stderr, "vout %i test.%li nValue.%li\n", i, test, tx.vout[i].nValue); + if ( test != tx.vout[i].nValue ) { fprintf(stderr, "vout.%i test.%li vs nVlaue.%li\n",i, test, tx.vout[i].nValue); return(eval->Invalid("amounts do not match")); } if ( test < minimum ) { + // prevent anyone being paid the minimum. fprintf(stderr, "vout.%i test.%li vs minimum.%i\n",i, test, minimum); return(eval->Invalid("under minimum size")); } amount += tx.vout[i].nValue; n++; } - mpz_clear(mpzTotalAllocations); - // This is a backup check to make sure there are no extra vouts paying something else! - if ( checkamount != amount ) - return(eval->Invalid("amounts do not match")); - - if ( amount < minrelease*COIN ) + if ( allocations.size() > n ) { - fprintf(stderr, "does not meet minrelease amount.%li minrelease.%li\n",amount, (int64_t)minrelease*COIN ); - return(eval->Invalid("amount is too small")); + // need to check that the next allocation was less than minimum, otherwise ppl can truncate the tx at any place not paying all elegible addresses. + mpz_init(mpzAllocation); + mpz_set_si(mpzAllocation,allocations[n+1]); + mpz_mul(mpzAllocation,mpzAllocation,mpzCheckamount); + mpz_tdiv_q(mpzAllocation,mpzAllocation,mpzTotalAllocations); + int64_t test = mpz_get_si(mpzAllocation); + //fprintf(stderr, "check next vout pays under min: test.%li > minimuim.%i\n", test, minimum); + if ( test > minimum ) + return(eval->Invalid("next allocation was not under minimum")); } + mpz_clear(mpzTotalAllocations); mpz_clear(mpzCheckamount); } // Check vins - i = 0; int32_t dust = 0; - int32_t blocksleft; - BOOST_FOREACH(const CTxIn& vin, tx.vin) + i = 0; + for (auto vin : tx.vin) { CTransaction txin; if ( myGetTransaction(vin.prevout.hash,txin,blockhash) ) { // check the vin comes from the CC address's - char destaddr[64]; int32_t mergeoffset = 0; CScript opret; uint256 checktxid; - Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey); + char fromaddr[64]; int32_t mergeoffset = 0; CScript vinccopret; uint256 checktxid; + Getscriptaddress(fromaddr,txin.vout[vin.prevout.n].scriptPubKey); if ( fIsMerge && txin.vout[vin.prevout.n].nValue < COIN ) dust++; - if ( strcmp(destaddr,coinaddr) != 0 ) + if ( IsPaymentsvout(cp,txin,vin.prevout.n,cp->unspendableCCaddr,vinccopret) != 0 ) { - // if does not come from address its in the global payments adddress and we need to check the opreturn. - uint256 checktxid; int32_t opret_ind; - if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 ) - getCCopret(txin.vout[vin.prevout.n].scriptPubKey,opret); // get op_return from CCvout, - else - opret = txin.vout[opret_ind].scriptPubKey; - if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) + // if from global payments address get ccopret to detemine pays correct plan. + uint256 checktxid; + if ( vinccopret.size() < 2 || DecodePaymentsFundOpRet(vinccopret,checktxid) != 'F' || checktxid != createtxid ) { - fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str()); + fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s vout.%i\n", i, txin.GetHash().ToString().c_str(), vin.prevout.n); return(eval->Invalid("vin is not paymentsCC type")); } } - else if ( fIsMerge && getCCopret(txin.vout[vin.prevout.n].scriptPubKey,opret) && opret.size() > 2 && DecodePaymentsMergeOpRet(opret,checktxid) == 'M' ) + else if ( IsPaymentsvout(cp,txin,vin.prevout.n,txidaddr,vinccopret) != 0 ) { - mergeoffset = PAYMENTS_MERGEOFSET; - } - //fprintf(stderr, "mergeoffset.%i\n", mergeoffset); + // if in txid address apply merge offset if applicable. + if ( fIsMerge && vinccopret.size() > 2 && DecodePaymentsMergeOpRet(vinccopret,checktxid) == 'M' ) + { + // Apply merge offset to locked blocks, this prevents people spaming payments fund and payments merge to prevent release happening. + mergeoffset = PAYMENTS_MERGEOFSET; + } + } + else // not from global payments plan, or txid address. + return(eval->Invalid("utxo comes from incorrect address")); // check the chain depth vs locked blocks requirement. if ( !payments_lockedblocks(blockhash, lockedblocks+mergeoffset, blocksleft) ) + { + fprintf(stderr, "vin.%i is not elegible for.%i blocks \n",i, blocksleft); return(eval->Invalid("vin not elegible")); + } i++; } else return(eval->Invalid("cant get vin transaction")); } @@ -496,8 +520,8 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & else if ( i == dust+1 ) return(eval->Invalid("cannot merge only dust")); } - } else return(eval->Invalid("create transaction cannot decode")); - } else return(eval->Invalid("Could not get contract transaction")); + } else return(eval->Invalid("cannot decode create transaction")); + } else return(eval->Invalid("could not get contract transaction")); return(true); } // end of consensus code @@ -533,32 +557,23 @@ int64_t AddPaymentsInputs(bool fLockedBlocks,int8_t GetBalance,struct CCcontract txid = it->first.txhash; vout = (int32_t)it->first.index; //fprintf(stderr,"iter.%d %s/v%d %s\n",iter,txid.GetHex().c_str(),vout,coinaddr); - if ( (vout == 0 || vout == 1) && GetTransaction(txid,vintx,hashBlock,false) != 0 ) + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( iter == 0 ) - { - CScript opret; uint256 checktxid; int32_t opret_ind; - if ( (opret_ind= has_opret(vintx, EVAL_PAYMENTS)) == 0 ) - { - // get op_return from CCvout - getCCopret(vintx.vout[vout].scriptPubKey,opret); - } - else - { - // get op_return from the op_return - opret = vintx.vout[opret_ind].scriptPubKey; - } - if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) - { - fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str()); - continue; - } - } if ( (nValue= IsPaymentsvout(cp,vintx,vout,coinaddr,ccopret)) > PAYMENTS_TXFEE && nValue >= threshold && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) { int32_t offset = 0; - if ( ccopret.size() > 2 && DecodePaymentsMergeOpRet(ccopret,checktxid) == 'M' ) - offset = PAYMENTS_MERGEOFSET; + if ( ccopret.size() > 2 ) + { + if ( iter == 0 && (DecodePaymentsFundOpRet(ccopret,checktxid) != 'F' || checktxid != createtxid) ) + { + // global address but not for this plan. + fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str()); + continue; + } + // increase merge offset, if this is a merge tx, merging merged utxos. + if ( iter == 1 && GetBalance == 4 && DecodePaymentsMergeOpRet(ccopret,checktxid) == 'M' ) + offset = PAYMENTS_MERGEOFSET; + } int32_t tmpblocksleft = 0; if ( fLockedBlocks && !payments_lockedblocks(hashBlock, lockedblocks+offset, tmpblocksleft) ) { @@ -671,19 +686,20 @@ int32_t payments_parsehexdata(std::vector &hexdata,cJSON *item,int32_t UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) { - int32_t nextheight = komodo_nextheight(); - //int32_t latestheight,nextheight = komodo_nextheight(); - CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); UniValue result(UniValue::VOBJ); uint256 createtxid,hashBlock,tokenid; - CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,m,numoprets=0,lockedblocks,minrelease; int64_t newamount,inputsum,amount,CCchange=0,totalallocations=0,checkallocations=0,allocation; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector txidoprets; - int32_t top,bottom=0,blocksleft=0,minimum=10000; std::vector> excludeScriptPubKeys; int8_t funcid,fixedAmount=0; bool fFixedAmount = false; - mpz_t mpzTotalAllocations; mpz_init(mpzTotalAllocations); + LOCK(cs_main); + CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),komodo_nextheight()); UniValue result(UniValue::VOBJ); uint256 createtxid,hashBlock,tokenid; + CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,m,numoprets=0,lockedblocks,minrelease; int64_t newamount,inputsum,amount,CCchange=0,totalallocations=0,checkallocations=0,allocation; CTxOut vout; CScript onlyopret,ccopret; char txidaddr[64],destaddr[64]; std::vector txidoprets; + int32_t top,bottom=0,blocksleft=0,minimum=10000; std::vector> excludeScriptPubKeys; int8_t funcid,fixedAmount=0,skipminimum=0; bool fFixedAmount = false; + mpz_t mpzTotalAllocations, mpzAllocation; mpz_init(mpzTotalAllocations); cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); Paymentspk = GetUnspendable(cp,0); - if ( params != 0 && n == 2 ) + if ( params != 0 && n >= 2 ) { createtxid = payments_juint256(jitem(params,0)); amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049; + if ( n == 3 ) + skipminimum = juint(jitem(params,2),0); if ( myGetTransaction(createtxid,tx,hashBlock) != 0 && tx.vout.size() > 0 ) { if ( ((funcid= DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets)) == 'C' || (funcid= DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys)) == 'S' || (funcid= DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys,tokenid)) == 'O') ) @@ -699,7 +715,6 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) // set minimum size to 10k sat otherwise the tx will be invalid. if ( minimum < 10000 ) minimum = 10000; - //latestheight = (nextheight - lockedblocks - 1); if ( amount < minrelease*COIN ) { result.push_back(Pair("result","error")); @@ -711,11 +726,15 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) return(result); } txidpk = CCtxidaddr(txidaddr,createtxid); - mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk)); + ccopret = EncodePaymentsReleaseOpRet(createtxid, amount); + std::vector> vData = std::vector>(); + if ( makeCCopret(ccopret, vData) ) + mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk,&vData)); //fprintf(stderr, "funcid.%i\n", funcid); if ( funcid == 'C' ) { // normal payments + m = txidoprets.size(); for (i=0; i scriptPubKey,opret; @@ -766,7 +785,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) // set totalallocations to a mpz_t bignum, for amounts calculation later. mpz_set_si(mpzTotalAllocations,totalallocations); } - else if ( funcid == 'S' ) + else if ( funcid == 'S' || funcid == 'O' ) { // normal snapshot if ( vAddressSnapshot.size() == 0 ) @@ -785,7 +804,6 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) free_json(params); return(result); } - i = 0; if ( fixedAmount == 7 ) { // game setting, randomise bottom and top values @@ -795,38 +813,40 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) { fFixedAmount = true; } - for (int32_t j = bottom; j < vAddressSnapshot.size(); j++) + if ( (top-bottom) < 0 ) { - auto &address = vAddressSnapshot[j]; - CScript scriptPubKey = GetScriptForDestination(address.second); bool skip = false; - for ( auto skipkey : excludeScriptPubKeys ) - { - if ( scriptPubKey == CScript(skipkey.begin(), skipkey.end()) ) - { - skip = true; - //fprintf(stderr, "SKIPPED::: %s\n", CBitcoinAddress(address.second).ToString().c_str()); - } - } - if ( !skip ) - { - mpz_t mpzAllocation; mpz_init(mpzAllocation); - i++; - //fprintf(stderr, "address: %s nValue.%li \n", CBitcoinAddress(address.second).ToString().c_str(), address.first); - vout.nValue = address.first; - vout.scriptPubKey = scriptPubKey; - mpz_set_si(mpzAllocation,address.first); - mpz_add(mpzTotalAllocations,mpzTotalAllocations,mpzAllocation); - mtx.vout.push_back(vout); - mpz_clear(mpzAllocation); - } - if ( i+bottom == top ) // we reached top amount to pay, it can be less than this! - break; + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid range top/bottom")); + if ( params != 0 ) + free_json(params); + return(result); + } + + std::vector allocations; + std::vector scriptPubKeys; + if ( funcid == 'S' ) + m = payments_getallocations(top, bottom, excludeScriptPubKeys, mpzTotalAllocations, scriptPubKeys, allocations); + else + { + // token snapshot + // payments_gettokenallocations(top, bottom, excludeScriptPubKeys, tokenid, mpzTotalAllocations, scriptPubKeys, allocations); + } + if ( (allocations.size() == 0 || scriptPubKeys.size() == 0 || allocations.size() != scriptPubKeys.size()) ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","mismatched allocations, scriptpubkeys")); + if ( params != 0 ) + free_json(params); + return(result); + } + i = 0; + for ( auto allocation : allocations ) + { + vout.nValue = allocation; + vout.scriptPubKey = scriptPubKeys[i]; + mtx.vout.push_back(vout); + i++; } - m = i; // this is the amount we got, either top, or all of the address on the chain. - } - else if ( funcid == 'O' ) - { - // token snapshot } newamount = amount; int64_t totalamountsent = 0; @@ -835,15 +855,12 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) { mpz_t mpzValue; mpz_init(mpzValue); if ( fFixedAmount ) - { mtx.vout[i+1].nValue = amount / (top-bottom); - //fprintf(stderr, "amount.%li / top-bottom.%i = value.%li\n", amount, (top-bottom-2), mtx.vout[i+1].nValue); - } else { mpz_set_si(mpzValue,mtx.vout[i+1].nValue); mpz_mul(mpzValue,mpzValue,mpzAmount); - mpz_cdiv_q(mpzValue,mpzValue,mpzTotalAllocations); + mpz_tdiv_q(mpzValue,mpzValue,mpzTotalAllocations); if ( mpz_fits_slong_p(mpzValue) ) mtx.vout[i+1].nValue = mpz_get_si(mpzValue); else @@ -855,20 +872,31 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) return(result); } } - //fprintf(stderr, "nValue.%li \n", mtx.vout[i+1].nValue); mpz_clear(mpzValue); + //fprintf(stderr, "[%i] nValue.%li minimum.%i scriptpubkey.%s\n", i, mtx.vout[i+1].nValue, minimum, HexStr(mtx.vout[i+1].scriptPubKey.begin(),mtx.vout[i+1].scriptPubKey.end()).c_str()); if ( mtx.vout[i+1].nValue < minimum ) { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","value too small, try releasing a larger amount")); - if ( params != 0 ) - free_json(params); - return(result); + if ( skipminimum == 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","value too small, try releasing a larger amount, or use skipminimum flag")); + if ( params != 0 ) + free_json(params); + return(result); + } + else + { + // NOTE: should make this default behaviour. + // truncate off any vouts that are less than minimum. + mtx.vout.resize(i+1); + break; + } } totalamountsent += mtx.vout[i+1].nValue; } if ( totalamountsent < amount ) newamount = totalamountsent; - fprintf(stderr, "newamount.%li totalamountsent.%li\n", newamount, totalamountsent); + //int64_t temptst = mpz_get_si(mpzTotalAllocations); + //fprintf(stderr, "checkamount RPC.%li totalallocations.%li\n",totalamountsent, temptst); mpz_clear(mpzAmount); mpz_clear(mpzTotalAllocations); } else @@ -882,9 +910,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) if ( (inputsum= AddPaymentsInputs(true,0,cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,lockedblocks,minrelease,blocksleft)) >= newamount+2*PAYMENTS_TXFEE ) { std::string rawtx; - if ( (CCchange= (inputsum - newamount - 2*PAYMENTS_TXFEE)) >= PAYMENTS_TXFEE ) - mtx.vout[0].nValue = CCchange; - mtx.vout.push_back(CTxOut(PAYMENTS_TXFEE,CScript() << ParseHex(HexStr(txidpk)) << OP_CHECKSIG)); + mtx.vout[0].nValue = inputsum - newamount - PAYMENTS_TXFEE; // only 1 txfee, so the minimum in this vout is a tx fee. GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk); CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr); rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,onlyopret); @@ -919,18 +945,20 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); - CPubKey Paymentspk,mypk,txidpk; uint256 txid,hashBlock; int64_t amount,totalallocations; CScript opret; CTransaction tx; char txidaddr[64]; std::string rawtx; int32_t n,useopret = 0,lockedblocks,minrelease; std::vector txidoprets; + CPubKey Paymentspk,mypk,txidpk; uint256 txid,hashBlock; int64_t amount,totalallocations; CScript opret; CTransaction tx; char txidaddr[64]; std::string rawtx; int32_t n,useopret = 0,broadcast=0,lockedblocks,minrelease; std::vector txidoprets; int32_t top,bottom,minimum=10000; std::vector> excludeScriptPubKeys; // snapshot uint256 tokenid; int8_t fixedAmount; cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); Paymentspk = GetUnspendable(cp,0); - if ( params != 0 && n > 1 && n <= 3 ) + if ( params != 0 && n > 1 && n <= 4 ) { txid = payments_juint256(jitem(params,0)); amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049; if ( n == 3 ) useopret = jint(jitem(params,2),0) != 0; + if ( n == 4 ) + broadcast = jint(jitem(params,3),0) != 0; if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() == 1 || (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 0 && DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys) == 0 && DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys,tokenid) == 0) ) { result.push_back(Pair("result","error")); @@ -953,18 +981,14 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) } else { - mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk)); opret = EncodePaymentsFundOpRet(txid); - // Use the below one along with other FinalizeCCTx/return, to get the ccvout scriptpubkey - /*std::vector> vData = std::vector>(); + std::vector> vData = std::vector>(); if ( makeCCopret(opret, vData) ) - mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData)); */ + mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData)); } - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,opret); - //rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); // use this one to get ccvout scriptpubkey. + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); if ( params != 0 ) - free_json(params); - //return(payments_rawtxresult(result,rawtx,0)); // disable sending for CCvout, as we only need to decode the tx. + free_json(params); return(payments_rawtxresult(result,rawtx,1)); } else @@ -1015,7 +1039,6 @@ UniValue PaymentsMerge(struct CCcontract_info *cp,char *jsonstr) // encode the checktxid into the end of the ccvout, along with 'M' to flag merge type tx. opret = EncodePaymentsMergeOpRet(createtxid); std::vector> vData = std::vector>(); - // try to pay to diffrent pubkey here... change txidpk. if ( makeCCopret(opret, vData) ) mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,inputsum-PAYMENTS_TXFEE,Paymentspk,txidpk,&vData)); GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk); @@ -1045,15 +1068,27 @@ UniValue PaymentsMerge(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); CPubKey mypk; std::string rawtx; - std::vector scriptPubKey,opret; int32_t n,retval0,retval1=0; int64_t allocation; + std::vector scriptPubKey,opret; int32_t n,retval0,retval1=0; int64_t allocation; CScript test; txnouttype whichType; cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); if ( params != 0 && n > 1 && n <= 3 ) { allocation = (int64_t)jint(jitem(params,0),0); - retval0 = payments_parsehexdata(scriptPubKey,jitem(params,1),0); - CScript test = CScript(scriptPubKey.begin(),scriptPubKey.end()); - txnouttype whichType; + std::string address; + address.append(jstri(params,1)); + CTxDestination destination = DecodeDestination(address); + if ( IsValidDestination(destination) ) + { + // its an address + test = GetScriptForDestination(destination); + scriptPubKey = std::vector (test.begin(),test.end()); + } + else + { + // its a scriptpubkey + retval0 = payments_parsehexdata(scriptPubKey,jitem(params,1),0); + test = CScript(scriptPubKey.begin(),scriptPubKey.end()); + } if (!::IsStandard(test, whichType)) { result.push_back(Pair("result","error")); @@ -1108,7 +1143,7 @@ UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr) for (i=0; i scriptPubKey,opret; int64_t allocation; - fprintf(stderr, "txid.%s\n",txidoprets[i].GetHex().c_str()); + //fprintf(stderr, "txid.%s\n",txidoprets[i].GetHex().c_str()); if ( myGetTransaction(txidoprets[i],tx,hashBlock) != 0 && tx.vout.size() > 1 && DecodePaymentsTxidOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) { totalallocations += allocation; @@ -1188,6 +1223,14 @@ UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr) free_json(params); return(result); } + if ( top-bottom < 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid range, top/bottom")); + if ( params != 0 ) + free_json(params); + return(result); + } if ( n > 6 ) { for (i=0; i> excludeScriptPubKeys; int8_t fixedAmount; cJSON *params = payments_reparse(&n,jsonstr); - if ( params != 0 && n >= 6 ) + // disable for now. Need token snapshot function. + if ( 0 ) //params != 0 && n >= 6 ) { tokenid = payments_juint256(jitem(params,0)); lockedblocks = juint(jitem(params,1),0); @@ -1316,7 +1360,8 @@ UniValue PaymentsAirdropTokens(struct CCcontract_info *cp,char *jsonstr) else { result.push_back(Pair("result","error")); - result.push_back(Pair("error","parameters error")); + //result.push_back(Pair("error","parameters error")); + result.push_back(Pair("error","tokens airdrop not yet impmlemented")); } if ( params != 0 ) free_json(params); diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index 2116f2e8e..2c0a33b20 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -11,7 +11,34 @@ * * * Removal or modification of this copyright notice is prohibited. * * * - ***************************************************************************** + *****************************************************************************/ + + /* + CBOPRET creates trustless oracles, which can be used for making a synthetic cash settlement system based on real world prices; + + 0.5% fee based on betamount, NOT leveraged betamount!! + 0.1% collected by price basis determinant + 0.2% collected by rekt tx + + PricesBet -> +/-leverage, amount, synthetic -> opreturn includes current price + funds are locked into 1of2 global CC address + for first day, long basis is MAX(correlated,smoothed), short is MIN() + reference price is the smoothed of the previous block + if synthetic value + amount goes negative, then anybody can rekt it to collect a rektfee, proof of rekt must be included to show cost basis, rekt price + original creator can liquidate at anytime and collect (synthetic value + amount) from globalfund + 0.5% of bet -> globalfund + + PricesStatus -> bettxid maxsamples returns initial params, cost basis, amount left, rekt:true/false, rektheight, initial synthetic price, current synthetic price, net gain + + PricesRekt -> bettxid height -> 0.1% to miner, rest to global CC + + PricesClose -> bettxid returns (synthetic value + amount) + + PricesList -> all bettxid -> list [bettxid, netgain] + + */ + +/* To create payments plan start a chain with the following ac_params: -ac_snapshot=1440 (or for test chain something smaller, if you like.) - this enables the payments airdrop cc to work. @@ -45,6 +72,7 @@ GetKomodoEarlytxidScriptPub is on line #2080 of komodo_bitcoind.h #include "CCassets.h" #include "CCPrices.h" +#include #include #define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos) @@ -62,53 +90,50 @@ typedef struct OneBetData { } onebetdata; typedef struct BetInfo { + uint256 txid; int64_t averageCostbasis, firstprice, lastprice, liquidationprice, equity; - int64_t rektfee; + int64_t exitfee; int32_t lastheight; int16_t leverage; bool isOpen, isRekt; uint256 tokenid; - std::vector parsed; + std::vector vecparsed; std::vector bets; CPubKey pk; + bool isUp; + BetInfo() { averageCostbasis = firstprice = lastprice = liquidationprice = equity = 0; lastheight = 0; leverage = 0; - rektfee = 0; - isOpen = isRekt = false; + exitfee = 0; + isOpen = isRekt = isUp = false; } } BetInfo; -/* -CBOPRET creates trustless oracles, which can be used for making a synthetic cash settlement system based on real world prices; - - 0.5% fee based on betamount, NOT leveraged betamount!! - 0.1% collected by price basis determinant - 0.2% collected by rekt tx - - PricesBet -> +/-leverage, amount, synthetic -> opreturn includes current price - funds are locked into 1of2 global CC address - for first day, long basis is MAX(correlated,smoothed), short is MIN() - reference price is the smoothed of the previous block - if synthetic value + amount goes negative, then anybody can rekt it to collect a rektfee, proof of rekt must be included to show cost basis, rekt price - original creator can liquidate at anytime and collect (synthetic value + amount) from globalfund - 0.5% of bet -> globalfund - - PricesStatus -> bettxid maxsamples returns initial params, cost basis, amount left, rekt:true/false, rektheight, initial synthetic price, current synthetic price, net gain - - PricesRekt -> bettxid height -> 0.1% to miner, rest to global CC - - PricesClose -> bettxid returns (synthetic value + amount) - - PricesList -> all bettxid -> list [bettxid, netgain] - - -*/ +typedef struct MatchedBookTotal { + + int64_t diffLeveragedPosition; + +} MatchedBookTotal; + +typedef struct TotalFund { + int64_t totalFund; + int64_t totalActiveBets; + int64_t totalCashout; + int64_t totalRekt; + int64_t totalEquity; + + TotalFund() { + totalFund = totalActiveBets = totalCashout = totalRekt = totalEquity = 0; + } + +} TotalFund; int32_t prices_syntheticprofits(int64_t &costbasis, int32_t firstheight, int32_t height, int16_t leverage, std::vector vec, int64_t positionsize, int64_t &profits, int64_t &outprice); +static bool prices_isacceptableamount(const std::vector &vecparsed, int64_t amount, int16_t leverage); // helpers: @@ -177,18 +202,20 @@ uint8_t prices_costbasisopretdecode(CScript scriptPubKey,uint256 &bettxid,CPubKe return(0); } -CScript prices_finalopret(uint256 bettxid,int64_t profits,int32_t height,CPubKey mypk,int64_t firstprice,int64_t costbasis,int64_t addedbets,int64_t positionsize,int16_t leverage) +CScript prices_finalopret(bool isRekt, uint256 bettxid, CPubKey pk, int32_t lastheight, int64_t costbasis, int64_t lastprice, int64_t liquidationprice, int64_t equity, int64_t exitfee, uint32_t nonce) { CScript opret; - opret << OP_RETURN << E_MARSHAL(ss << EVAL_PRICES << 'F' << bettxid << profits << height << mypk << firstprice << costbasis << addedbets << positionsize << leverage); + opret << OP_RETURN << E_MARSHAL(ss << EVAL_PRICES << (isRekt ? 'R' : 'F') << bettxid << pk << lastheight << costbasis << lastprice << liquidationprice << equity << exitfee << nonce); return(opret); } -uint8_t prices_finalopretdecode(CScript scriptPubKey,uint256 &bettxid,int64_t &profits,int32_t &height,CPubKey &pk,int64_t &firstprice,int64_t &costbasis,int64_t &addedbets,int64_t &positionsize,int16_t &leverage) +uint8_t prices_finalopretdecode(CScript scriptPubKey, uint256 &bettxid, CPubKey &pk, int32_t &lastheight, int64_t &costbasis, int64_t &lastprice, int64_t &liquidationprice, int64_t &equity, int64_t &exitfee) { std::vector vopret; uint8_t e,f; + uint32_t nonce; + GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> bettxid; ss >> profits; ss >> height; ss >> pk; ss >> firstprice; ss >> costbasis; ss >> addedbets; ss >> positionsize; ss >> leverage) != 0 && e == EVAL_PRICES && f == 'F' ) + if (vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> bettxid; ss >> pk; ss >> lastheight; ss >> costbasis; ss >> lastprice; ss >> liquidationprice; ss >> equity; ss >> exitfee; if (!ss.eof()) ss >> nonce; ) != 0 && e == EVAL_PRICES && (f == 'F' || f == 'R')) { return(f); } @@ -198,7 +225,7 @@ uint8_t prices_finalopretdecode(CScript scriptPubKey,uint256 &bettxid,int64_t &p // price opret basic validation and retrieval static uint8_t PricesCheckOpret(const CTransaction & tx, vscript_t &opret) { - if (tx.vout.size() > 0 && GetOpReturnData(tx.vout.back().scriptPubKey, opret) && opret.size() > 2 && opret.begin()[0] == EVAL_PRICES && IS_CHARINSTR(opret.begin()[1], "BACF")) + if (tx.vout.size() > 0 && GetOpReturnData(tx.vout.back().scriptPubKey, opret) && opret.size() > 2 && opret.begin()[0] == EVAL_PRICES && IS_CHARINSTR(opret.begin()[1], "BACFR")) return opret.begin()[1]; else return (uint8_t)0; @@ -213,9 +240,12 @@ static bool ValidateBetTx(struct CCcontract_info *cp, Eval *eval, const CTransac int16_t leverage; CPubKey pk, pricespk; std::vector vec; + + // check payment cc config: if ( ASSETCHAINS_EARLYTXIDCONTRACT == EVAL_PRICES && KOMODO_EARLYTXID_SCRIPTPUB.size() == 0 ) GetKomodoEarlytxidScriptPub(); - if (bettx.vout.size() < 5 || bettx.vout.size() > 6) + + if (bettx.vout.size() < 6 || bettx.vout.size() > 7) return eval->Invalid("incorrect vout number for bet tx"); vscript_t opret; @@ -235,7 +265,7 @@ static bool ValidateBetTx(struct CCcontract_info *cp, Eval *eval, const CTransac return eval->Invalid("the fee was paid to wrong address."); int64_t betamount = bettx.vout[2].nValue; - if (betamount != (positionsize * 199) / 200) { + if (betamount != PRICES_SUBREVSHAREFEE(positionsize)) { return eval->Invalid("invalid position size in the opreturn"); } @@ -264,7 +294,11 @@ static bool ValidateAddFundingTx(struct CCcontract_info *cp, Eval *eval, const C CPubKey pk, pricespk; vscript_t vintxOpret; - if (addfundingtx.vout.size() < 3 || addfundingtx.vout.size() > 4) + // check payment cc config: + if (ASSETCHAINS_EARLYTXIDCONTRACT == EVAL_PRICES && KOMODO_EARLYTXID_SCRIPTPUB.size() == 0) + GetKomodoEarlytxidScriptPub(); + + if (addfundingtx.vout.size() < 4 || addfundingtx.vout.size() > 5) return eval->Invalid("incorrect vout number for add funding tx"); vscript_t opret; @@ -286,10 +320,20 @@ static bool ValidateAddFundingTx(struct CCcontract_info *cp, Eval *eval, const C if (MakeCC1vout(cp->evalcode, addfundingtx.vout[1].nValue, pricespk) != addfundingtx.vout[1]) return eval->Invalid("cannot validate vout1 in add funding tx with global pk"); + // This should be all you need to verify it, maybe also check amount? + if (addfundingtx.vout[2].scriptPubKey != KOMODO_EARLYTXID_SCRIPTPUB) + return eval->Invalid("the fee was paid to wrong address."); + + int64_t betamount = addfundingtx.vout[1].nValue; + if (betamount != PRICES_SUBREVSHAREFEE(amount)) { + return eval->Invalid("invalid bet position size in the opreturn"); + } + return true; } -// validate costbasis tx helper +// validate costbasis tx helper (deprecated) +/* static bool ValidateCostbasisTx(struct CCcontract_info *cp, Eval *eval, const CTransaction & costbasistx, const CTransaction & bettx) { uint256 bettxid; @@ -349,6 +393,7 @@ static bool ValidateCostbasisTx(struct CCcontract_info *cp, Eval *eval, const CT return true; } +*/ // validate final tx helper static bool ValidateFinalTx(struct CCcontract_info *cp, Eval *eval, const CTransaction & finaltx, const CTransaction & bettx) @@ -357,8 +402,8 @@ static bool ValidateFinalTx(struct CCcontract_info *cp, Eval *eval, const CTrans int64_t amount; CPubKey pk, pricespk; int64_t profits; - int32_t height; - int64_t firstprice, costbasis, addedbets, positionsize; + int32_t lastheight; + int64_t firstprice, costbasis, lastprice, liquidationprice, equity, fee; int16_t leverage; if (finaltx.vout.size() < 3 || finaltx.vout.size() > 4) { @@ -367,9 +412,14 @@ static bool ValidateFinalTx(struct CCcontract_info *cp, Eval *eval, const CTrans } vscript_t opret; - if (prices_finalopretdecode(finaltx.vout.back().scriptPubKey, bettxid, profits, height, pk, firstprice, costbasis, addedbets, positionsize, leverage) != 'F') + uint8_t funcId; + if ((funcId = prices_finalopretdecode(finaltx.vout.back().scriptPubKey, bettxid, pk, lastheight, costbasis, lastprice, liquidationprice, equity, fee)) == 0) return eval->Invalid("cannot decode opreturn for final tx"); + // check rekt txid mining: +// if( funcId == 'R' && (finaltx.GetHash().begin()[0] != 0 || finaltx.GetHash().begin()[31] != 0) ) +// return eval->Invalid("incorrect rekt txid"); + if (bettx.GetHash() != bettxid) return eval->Invalid("incorrect bettx id"); @@ -381,6 +431,9 @@ static bool ValidateFinalTx(struct CCcontract_info *cp, Eval *eval, const CTrans if( finaltx.vout.size() == 3 && MakeCC1vout(cp->evalcode, finaltx.vout[1].nValue, pricespk) != finaltx.vout[1] ) return eval->Invalid("cannot validate vout1 in final tx with global pk"); + // TODO: validate exitfee for 'R' + // TODO: validate amount for 'F' + return true; } @@ -404,7 +457,7 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx { vscript_t vopret; - if (strcmp(ASSETCHAINS_SYMBOL, "REKT0") == 0 && chainActive.Height() < 2965) + if (strcmp(ASSETCHAINS_SYMBOL, "REKT0") == 0 && chainActive.Height() < 5851) return true; // check basic opret rules: if (PricesCheckOpret(tx, vopret) == 0) @@ -416,7 +469,7 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx vscript_t firstVinTxOpret; bool foundFirst = false; int32_t ccVinCount = 0; - uint32_t prevoutN = 0; + uint32_t prevCCoutN = 0; // check basic rules: @@ -435,13 +488,13 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx std::cerr << "PricesValidate() " << "cannot find prices opret in vintx" << std::endl; } - if (funcId != 'F' && vintxOpret.begin()[1] == 'B' && prevoutN == 1) { + if (!IS_CHARINSTR(funcId, "FR") && vintxOpret.begin()[1] == 'B' && prevCCoutN == 1) { //return eval->Invalid("cannot spend bet marker"); - std::cerr << "PricesValidate() " << " non-final tx cannot spend cc marker vout=" << prevoutN << std::endl; + std::cerr << "PricesValidate() " << " non-final tx cannot spend cc marker vout=" << prevCCoutN << std::endl; } if (!foundFirst) { - prevoutN = vin.prevout.n; + prevCCoutN = vin.prevout.n; firstVinTx = vintx; firstVinTxOpret = vintxOpret; foundFirst = true; @@ -452,7 +505,7 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx if (!foundFirst) return eval->Invalid("prices cc vin not found"); - if (funcId != 'F' && ccVinCount > 1) {// for all prices tx except final tx only one cc vin is allowed + if (!IS_CHARINSTR(funcId, "FR") && ccVinCount > 1) {// for all prices tx except final tx only one cc vin is allowed //return eval->Invalid("only one prices cc vin allowed for this tx"); std::cerr << "PricesValidate() " << "only one prices cc vin allowed for this tx" << std::endl; } @@ -464,26 +517,24 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx case 'A': // add funding // check tx structure: if (!ValidateAddFundingTx(cp, eval, tx, firstVinTx)) { - //return false; // invalid state is already set in the func std::cerr << "PricesValidate() " << "ValidateAddFundingTx = false " << eval->state.GetRejectReason() << std::endl; + return false; // invalid state is already set in the func } if (firstVinTxOpret.begin()[1] == 'B') { if (!ValidateBetTx(cp, eval, firstVinTx)) {// check tx structure - // return false; std::cerr << "PricesValidate() " << "funcId=A ValidatebetTx = false " << eval->state.GetRejectReason() << std::endl; + return false; // invalid state is already set in the func } } - else if (firstVinTxOpret.begin()[1] == 'A') { - // no need to validate the previous addfunding tx (it was validated when added) - } - if (prevoutN != 0) { // check spending rules - // return eval->Invalid("incorrect vintx vout to spend"); - std::cerr << "PricesValidate() " << "add fund tx incorrect vout to spend=" << prevoutN << std::endl; + if (prevCCoutN != 0) { // check spending rules + std::cerr << "PricesValidate() " << "addfunding tx incorrect vout to spend=" << prevCCoutN << std::endl; + return eval->Invalid("incorrect vintx vout to spend"); } break; + /* not used: case 'C': // set costbasis if (!ValidateCostbasisTx(cp, eval, tx, firstVinTx)) { //return false; @@ -498,20 +549,21 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx std::cerr << "PricesValidate() " << "costbasis tx incorrect vout to spend=" << prevoutN << std::endl; } //return eval->Invalid("test: costbasis is good"); - break; + break; */ case 'F': // final tx + case 'R': if (!ValidateFinalTx(cp, eval, tx, firstVinTx)) { - ///return false; std::cerr << "PricesValidate() " << "ValidateFinalTx=false " << eval->state.GetRejectReason() << std::endl; + return false; } if (!ValidateBetTx(cp, eval, firstVinTx)) { - // return false; std::cerr << "PricesValidate() " << "ValidateBetTx=false " << eval->state.GetRejectReason() << std::endl; + return false; } - if (prevoutN != 1) { // check spending rules - // return eval->Invalid("incorrect vout to spend"); - std::cerr << "PricesValidate() "<< "final tx incorrect vout to spend=" << prevoutN << std::endl; + if (prevCCoutN != 1) { // check spending rules + std::cerr << "PricesValidate() "<< "final tx incorrect vout to spend=" << prevCCoutN << std::endl; + return eval->Invalid("incorrect vout to spend"); } break; @@ -560,6 +612,19 @@ int64_t AddPricesInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, ch return(totalinputs); } +// return min equity percentage depending on leverage value +// for lev=1 2% +// for lev>=100 10% +double prices_minmarginpercent(int16_t leverage) +{ + int16_t absleverage = std::abs(leverage); + if (absleverage < 100) + return (absleverage * 0.080808 + 1.9191919) / 100.0; + else + return 0.1; +} + + UniValue prices_rawtxresult(UniValue &result, std::string rawtx, int32_t broadcastflag) { CTransaction tx; @@ -881,10 +946,10 @@ int32_t prices_syntheticvec(std::vector &vec, std::vector return(-3); } depth -= need; - std::cerr << "prices_syntheticvec() opcode=" << opcode << " opstr=" << opstr << " need=" << need << " depth=" << depth << std::endl; + ///std::cerr << "prices_syntheticvec() opcode=" << opcode << " opstr=" << opstr << " need=" << need << " depth=" << depth << std::endl; if ((opcode & KOMODO_PRICEMASK) != PRICES_WEIGHT) { // skip weight depth++; // increase operands count - std::cerr << "depth++=" << depth << std::endl; + ///std::cerr << "depth++=" << depth << std::endl; } if (depth > 3) { std::cerr << "prices_syntheticvec() too many operands, last=" << opstr << std::endl; @@ -930,14 +995,14 @@ int64_t prices_syntheticprice(std::vector vec, int32_t height, int32_t mpz_set_ui(mpzResult, 0); // clear result to test overflow (see below) - std::cerr << "prices_syntheticprice" << " i=" << i << " mpzTotalPrice=" << mpz_get_si(mpzTotalPrice) << " value=" << value << " depth=" << depth << " opcode&KOMODO_PRICEMASK=" << (opcode & KOMODO_PRICEMASK) < 0 ) + // std::cerr << "prices_syntheticprice top pricestack[depth-1=" << depth-1 << "]=" << pricestack[depth-1] << std::endl; + // else + // std::cerr << "prices_syntheticprice pricestack empty" << std::endl; } free(pricedata); @@ -1134,14 +1199,22 @@ int64_t prices_syntheticprice(std::vector vec, int32_t height, int32_t mpz_clear(mpzTotalPrice); mpz_clear(mpzPriceValue); - if (errcode != 0) + if (errcode != 0) std::cerr << "prices_syntheticprice errcode in switch=" << errcode << std::endl; + + if( errcode == -1 ) { + std::cerr << "prices_syntheticprice error getting price (could be end of chain)" << std::endl; + return errcode; + } if (errcode == -13) { std::cerr << "prices_syntheticprice overflow in price" << std::endl; return errcode; } - + if (errcode == -14) { + std::cerr << "prices_syntheticprice price is zero, not enough historic data yet" << std::endl; + return errcode; + } if (den == 0) { std::cerr << "prices_syntheticprice den==0 return err=-11" << std::endl; return(-11); @@ -1154,7 +1227,7 @@ int64_t prices_syntheticprice(std::vector vec, int32_t height, int32_t std::cerr << "prices_syntheticprice err=" << errcode << std::endl; return(errcode); } - std::cerr << "prices_syntheticprice priceIndex=" << priceIndex << " den=" << den << std::endl; +// std::cerr << "prices_syntheticprice priceIndex=totalprice/den=" << priceIndex << " den=" << den << std::endl; return priceIndex; } @@ -1191,24 +1264,24 @@ int32_t prices_syntheticprofits(int64_t &costbasis, int32_t firstheight, int32_t if (minmax) { // if we are within day window, set temp costbasis to max (or min) price value if (leverage > 0 && price > costbasis) { costbasis = price; // set temp costbasis - std::cerr << "prices_syntheticprofits() minmax costbasis=" << costbasis << std::endl; + //std::cerr << "prices_syntheticprofits() minmax costbasis=" << costbasis << std::endl; } else if (leverage < 0 && (costbasis == 0 || price < costbasis)) { costbasis = price; - std::cerr << "prices_syntheticprofits() minmax costbasis=" << costbasis << std::endl; + //std::cerr << "prices_syntheticprofits() minmax costbasis=" << costbasis << std::endl; } //else { //-> use the previous value // std::cerr << "prices_syntheticprofits() unchanged costbasis=" << costbasis << " price=" << price << " leverage=" << leverage << std::endl; //} } else { - if (height == firstheight + COSTBASIS_PERIOD) { + //if (height == firstheight + COSTBASIS_PERIOD) { // if costbasis not set, just set it //costbasis = price; // use calculated minmax costbasis - std::cerr << "prices_syntheticprofits() use permanent costbasis=" << costbasis << " at height=" << height << std::endl; - } + //std::cerr << "prices_syntheticprofits() use permanent costbasis=" << costbasis << " at height=" << height << std::endl; + //} } // normalize to 10,000,000 to prevent underflow @@ -1265,7 +1338,7 @@ int32_t prices_syntheticprofits(int64_t &costbasis, int32_t firstheight, int32_t else profits = 0; - std::cerr << "prices_syntheticprofits() profits=" << profits << std::endl; + //std::cerr << "prices_syntheticprofits() profits=" << profits << std::endl; return 0; // (positionsize + addedbets + profits); } @@ -1274,7 +1347,7 @@ void prices_betjson(UniValue &result, std::vector bets, int16_t leve { UniValue resultbets(UniValue::VARR); - int64_t totalbets = 0; + int64_t totalposition = 0; int64_t totalprofits = 0; for (auto b : bets) { @@ -1284,14 +1357,14 @@ void prices_betjson(UniValue &result, std::vector bets, int16_t leve entry.push_back(Pair("costbasis", ValueFromAmount(b.costbasis))); entry.push_back(Pair("firstheight", b.firstheight)); resultbets.push_back(entry); - totalbets += b.positionsize; + totalposition += b.positionsize; totalprofits += b.profits; } - int64_t equity = totalbets + totalprofits; + int64_t equity = totalposition + totalprofits; result.push_back(Pair("bets", resultbets)); result.push_back(Pair("leverage", (int64_t)leverage)); - result.push_back(Pair("TotalPositionSize", ValueFromAmount(totalbets))); + result.push_back(Pair("TotalPositionSize", ValueFromAmount(totalposition))); result.push_back(Pair("TotalProfits", ValueFromAmount(totalprofits))); result.push_back(Pair("equity", ValueFromAmount(equity))); result.push_back(Pair("LastPrice", ValueFromAmount(lastprice))); @@ -1363,9 +1436,9 @@ int64_t prices_enumaddedbets(uint256 &batontxid, std::vector &bets, addedBetsTotal += amount; added.positionsize = amount; - added.firstheight = blockIdx.GetHeight(); + added.firstheight = blockIdx.GetHeight(); //TODO: check if this is correct (to get height from the block not from the opret) bets.push_back(added); - std::cerr << "prices_batontxid() added amount=" << amount << std::endl; + //std::cerr << "prices_batontxid() added amount=" << amount << std::endl; } else { std::cerr << "prices_batontxid() cannot load or decode add bet tx, isLoaded=" << isLoaded << " funcId=" << (int)funcId << std::endl; @@ -1407,9 +1480,24 @@ UniValue PricesBet(int64_t txfee, int64_t amount, int16_t leverage, std::vector< result.push_back(Pair("error", "invalid synthetic")); return(result); } + + if (!prices_isacceptableamount(vec, amount, leverage)) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "too big amount and leverage")); + return(result); + } + if (AddNormalinputs(mtx, mypk, amount + 4 * txfee, 64) >= amount + 4 * txfee) { - betamount = (amount * 199) / 200; + betamount = PRICES_SUBREVSHAREFEE(amount); + + /*if( amount - betamount < PRICES_REVSHAREDUST) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "bet amount too small")); + return(result); + }*/ + + mtx.vout.push_back(MakeCC1vout(cp->evalcode, txfee, mypk)); // vout0 baton for total funding // mtx.vout.push_back(MakeCC1vout(cp->evalcode, (amount - betamount) + 2 * txfee, pricespk)); // vout1, when spent, costbasis is set mtx.vout.push_back(MakeCC1vout(cp->evalcode, txfee, pricespk)); // vout1 cc marker (NVOUT_CCMARKER) @@ -1422,7 +1510,8 @@ UniValue PricesBet(int64_t txfee, int64_t amount, int16_t leverage, std::vector< LOCK(cs_main); GetKomodoEarlytxidScriptPub(); } - mtx.vout.push_back(CTxOut(amount-betamount, KOMODO_EARLYTXID_SCRIPTPUB)); + mtx.vout.push_back(CTxOut(amount-betamount, KOMODO_EARLYTXID_SCRIPTPUB)); + //test: mtx.vout.push_back(CTxOut(amount - betamount, CScript() << ParseHex("037c803ec82d12da939ac04379bbc1130a9065c53d8244a61eece1db942cf0efa7") << OP_CHECKSIG)); // vout4 test revshare fee rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, prices_betopret(mypk, nextheight - 1, amount, leverage, firstprice, vec, zeroid)); return(prices_rawtxresult(result, rawtx, 0)); @@ -1437,11 +1526,14 @@ UniValue PricesAddFunding(int64_t txfee, uint256 bettxid, int64_t amount) { int32_t nextheight = komodo_nextheight(); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextheight); UniValue result(UniValue::VOBJ); - struct CCcontract_info *cp, C; CTransaction bettx; - CPubKey pricespk, mypk; - //int64_t addedbets = 0, betamount, firstprice; - std::vector vec; - uint256 batontxid; + struct CCcontract_info *cp, C; + CTransaction bettx; + CPubKey pricespk, mypk, pk; + int64_t positionsize, betamount, firstprice; + int32_t firstheight; + std::vector vecparsed; + uint256 batontxid, tokenid, hashBlock; + int16_t leverage = 0; std::string rawtx; //char myaddr[64]; @@ -1450,15 +1542,48 @@ UniValue PricesAddFunding(int64_t txfee, uint256 bettxid, int64_t amount) txfee = PRICES_TXFEE; mypk = pubkey2pk(Mypubkey()); pricespk = GetUnspendable(cp, 0); - //GetCCaddress(cp, myaddr, mypk); + + if (!myGetTransaction(bettxid, bettx, hashBlock) || + bettx.vout.size() <= 3 || + hashBlock.IsNull() || + prices_betopretdecode(bettx.vout.back().scriptPubKey, pk, firstheight, positionsize, leverage, firstprice, vecparsed, tokenid) != 'B') { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "invalid bet tx")); + return(result); + } + + if (!prices_isacceptableamount(vecparsed, amount, leverage)) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "too big amount and leverage")); + return(result); + } + if (AddNormalinputs(mtx, mypk, amount + 2*txfee, 64) >= amount + 2*txfee) { + betamount = PRICES_SUBREVSHAREFEE(amount); + /*if (amount - betamount < PRICES_REVSHAREDUST) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "bet amount too small")); + return(result); + }*/ + std::vector bets; if (prices_enumaddedbets(batontxid, bets, bettxid) >= 0) { mtx.vin.push_back(CTxIn(batontxid, 0, CScript())); mtx.vout.push_back(MakeCC1vout(cp->evalcode, txfee, mypk)); // vout0 baton for total funding - mtx.vout.push_back(MakeCC1vout(cp->evalcode, amount, pricespk)); // vout1 added amount + mtx.vout.push_back(MakeCC1vout(cp->evalcode, betamount, pricespk)); // vout1 added amount + + if (ASSETCHAINS_EARLYTXIDCONTRACT == EVAL_PRICES && KOMODO_EARLYTXID_SCRIPTPUB.size() == 0) + { + // Lock here, as in validation we cannot call lock in the function itself. + // may not be needed as the validation call to update the global, is called in a LOCK already, and it can only update there and here. + LOCK(cs_main); + GetKomodoEarlytxidScriptPub(); + } + mtx.vout.push_back(CTxOut(amount - betamount, KOMODO_EARLYTXID_SCRIPTPUB)); + // test: mtx.vout.push_back(CTxOut(amount - betamount, CScript() << ParseHex("037c803ec82d12da939ac04379bbc1130a9065c53d8244a61eece1db942cf0efa7") << OP_CHECKSIG)); //vout2 test revshare fee + rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, prices_addopret(bettxid, mypk, amount)); return(prices_rawtxresult(result, rawtx, 0)); } @@ -1481,9 +1606,9 @@ int32_t prices_scanchain(std::vector &bets, int16_t leverage, std::v return -1; bool stop = false; - for (int32_t height = bets[0].firstheight; ; height++) // the last datum for 24h is the costbasis value + for (int32_t height = bets[0].firstheight+1; ; height++) // the last datum for 24h is the costbasis value { - int64_t totalbets = 0; + int64_t totalposition = 0; int64_t totalprofits = 0; // scan upto the chain tip @@ -1493,11 +1618,11 @@ int32_t prices_scanchain(std::vector &bets, int16_t leverage, std::v int32_t retcode = prices_syntheticprofits(bets[i].costbasis, bets[i].firstheight, height, leverage, vec, bets[i].positionsize, bets[i].profits, lastprice); if (retcode < 0) { - std::cerr << "prices_scanchain() prices_syntheticprofits returned -1, breaking" << std::endl; + std::cerr << "prices_scanchain() prices_syntheticprofits returned -1, finishing..." << std::endl; stop = true; break; } - totalbets += bets[i].positionsize; + totalposition += bets[i].positionsize; totalprofits += bets[i].profits; } } @@ -1506,8 +1631,8 @@ int32_t prices_scanchain(std::vector &bets, int16_t leverage, std::v break; endheight = height; - int64_t equity = totalbets + totalprofits; - if (equity < 0) + int64_t equity = totalposition + totalprofits; + if (equity <= (int64_t)((double)totalposition * prices_minmarginpercent(leverage))) { // we are in loss break; } @@ -1588,6 +1713,34 @@ UniValue PricesSetcostbasis(int64_t txfee, uint256 bettxid) } +// pricesaddfunding rpc impl: add yet another bet +UniValue PricesRefillFund(int64_t amount) +{ + int32_t nextheight = komodo_nextheight(); + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextheight); UniValue result(UniValue::VOBJ); + struct CCcontract_info *cp, C; + CPubKey pricespk, mypk, pk; + std::string rawtx; + //char myaddr[64]; + + cp = CCinit(&C, EVAL_PRICES); + const int64_t txfee = PRICES_TXFEE; + mypk = pubkey2pk(Mypubkey()); + pricespk = GetUnspendable(cp, 0); + + if (AddNormalinputs(mtx, mypk, amount + txfee, 64) >= amount + txfee) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode, amount, pricespk)); // vout1 added amount + rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, CScript()); + return(prices_rawtxresult(result, rawtx, 0)); + + } + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "not enough funds")); + return(result); +} + + int32_t prices_getbetinfo(uint256 bettxid, BetInfo &betinfo) { CTransaction bettx; @@ -1598,39 +1751,64 @@ int32_t prices_getbetinfo(uint256 bettxid, BetInfo &betinfo) if (hashBlock.IsNull()) return -2; + + // TODO: forget old tx + //CBlockIndex *bi = komodo_getblockindex(hashBlock); + //if (bi && bi->GetHeight() < 5342) + // return -5; + OneBetData bet1; - if (prices_betopretdecode(bettx.vout.back().scriptPubKey, betinfo.pk, bet1.firstheight, bet1.positionsize, betinfo.leverage, betinfo.firstprice, betinfo.parsed, betinfo.tokenid) == 'B') + if (prices_betopretdecode(bettx.vout.back().scriptPubKey, betinfo.pk, bet1.firstheight, bet1.positionsize, betinfo.leverage, betinfo.firstprice, betinfo.vecparsed, betinfo.tokenid) == 'B') { uint256 finaltxid; int32_t vini; int32_t finaltxheight; //, endheight; //std::vector bets; - + betinfo.txid = bettxid; if (CCgetspenttxid(finaltxid, vini, finaltxheight, bettxid, NVOUT_CCMARKER) == 0) betinfo.isOpen = false; else betinfo.isOpen = true; - //bet1.amount = betinfo.positionsize; - //bet1.firstheight = firstheight; + // override with real amount (TODO: check this) + //bet1.positionsize = bettx.vout[2].nValue; + betinfo.bets.push_back(bet1); prices_enumaddedbets(batontxid, betinfo.bets, bettxid); - if (prices_scanchain(betinfo.bets, betinfo.leverage, betinfo.parsed, betinfo.lastprice, betinfo.lastheight) < 0) { + if (!betinfo.isOpen) { + CTransaction finaltx; + uint256 hashBlock; + vscript_t vopret; + if (myGetTransaction(finaltxid, finaltx, hashBlock) && finaltx.vout.size() > 0 && PricesCheckOpret(finaltx, vopret) != 0) { + uint8_t funcId = prices_finalopretdecode(finaltx.vout.back().scriptPubKey, betinfo.txid, betinfo.pk, betinfo.lastheight, betinfo.averageCostbasis, betinfo.lastprice, betinfo.liquidationprice, betinfo.equity, betinfo.exitfee); + if (funcId == 0) + return -3; + + betinfo.isRekt = (funcId == 'R'); + + // return 0; + } + else + return -6; + } + + + if (prices_scanchain(betinfo.bets, betinfo.leverage, betinfo.vecparsed, betinfo.lastprice, betinfo.lastheight) < 0) { return -4; } - mpz_t mpzTotalbets; + mpz_t mpzTotalPosition; mpz_t mpzTotalprofits; mpz_t mpzTotalcostbasis; - mpz_init(mpzTotalbets); + mpz_init(mpzTotalPosition); mpz_init(mpzTotalprofits); mpz_init(mpzTotalcostbasis); - int64_t totalbets = 0; + int64_t totalposition = 0; int64_t totalprofits = 0; for (auto b : betinfo.bets) { @@ -1649,26 +1827,26 @@ int32_t prices_getbetinfo(uint256 bettxid, BetInfo &betinfo) mpz_mul_ui(mpzProduct, mpzProduct, (uint64_t)b.positionsize); // b.costbasis * b.amount mpz_add(mpzTotalcostbasis, mpzTotalcostbasis, mpzProduct); //averageCostbasis += b.costbasis * b.amount; - mpz_add_ui(mpzTotalbets, mpzTotalbets, (uint64_t)b.positionsize); //totalbets += b.amount; + mpz_add_ui(mpzTotalPosition, mpzTotalPosition, (uint64_t)b.positionsize); //totalposition += b.amount; mpz_add(mpzTotalprofits, mpzTotalprofits, mpzProfits); //totalprofits += b.profits; - totalbets += b.positionsize; + totalposition += b.positionsize; totalprofits += b.profits; mpz_clear(mpzProduct); mpz_clear(mpzProfits); } - betinfo.equity = totalbets + totalprofits; + betinfo.equity = totalposition + totalprofits; //int64_t averageCostbasis = 0; - if (mpz_get_ui(mpzTotalbets) != 0) { //prevent zero div + if (mpz_get_ui(mpzTotalPosition) != 0) { //prevent zero div mpz_t mpzAverageCostbasis; mpz_init(mpzAverageCostbasis); - //averageCostbasis = totalcostbasis / totalbets; + //averageCostbasis = totalcostbasis / totalposition; mpz_mul_ui(mpzTotalcostbasis, mpzTotalcostbasis, SATOSHIDEN); // profits *= SATOSHIDEN normalization to prevent loss of significance while division - mpz_tdiv_q(mpzAverageCostbasis, mpzTotalcostbasis, mpzTotalbets); + mpz_tdiv_q(mpzAverageCostbasis, mpzTotalcostbasis, mpzTotalPosition); mpz_tdiv_q_ui(mpzAverageCostbasis, mpzAverageCostbasis, SATOSHIDEN); // profits /= SATOSHIDEN de-normalization @@ -1678,18 +1856,21 @@ int32_t prices_getbetinfo(uint256 bettxid, BetInfo &betinfo) betinfo.liquidationprice = 0; if (betinfo.leverage != 0) {// prevent zero div - betinfo.liquidationprice = betinfo.averageCostbasis - betinfo.averageCostbasis / betinfo.leverage; + betinfo.liquidationprice = betinfo.averageCostbasis - (betinfo.averageCostbasis * (1 - prices_minmarginpercent(betinfo.leverage))) / betinfo.leverage; } - if (betinfo.equity >= 0) - betinfo.isRekt = false; - else - { - betinfo.isRekt = true; - betinfo.rektfee = totalbets / 500; + if (!betinfo.isRekt) { // not set by check for final tx + + if (betinfo.equity > (int64_t)((double)totalposition * prices_minmarginpercent(betinfo.leverage))) + betinfo.isRekt = false; + else + { + betinfo.isRekt = true; + betinfo.exitfee = (int64_t)(((double)totalposition * prices_minmarginpercent(betinfo.leverage)) / 10); // was: totalposition / 500 + } } - mpz_clear(mpzTotalbets); + mpz_clear(mpzTotalPosition); mpz_clear(mpzTotalprofits); mpz_clear(mpzTotalcostbasis); return 0; @@ -1706,18 +1887,13 @@ UniValue PricesRekt(int64_t txfee, uint256 bettxid, int32_t rektheight) CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextheight); UniValue result(UniValue::VOBJ); struct CCcontract_info *cp, C; CTransaction bettx; -/* uint256 hashBlock, tokenid, batontxid; - int64_t firstprice, lastprice = 0, positionsize; - int32_t firstheight; - int16_t leverage; - std::vector vec; */ int64_t myfee = 0; CPubKey pk, mypk, pricespk; std::string rawtx; char destaddr[64]; cp = CCinit(&C, EVAL_PRICES); - if (txfee == 0) // TODO: what did we want tot do with txfee in prices? + if (txfee == 0) // TODO: what did we want to do with txfee in prices? txfee = PRICES_TXFEE; mypk = pubkey2pk(Mypubkey()); pricespk = GetUnspendable(cp, 0); @@ -1746,11 +1922,11 @@ UniValue PricesRekt(int64_t txfee, uint256 bettxid, int32_t rektheight) return(result); } - int64_t totalbets = 0; + int64_t totalposition = 0; int64_t totalprofits = 0; for (auto b : betinfo.bets) { - totalbets += b.positionsize; + totalposition += b.positionsize; totalprofits += b.profits; } @@ -1764,7 +1940,7 @@ UniValue PricesRekt(int64_t txfee, uint256 bettxid, int32_t rektheight) prices_betjson(result, betinfo.bets, betinfo.leverage, betinfo.lastheight, betinfo.lastprice); // fill output if (betinfo.isRekt) { - myfee = betinfo.rektfee; // consolation fee for loss + myfee = betinfo.exitfee; // consolation fee for loss } if (myfee != 0) { @@ -1778,8 +1954,37 @@ UniValue PricesRekt(int64_t txfee, uint256 bettxid, int32_t rektheight) mtx.vout.push_back(MakeCC1vout(cp->evalcode, CCchange, pricespk)); /// mtx.vout.push_back(MakeCC1vout(cp->evalcode, bettx.vout[2].nValue - myfee - txfee, pricespk)); // change - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, prices_finalopret(bettxid, totalprofits, rektheight, mypk, betinfo.firstprice, 0, totalbets /*- positionsize*/, 0/*positionsize*/, betinfo.leverage)); - return(prices_rawtxresult(result, rawtx, 0)); + + // make some PoW to get txid=0x00.....00 to 'faucet' rekts + fprintf(stderr, "start PoW at %u\n", (uint32_t)time(NULL)); + uint32_t nonce = rand() & 0xfffffff; + for (int i = 0; i<1000000; i++, nonce++) + { + CMutableTransaction tmpmtx = mtx; + //int32_t len; + //uint8_t txbuf[32768]; + + rawtx = FinalizeCCTx(0, cp, tmpmtx, mypk, txfee, prices_finalopret(true, bettxid, mypk, betinfo.lastheight, betinfo.averageCostbasis, betinfo.lastprice, betinfo.liquidationprice, betinfo.equity, myfee, nonce)); + //if ((len = (int32_t)rawtx.size()) > 0 && len < sizeof(txbuf) / sizeof(txbuf[0]) * 2) + //{ + // len >>= 1; // sizeof hex divide by 2 + //decode_hex(txbuf, len, (char *)rawtx.c_str()); + //bits256 hash = bits256_doublesha256(0, txbuf, len); + uint256 hash = tmpmtx.GetHash(); + //if ((hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0) + if ((hash.begin()[0] & 0xff) == 0 && (hash.begin()[31] & 0xff) == 0) + { + fprintf(stderr, "found valid txid after %d iterations %u\n", i, (uint32_t)time(NULL)); + return(prices_rawtxresult(result, rawtx, 0)); + } + //fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]); + //} + } + fprintf(stderr, "couldnt generate valid txid %u\n", (uint32_t)time(NULL)); + + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "could not generate valid txid")); + return(result); } else { @@ -1796,12 +2001,6 @@ UniValue PricesCashout(int64_t txfee, uint256 bettxid) CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextheight); UniValue result(UniValue::VOBJ); struct CCcontract_info *cp, C; char destaddr[64]; -/* CTransaction bettx; - uint256 hashBlock, batontxid, tokenid; - int64_t positionsize, firstprice, lastprice = 0; - int32_t firstheight; - int16_t leverage; - std::vector vec;*/ int64_t CCchange = 0, inputsum; CPubKey pk, mypk, pricespk; std::string rawtx; @@ -1837,11 +2036,11 @@ UniValue PricesCashout(int64_t txfee, uint256 bettxid) return(result); } - int64_t totalbets = 0; + int64_t totalposition = 0; int64_t totalprofits = 0; for (auto b : betinfo.bets) { - totalbets += b.positionsize; + totalposition += b.positionsize; totalprofits += b.profits; } @@ -1862,20 +2061,18 @@ UniValue PricesCashout(int64_t txfee, uint256 bettxid) } mtx.vin.push_back(CTxIn(bettxid, NVOUT_CCMARKER, CScript())); // spend cc marker - if ((inputsum = AddPricesInputs(cp, mtx, destaddr, betinfo.equity + txfee, 64)) > betinfo.equity + txfee) + if ((inputsum = AddPricesInputs(cp, mtx, destaddr, betinfo.equity + txfee, 64)) > betinfo.equity + txfee) // TODO: why txfee from the fund? CCchange = (inputsum - betinfo.equity); mtx.vout.push_back(CTxOut(betinfo.equity, CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); if (CCchange >= txfee) mtx.vout.push_back(MakeCC1vout(cp->evalcode, CCchange, pricespk)); // TODO: what should the opret param be: - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, prices_finalopret(bettxid, totalprofits, nextheight - 1, mypk, betinfo.firstprice, 0, totalbets/*- betinfo.positionsize*/, 0/*betinfo.positionsize*/, betinfo.leverage)); + rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, prices_finalopret(false, bettxid, mypk, nextheight-1, betinfo.averageCostbasis, betinfo.lastprice, betinfo.liquidationprice, betinfo.equity, txfee, 0)); return(prices_rawtxresult(result, rawtx, 0)); } - - // pricesinfo rpc impl UniValue PricesInfo(uint256 bettxid, int32_t refheight) { @@ -1908,6 +2105,10 @@ UniValue PricesInfo(uint256 bettxid, int32_t refheight) else if (retcode == -4) { result.push_back(Pair("result", "error")); result.push_back(Pair("error", "error scanning chain")); + } + else { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", retcode)); } return(result); } @@ -1917,11 +2118,13 @@ UniValue PricesInfo(uint256 bettxid, int32_t refheight) else { result.push_back(Pair("rekt", (int64_t)1)); - result.push_back(Pair("rektfee", betinfo.rektfee)); + result.push_back(Pair("rektfee", betinfo.exitfee)); result.push_back(Pair("rektheight", betinfo.lastheight)); } - std::string expr = prices_getsourceexpression(betinfo.parsed); + result.push_back(Pair("open", betinfo.isOpen ? 1 : 0 )); + + std::string expr = prices_getsourceexpression(betinfo.vecparsed); result.push_back(Pair("expression", expr)); result.push_back(Pair("reduced", prices_getreducedexpr(expr))); // result.push_back(Pair("batontxid", batontxid.GetHex())); @@ -1960,6 +2163,12 @@ UniValue PricesList(uint32_t filter, CPubKey mypk) if (GetTransaction(txid, vintx, hashBlock, false) != 0) { + + // TODO: forget old tx + //CBlockIndex *bi = komodo_getblockindex(hashBlock); + //if (bi && bi->GetHeight() < 5342) + // return; + bool bAppend = false; if (vintx.vout.size() > 0 && prices_betopretdecode(vintx.vout.back().scriptPubKey, pk, height, amount, leverage, firstprice, vec, tokenid) == 'B' && (mypk == CPubKey() || mypk == pk)) // if only mypubkey to list @@ -1987,7 +2196,7 @@ UniValue PricesList(uint32_t filter, CPubKey mypk) SetCCtxids(addressIndex, cp->normaladdr, false); // old normal marker for (std::vector >::const_iterator it = addressIndex.begin(); it != addressIndex.end(); it++) { - if( it->first.txindex == NVOUT_NORMALMARKER ) + if( it->first.index == NVOUT_NORMALMARKER ) AddBetToList(it->first.txhash); } @@ -2002,12 +2211,244 @@ UniValue PricesList(uint32_t filter, CPubKey mypk) } -void prices_addbookentry(uint256 txid) +static bool prices_addbookentry(uint256 txid, std::vector &book) { BetInfo betinfo; - //if( prices_getbetinfo(txid, betinfo) == 0 ) + if (prices_getbetinfo(txid, betinfo) == 0) { + book.push_back(betinfo); + return true; + } + return false; } + +static bool prices_ispositionup(const std::vector &vecparsed, int16_t leverage) { + if (vecparsed.size() > 1 && vecparsed.size() <= 3) { + uint16_t opcode = vecparsed[0]; + + int32_t value = (opcode & (KOMODO_MAXPRICES - 1)); // filter index or weight = opcode & (2048-1) + + if ((opcode & KOMODO_PRICEMASK) == 0) { + char name[65]; + if (komodo_pricename(name, value)) { + std::string upperquote, bottomquote; + prices_splitpair(std::string(name), upperquote, bottomquote); + + uint16_t opcode1 = vecparsed[1]; + bool isInverted = ((opcode1 & KOMODO_PRICEMASK) == PRICES_INV); + + //std::cerr << "prices_ispositionup upperquote=" << upperquote << " bottomquote=" << bottomquote << " opcode1=" << opcode1 << " (opcode1 & KOMODO_PRICEMASK)=" << (opcode1 & KOMODO_PRICEMASK) << std::endl; + + if (upperquote == "BTC" || bottomquote == "BTC") { // it is relatively btc + if (upperquote == "BTC" && (leverage > 0 && !isInverted || leverage < 0 && isInverted) || + bottomquote == "BTC" && (leverage < 0 && !isInverted || leverage > 0 && isInverted)) { + std::cerr << "prices_ispositionup returns true for BTC for expr=" << prices_getsourceexpression(vecparsed) << " lev=" << leverage << std::endl; + return true; + } + else { + std::cerr << "prices_ispositionup returns false for BTC for expr=" << prices_getsourceexpression(vecparsed) << " lev=" << leverage << std::endl; + return false; + } + } + + if (upperquote == "USD" || bottomquote == "USD") { // it is relatively usd + if (upperquote == "USD" && (leverage > 0 && !isInverted || leverage < 0 && isInverted) || + bottomquote == "USD" && (leverage < 0 && !isInverted || leverage > 0 && isInverted)) { + std::cerr << "prices_ispositionup returns true for USD for expr=" << prices_getsourceexpression(vecparsed) << " lev=" << leverage << std::endl; + return true; + } + else { + std::cerr << "prices_ispositionup returns false for USD for expr=" << prices_getsourceexpression(vecparsed) << " lev=" << leverage << std::endl; + return false; + } + } + } + } + } + std::cerr << "prices_ispositionup returns false for expr=" << prices_getsourceexpression(vecparsed) << " lev=" << leverage << std::endl; + return false; +} + +static bool prices_isopposite(BetInfo p1, BetInfo p2) { + if (p1.vecparsed.size() <= 3 && p2.vecparsed.size() <= 3) { // simple synthetic exp + + uint16_t opcode1 = p1.vecparsed[0]; + uint16_t opcode2 = p2.vecparsed[0]; + + int32_t value1 = (opcode1 & (KOMODO_MAXPRICES - 1)); // index or weight + int32_t value2 = (opcode2 & (KOMODO_MAXPRICES - 1)); // index or weight + + if ( (opcode1 & KOMODO_PRICEMASK) == 0 && (opcode2 & KOMODO_PRICEMASK) == 0 ) { + char name1[65]; + char name2[65]; + if (komodo_pricename(name1, value1) && komodo_pricename(name2, value2)) { + + uint16_t opcode1 = p1.vecparsed[1]; + uint16_t opcode2 = p2.vecparsed[1]; + + std::string upperquote1, bottomquote1, upperquote2, bottomquote2; + prices_splitpair(std::string(name1), upperquote1, bottomquote1); + prices_splitpair(std::string(name2), upperquote2, bottomquote2); + + bool isInverted1 = ((opcode1 & KOMODO_PRICEMASK) != PRICES_INV); + bool isInverted2 = ((opcode2 & KOMODO_PRICEMASK) != PRICES_INV); + + if (/*upperquote1 == bottomquote2 && bottomquote1 == upperquote2 && (p1.leverage > 0 == p2.leverage > 0 || (opcode1 & KOMODO_PRICEMASK) == PRICES_INV == (opcode2 & KOMODO_PRICEMASK) == PRICES_INV) ||*/ + upperquote1 == upperquote2 && bottomquote1 == bottomquote2 && ((p1.leverage > 0) != (p2.leverage > 0) || isInverted1 != isInverted2) ) + return true; + } + } + } + return false; +} + + + +static std::string findMatchedBook(const std::vector &vecparsed, const std::map > & bookmatched) { + + if (vecparsed.size() > 1 && vecparsed.size() <= 3) { + uint16_t opcode = vecparsed[0]; + + int32_t value = (opcode & (KOMODO_MAXPRICES - 1)); // filter index or weight = opcode & (2048-1) + + if ((opcode & KOMODO_PRICEMASK) == 0) { + char name[65]; + if (komodo_pricename(name, value)) { + auto it = bookmatched.find(std::string(name)); + if (it != bookmatched.end()) + return it->first; + } + } + } + return std::string(""); +} + + +void prices_getorderbook(std::map > & bookmatched, std::map &matchedTotals, TotalFund &fundTotals) +{ + std::vector book; + std::vector > addressIndex; + struct CCcontract_info *cp, C; + + cp = CCinit(&C, EVAL_PRICES); + + // add all bets: + SetCCtxids(addressIndex, cp->normaladdr, false); // old normal marker + for (std::vector >::const_iterator it = addressIndex.begin(); it != addressIndex.end(); it++) + { + if (it->first.index == NVOUT_NORMALMARKER) + prices_addbookentry(it->first.txhash, book); + } + + + // calc total fund amount + fundTotals.totalFund = 0; + fundTotals.totalRekt = 0; + fundTotals.totalEquity = 0; + fundTotals.totalActiveBets = 0; + + std::vector > addressCCunspents; + SetCCunspents(addressCCunspents, cp->unspendableCCaddr, true); // cc marker + for (std::vector >::const_iterator it = addressCCunspents.begin(); it != addressCCunspents.end(); it++) + { + //std::cerr << "totalfund calc txid=" << it->first.txhash.GetHex() << " nvout=" << it->first.index << " satoshis=" << it->second.satoshis << std::endl; + fundTotals.totalFund += it->second.satoshis; + } + + // extract out opposite bets: + while (book.size() > 0) { + + int64_t totalPos = 0; + for (auto bet : book[0].bets) totalPos += bet.positionsize; + + if (book[0].isOpen) { + + fundTotals.totalActiveBets += totalPos; + fundTotals.totalEquity += book[0].equity; + + if (book[0].vecparsed.size() <= 3) { // only short expr check for match: "BTC_USD,1" or "BTC_USD,!,1" + char name[65]; + komodo_pricename(name, (book[0].vecparsed[0] & (KOMODO_MAXPRICES - 1))); + std::string sname = name; + bookmatched[sname].push_back(book[0]); + + for (int j = 1; j < book.size(); j++) { + if (book[0].isOpen && book[j].isOpen) { + if (prices_isopposite(book[0], book[j])) { + + bookmatched[sname].push_back(book[j]); + book.erase(book.begin() + j); + } + } + } + } + else { + // store as is + std::string sname = prices_getsourceexpression(book[0].vecparsed); + bookmatched[sname].push_back(book[0]); + } + } + else { + if( book[0].isRekt ) + fundTotals.totalRekt += (totalPos - book[0].exitfee); + else + fundTotals.totalCashout += (totalPos - book[0].exitfee); + + //TODO: store rekt + } + book.erase(book.begin()); + } + + // calculate cancelling amount + for (auto &m : bookmatched) { // note: use reference &m otherwise isUp will be changed only in a copy + int64_t totalLeveragedPositionUp = 0; + int64_t totalLeveragedPositionDown = 0; + + for (int i = 0; i < m.second.size(); i++) { + int64_t totalPos = 0; + for (auto bet : m.second[i].bets) totalPos += bet.positionsize; + m.second[i].isUp = prices_ispositionup(m.second[i].vecparsed, m.second[i].leverage); + if (m.second[i].isUp) + totalLeveragedPositionUp += totalPos * abs(m.second[i].leverage); + else + totalLeveragedPositionDown += totalPos * abs(m.second[i].leverage); + //std::cerr << "PricesGetOrderbook 0 m.second[i].isUp=" << m.second[i].isUp << " i=" << i << std::endl; + + } + matchedTotals[m.first].diffLeveragedPosition = totalLeveragedPositionUp - totalLeveragedPositionDown; + } +} + +static bool prices_isacceptableamount(const std::vector &vecparsed, int64_t amount, int16_t leverage) { + + std::map > matchedBook; + std::map matchedTotals; + TotalFund fundTotals; + + prices_getorderbook(matchedBook, matchedTotals, fundTotals); + std::string pricename = findMatchedBook(vecparsed, matchedBook); + if (!pricename.empty()) { + std::cerr << "prices_isacceptableamount() found matched book=" << pricename << " diffLeveragedPosition=" << matchedTotals[pricename].diffLeveragedPosition << " expr=" << prices_getsourceexpression(vecparsed) << std::endl; + // could fit into leveraged amount + if (prices_ispositionup(vecparsed, leverage) && amount*abs(leverage) + matchedTotals[pricename].diffLeveragedPosition <= 0) { + std::cerr << "prices_isacceptableamount() could fit into opposite negative lev amount" << std::endl; + return true; + } + if (!prices_ispositionup(vecparsed, leverage) && -amount*abs(leverage) + matchedTotals[pricename].diffLeveragedPosition >= 0) { + std::cerr << "prices_isacceptableamount() could fit into opposite positive lev amount" << std::endl; + return true; + } + } + + std::cerr << "prices_isacceptableamount() amount=" << amount << " leverage=" << leverage << " fundTotals.totalFund=" << fundTotals.totalFund << " fundTotals.totalEquity=" << fundTotals.totalEquity << std::endl; + // if not fit to matched = allow to bet for leveraged amount no more than 10% from free fund + if (amount * leverage < (fundTotals.totalFund - fundTotals.totalEquity) * PRICES_MINAVAILFUNDFRACTION) + return true; + + return false; +} + + // walk through uxtos on the global address // calculate the balance: // + rekt positions @@ -2015,17 +2456,65 @@ void prices_addbookentry(uint256 txid) // - unbalanced positions UniValue PricesGetOrderbook() { - UniValue result(UniValue::VARR); - std::vector > addressIndex, addressIndexCC; - struct CCcontract_info *cp, C; + UniValue result(UniValue::VOBJ); + std::map > matchedBook; + std::map matchedTotals; + TotalFund fundTotals; - cp = CCinit(&C, EVAL_PRICES); + prices_getorderbook(matchedBook, matchedTotals, fundTotals); - SetCCtxids(addressIndex, cp->normaladdr, false); // old normal marker - for (std::vector >::const_iterator it = addressIndex.begin(); it != addressIndex.end(); it++) - { - if (it->first.txindex == NVOUT_NORMALMARKER) - prices_addbookentry(it->first.txhash); + /*UniValue resbook (UniValue::VARR); + for (int i = 0; i < book.size(); i++) { + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("expression", prices_getsourceexpression(book[i].vecparsed))); + entry.push_back(Pair("costbasis", book[i].averageCostbasis)); + entry.push_back(Pair("leverage", book[i].leverage)); + entry.push_back(Pair("equity", book[i].equity)); + resbook.push_back(entry); } + result.push_back(Pair("unmatched", resbook)); */ + + // copy to rpc UniResult + for (auto &m : matchedBook) { + UniValue resheader(UniValue::VOBJ); + UniValue resbook(UniValue::VARR); + for (int i = 0; i < m.second.size(); i++) { + UniValue entry(UniValue::VOBJ); + + int64_t totalPos = 0; + for (auto bet : m.second[i].bets) totalPos += bet.positionsize; + entry.push_back(Pair("isOpen", (m.second[i].isOpen ? 1 : 0 ))); + entry.push_back(Pair("expression", prices_getsourceexpression(m.second[i].vecparsed))); + entry.push_back(Pair("positionsize", totalPos)); + entry.push_back(Pair("leverage", m.second[i].leverage)); + entry.push_back(Pair("costbasis", m.second[i].averageCostbasis)); + entry.push_back(Pair("lastprice", m.second[i].lastprice)); + entry.push_back(Pair("equity", m.second[i].equity)); + entry.push_back(Pair("isUpPosition", (m.second[i].isUp ? 1 : 0))); + resbook.push_back(entry); + } + resheader.push_back(Pair("positions", resbook)); + resheader.push_back(Pair("DiffLeveragedPosition", matchedTotals[m.first].diffLeveragedPosition)); + result.push_back(Pair(m.first, resheader)); + } + + //int64_t totalLiabilities = 0; + /* empty + for (int i = 0; i < book.size(); i++) { + if (book[i].isOpen) { + int64_t t = 0; + for (auto b : book[i].bets) t += b.positionsize; + std::cerr << "book[i].txid=" << book[i].txid.GetHex() << " exp=" << prices_getsourceexpression(book[i].vecparsed) << " totalpos=" << t << " equity=" << book[i].equity << std::endl; + totalLiabilities += book[i].equity; + } + } */ + + result.push_back(Pair("TotalFund", ValueFromAmount(fundTotals.totalFund))); + result.push_back(Pair("TotalEquity", ValueFromAmount(fundTotals.totalEquity))); + result.push_back(Pair("TotalRekt", ValueFromAmount(fundTotals.totalRekt))); + result.push_back(Pair("TotalBets", ValueFromAmount(fundTotals.totalActiveBets))); + result.push_back(Pair("TotalCashoutBets", ValueFromAmount(fundTotals.totalCashout))); + +// result.push_back(Pair("TotalLiabilities", ValueFromAmount(totalLiabilities))); return result; } diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index 5ca2b038a..2edd275ec 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -195,6 +195,7 @@ bool RewardsExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransactio bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { uint256 txid,fundingtxid,hashBlock,vinfundingtxid; uint64_t vinsbits,sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx; + int64_t dummy; numvins = tx.vin.size(); numvouts = tx.vout.size(); preventCCvins = preventCCvouts = -1; @@ -255,7 +256,7 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 ) return eval->Invalid("unexpected normal vin for unlock"); } - if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) + if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime, dummy) ) return eval->Invalid("txfee is too high"); amount = vinTx.vout[0].nValue; reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit); diff --git a/src/crypto/verus_hash.h b/src/crypto/verus_hash.h index 2f1f2cd26..63ff1aaaa 100644 --- a/src/crypto/verus_hash.h +++ b/src/crypto/verus_hash.h @@ -1,134 +1,134 @@ -// (C) 2018 Michael Toutonghi -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -/* -This provides the PoW hash function for Verus, enabling CPU mining. -*/ -#ifndef VERUS_HASH_H_ -#define VERUS_HASH_H_ - -#include -#include - -#include - -extern "C" -{ -#include "crypto/haraka.h" -#include "crypto/haraka_portable.h" -} - -class CVerusHash -{ - public: - static void Hash(void *result, const void *data, size_t len); - static void (*haraka512Function)(unsigned char *out, const unsigned char *in); - - static void init(); - - CVerusHash() { } - - CVerusHash &Write(const unsigned char *data, size_t len); - - CVerusHash &Reset() - { - curBuf = buf1; - result = buf2; - curPos = 0; - std::fill(buf1, buf1 + sizeof(buf1), 0); - return *this; - } - - int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } - void ClearExtra() - { - if (curPos) - { - std::fill(curBuf + 32 + curPos, curBuf + 64, 0); - } - } - void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); } - - void Finalize(unsigned char hash[32]) - { - if (curPos) - { - std::fill(curBuf + 32 + curPos, curBuf + 64, 0); - (*haraka512Function)(hash, curBuf); - } - else - std::memcpy(hash, curBuf, 32); - } - - private: - // only buf1, the first source, needs to be zero initialized - unsigned char buf1[64] = {0}, buf2[64]; - unsigned char *curBuf = buf1, *result = buf2; - size_t curPos = 0; -}; - -class CVerusHashV2 -{ - public: - static void Hash(void *result, const void *data, size_t len); - static void (*haraka512Function)(unsigned char *out, const unsigned char *in); - - static void init(); - - CVerusHashV2() {} - - CVerusHashV2 &Write(const unsigned char *data, size_t len); - - CVerusHashV2 &Reset() - { - curBuf = buf1; - result = buf2; - curPos = 0; - std::fill(buf1, buf1 + sizeof(buf1), 0); - return *this; - } - - int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } - void ClearExtra() - { - if (curPos) - { - std::fill(curBuf + 32 + curPos, curBuf + 64, 0); - } - } - void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); } - - void Finalize(unsigned char hash[32]) - { - if (curPos) - { - std::fill(curBuf + 32 + curPos, curBuf + 64, 0); - (*haraka512Function)(hash, curBuf); - } - else - std::memcpy(hash, curBuf, 32); - } - - private: - // only buf1, the first source, needs to be zero initialized - unsigned char buf1[64] = {0}, buf2[64]; - unsigned char *curBuf = buf1, *result = buf2; - size_t curPos = 0; -}; - -extern void verus_hash(void *result, const void *data, size_t len); -extern void verus_hash_v2(void *result, const void *data, size_t len); - -inline bool IsCPUVerusOptimized() -{ - unsigned int eax,ebx,ecx,edx; - - if (!__get_cpuid(1,&eax,&ebx,&ecx,&edx)) - { - return false; - } - return ((ecx & (bit_AVX | bit_AES)) == (bit_AVX | bit_AES)); -}; - -#endif +// (C) 2018 Michael Toutonghi +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/* +This provides the PoW hash function for Verus, enabling CPU mining. +*/ +#ifndef VERUS_HASH_H_ +#define VERUS_HASH_H_ + +#include +#include + +#include + +extern "C" +{ +#include "crypto/haraka.h" +#include "crypto/haraka_portable.h" +} + +class CVerusHash +{ + public: + static void Hash(void *result, const void *data, size_t len); + static void (*haraka512Function)(unsigned char *out, const unsigned char *in); + + static void init(); + + CVerusHash() { } + + CVerusHash &Write(const unsigned char *data, size_t len); + + CVerusHash &Reset() + { + curBuf = buf1; + result = buf2; + curPos = 0; + std::fill(buf1, buf1 + sizeof(buf1), 0); + return *this; + } + + int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } + void ClearExtra() + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + } + } + void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); } + + void Finalize(unsigned char hash[32]) + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + (*haraka512Function)(hash, curBuf); + } + else + std::memcpy(hash, curBuf, 32); + } + + private: + // only buf1, the first source, needs to be zero initialized + unsigned char buf1[64] = {0}, buf2[64]; + unsigned char *curBuf = buf1, *result = buf2; + size_t curPos = 0; +}; + +class CVerusHashV2 +{ + public: + static void Hash(void *result, const void *data, size_t len); + static void (*haraka512Function)(unsigned char *out, const unsigned char *in); + + static void init(); + + CVerusHashV2() {} + + CVerusHashV2 &Write(const unsigned char *data, size_t len); + + CVerusHashV2 &Reset() + { + curBuf = buf1; + result = buf2; + curPos = 0; + std::fill(buf1, buf1 + sizeof(buf1), 0); + return *this; + } + + int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } + void ClearExtra() + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + } + } + void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); } + + void Finalize(unsigned char hash[32]) + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + (*haraka512Function)(hash, curBuf); + } + else + std::memcpy(hash, curBuf, 32); + } + + private: + // only buf1, the first source, needs to be zero initialized + unsigned char buf1[64] = {0}, buf2[64]; + unsigned char *curBuf = buf1, *result = buf2; + size_t curPos = 0; +}; + +extern void verus_hash(void *result, const void *data, size_t len); +extern void verus_hash_v2(void *result, const void *data, size_t len); + +inline bool IsCPUVerusOptimized() +{ + unsigned int eax,ebx,ecx,edx; + + if (!__get_cpuid(1,&eax,&ebx,&ecx,&edx)) + { + return false; + } + return ((ecx & (bit_AVX | bit_AES)) == (bit_AVX | bit_AES)); +}; + +#endif diff --git a/src/deprecation.h b/src/deprecation.h index 427234b4a..dde45e22c 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -24,7 +24,7 @@ // * Shut down WEEKS_UNTIL_DEPRECATION weeks' worth of blocks after the estimated release block height. // * A warning is shown during the DEPRECATION_WARN_LIMIT worth of blocks prior to shut down. static const int WEEKS_UNTIL_DEPRECATION = 52; -static const int DEPRECATION_HEIGHT = 1600000; +static const int DEPRECATION_HEIGHT = 2200000; static const int APPROX_RELEASE_HEIGHT = DEPRECATION_HEIGHT - (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 60); // Number of blocks before deprecation to warn users diff --git a/src/fiat/k64 b/src/fiat/k64 new file mode 100755 index 000000000..a3b3bc835 --- /dev/null +++ b/src/fiat/k64 @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=K64 $1 $2 $3 $4 $5 $6 diff --git a/src/fiat/zex b/src/fiat/zex deleted file mode 100755 index f4573c093..000000000 --- a/src/fiat/zex +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -./komodo-cli -ac_name=ZEX $1 $2 $3 $4 $5 $6 diff --git a/src/fiat/zexo b/src/fiat/zexo new file mode 100755 index 000000000..b6fd508f2 --- /dev/null +++ b/src/fiat/zexo @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=ZEXO $1 $2 $3 $4 $5 $6 diff --git a/src/komodo.h b/src/komodo.h index b4c7d12bf..4de6ee4f3 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -713,9 +713,9 @@ int32_t komodo_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notar sp->MoMdepth = MoMdepth; } komodo_stateupdate(height,0,0,0,zero,0,0,0,0,0,0,0,0,0,0,sp->MoM,sp->MoMdepth); - if ( ASSETCHAINS_SYMBOL[0] != 0 ) + //if ( ASSETCHAINS_SYMBOL[0] != 0 ) printf("[%s] ht.%d NOTARIZED.%d %s.%s %sTXID.%s lens.(%d %d) MoM.%s %d\n",ASSETCHAINS_SYMBOL,height,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,srchash.ToString().c_str(),ASSETCHAINS_SYMBOL[0]==0?"BTC":"KMD",desttxid.ToString().c_str(),opretlen,len,sp->MoM.ToString().c_str(),sp->MoMdepth); - + if ( ASSETCHAINS_SYMBOL[0] == 0 ) { if ( signedfp == 0 ) @@ -803,7 +803,10 @@ int32_t komodo_notarycmp(uint8_t *scriptPubKey,int32_t scriptlen,uint8_t pubkeys return(-1); } -// int32_t ! +// int32_t (!!!) +/* + read blackjok3rtt comments in main.cpp +*/ int32_t komodo_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block) { static int32_t hwmheight; @@ -897,8 +900,8 @@ int32_t komodo_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block) } numvalid = bitweight(signedmask); if ( ((height < 90000 || (signedmask & 1) != 0) && numvalid >= KOMODO_MINRATIFY) || - (numvalid >= KOMODO_MINRATIFY && ASSETCHAINS_SYMBOL[0] != 0) || - numvalid > (numnotaries/5) ) + (numvalid >= KOMODO_MINRATIFY && ASSETCHAINS_SYMBOL[0] != 0) || + numvalid > (numnotaries/5) ) { if ( !fJustCheck && ASSETCHAINS_SYMBOL[0] != 0) { @@ -918,7 +921,7 @@ int32_t komodo_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block) fflush(signedfp); } transaction = i; - printf("[%s] ht.%d txi.%d signedmask.%llx numvins.%d numvouts.%d <<<<<<<<<<< notarized\n",ASSETCHAINS_SYMBOL,height,i,(long long)signedmask,numvins,numvouts); + printf("[%s] ht.%d txi.%d signedmask.%llx numvins.%d numvouts.%d <<<<<<<<<<< notarized\n",ASSETCHAINS_SYMBOL,height,i,(long long)signedmask,numvins,numvouts); } notarized = 1; } @@ -1014,7 +1017,9 @@ int32_t komodo_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block) printf("%s ht.%d\n",ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL,height); if ( !fJustCheck && pindex->GetHeight() == hwmheight ) komodo_stateupdate(height,0,0,0,zero,0,0,0,0,height,(uint32_t)pindex->nTime,0,0,0,0,zero,0); - } else fprintf(stderr,"komodo_connectblock: unexpected null pindex\n"); + } + else + { fprintf(stderr,"komodo_connectblock: unexpected null pindex\n"); return(0); } //KOMODO_INITDONE = (uint32_t)time(NULL); //fprintf(stderr,"%s end connect.%d\n",ASSETCHAINS_SYMBOL,pindex->GetHeight()); if (fJustCheck) @@ -1025,6 +1030,12 @@ int32_t komodo_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block) return(1); if ( notarisations.size() > 1 || (notarisations.size() == 1 && notarisations[0] != 1) ) return(-1); + + fprintf(stderr,"komodo_connectblock: unxexpected behaviour when fJustCheck == true, report blackjok3rtt plz ! \n"); + /* this needed by gcc-8, it counts here that control reaches end of non-void function without this. + by default, we count that if control reached here -> the valid notarization isnt in position 1 or there are too many notarizations in this block. + */ + return(-1); } else return(0); } diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index e616fb179..48962b015 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -682,11 +682,32 @@ int32_t komodo_WhoStaked(CBlock *pblock, CTxDestination &addressout) bool MarmaraPoScheck(char *destaddr,CScript opret,CTransaction staketx); -int32_t komodo_isPoS(CBlock *pblock,int32_t height) +int32_t komodo_isPoS2(CBlock *pblock) { - int32_t n,vout,numvouts; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid; CScript opret; + CBlockIndex *pindex = komodo_blockindex(pblock->GetHash()); + if ( pindex != 0 && pindex->segid >= -1 ) + { + //fprintf(stderr,"isPoSblock segid.%d\n",pindex->segid); + if ( pindex->segid == -1 ) + return(0); + else return(1); + } + return (-1); +} + +int32_t komodo_isPoS(CBlock *pblock,int32_t height,bool fJustCheck) +{ + int32_t n,vout,numvouts,ret; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid; CScript opret; if ( ASSETCHAINS_STAKED != 0 ) { + if ( fJustCheck ) + { + // check pindex first, if that does not work, continue with slow check. + if ( (ret= komodo_isPoS2(pblock)) == 1 ) + return (1); + else if ( ret == 0 ) + return (0); + } n = pblock->vtx.size(); //fprintf(stderr,"ht.%d check for PoS numtx.%d numvins.%d numvouts.%d\n",height,n,(int32_t)pblock->vtx[n-1].vin.size(),(int32_t)pblock->vtx[n-1].vout.size()); if ( n > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1+(ASSETCHAINS_MARMARA!=0) ) @@ -1401,10 +1422,6 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he if ( ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH || ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASHV1_1 ) percPoS = (percPoS*100) / (m+n); else - // This seems to be inverse. The actual PoS % is backwards in the first 100 blocks. - // I dont't understand the math here, or why its backwards, so I am just disabling it for VerusHash. - // No doubt this is probably wrong for equihash aswell, we may need to test an equihash chain with the rule above. - // Need to ask james what the deal is here! Seems to be causeing ALL the problems. percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100; } if ( dispflag != 0 && ASSETCHAINS_STAKED < 100 ) @@ -1585,7 +1602,7 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget,arith_uint256 bhash) { - CBlockIndex *previndex,*pindex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,PoSperc,txn_count,eligible=0,isPoS = 0,segid; uint64_t value; CTxDestination voutaddress; arith_uint256 POWTarget; + CBlockIndex *previndex,*pindex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t ret,vout,PoSperc,txn_count,eligible=0,isPoS = 0,segid; uint64_t value; CTxDestination voutaddress; arith_uint256 POWTarget; if ( ASSETCHAINS_STAKED == 100 && height <= 10 ) return(1); BlockMap::const_iterator it = mapBlockIndex.find(pblock->GetHash()); @@ -1612,7 +1629,7 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_ vout = pblock->vtx[txn_count-1].vin[0].prevout.n; if ( slowflag != 0 && prevtime != 0 ) { - if ( komodo_isPoS(pblock,height) != 0 ) + if ( komodo_isPoS(pblock,height,false) != 0 ) { eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"",PoSperc); } @@ -1644,7 +1661,7 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_ } else if ( slowflag == 0 ) // previous blocks are not seen yet, do the best approx { - if ( komodo_isPoS(pblock,height) != 0 ) + if ( komodo_isPoS(pblock,height,false) != 0 ) isPoS = 1; } if ( slowflag != 0 && isPoS != 0 ) @@ -2503,7 +2520,6 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt komodo_segids(hashbuf,nHeight-101,100); if ( *blocktimep < tipindex->nTime+60) *blocktimep = tipindex->nTime+60; -//fprintf(stderr,"Start scan of utxo for staking %u ht.%d\n",(uint32_t)time(NULL),nHeight); bool resetstaker = false; if ( array != 0 ) @@ -2588,9 +2604,8 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt } } lasttime = (uint32_t)time(NULL); -//fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp); + //fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp); } -//fprintf(stderr,"numkp.%d blocktime.%u\n",numkp,*blocktimep); block_from_future_rejecttime = (uint32_t)GetAdjustedTime() + 57; for (i=winners=0; itxid,kp->vout,0,(uint32_t)tipindex->nTime+27,kp->address,PoSperc); - //fprintf(stderr,"i.%d %u vs %u\n",i,eligible2,eligible); if ( eligible > 0 ) { - besttime = m = 0; + besttime = 0; if ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address,PoSperc) ) { - while ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address,PoSperc) ) + // have elegible utxo to stake with. + if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || kp->nValue < *utxovaluep)) ) { - besttime = eligible; - eligible--; - if ( eligible < block_from_future_rejecttime ) // nothing gained by going earlier - break; - m++; -//fprintf(stderr,"m.%d ht.%d validated winning blocktime %u -> %.8f eligible.%u test prior\n",m,nHeight,*blocktimep,(double)kp->nValue/COIN,eligible); + // is better than the previous best, so use it instead. + earliest = eligible; + best_scriptPubKey = kp->scriptPubKey; + *utxovaluep = (uint64_t)kp->nValue; + decode_hex((uint8_t *)utxotxidp,32,(char *)kp->txid.GetHex().c_str()); + *utxovoutp = kp->vout; + *txtimep = kp->txtime; } - } - else - { - //fprintf(stderr,"ht.%d error validating winning blocktime %u -> %.8f eligible.%u test prior\n",nHeight,*blocktimep,(double)kp->nValue/COIN,eligible); - continue; - } - eligible = besttime; - winners++; -//fprintf(stderr,"ht.%d validated winning [%d] -> %.8f eligible.%u test prior\n",nHeight,(int32_t)(eligible - tipindex->nTime),(double)kp->nValue/COIN,eligible); - if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || kp->nValue < *utxovaluep)) ) - { - earliest = eligible; - best_scriptPubKey = kp->scriptPubKey; //out.tx->vout[out.i].scriptPubKey; - *utxovaluep = (uint64_t)kp->nValue; - //decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); - decode_hex((uint8_t *)utxotxidp,32,(char *)kp->txid.GetHex().c_str()); - *utxovoutp = kp->vout; - *txtimep = kp->txtime;//(uint32_t)out.tx->nLockTime; - //fprintf(stderr,"ht.%d earliest.%u [%d].%d (%s) nValue %.8f locktime.%u counter.%d winners.%d\n",nHeight,earliest,(int32_t)(earliest - tipindex->nTime),m,kp->address,(double)kp->nValue/COIN,*txtimep,counter,winners); - } - } //else fprintf(stderr,"utxo not eligible\n"); + if ( eligible < block_from_future_rejecttime ) // nothing gained by going earlier + break; + } else continue; + } } - if ( numkp < 1000 && array != 0 ) + if ( numkp < 500 && array != 0 ) { free(array); array = 0; @@ -2659,7 +2658,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i]; txNew.vin[0].prevout.hash = revtxid; txNew.vin[0].prevout.n = *utxovoutp; - txNew.vout[0].scriptPubKey = best_scriptPubKey;// CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; + txNew.vout[0].scriptPubKey = best_scriptPubKey; txNew.vout[0].nValue = *utxovaluep - txfee; txNew.nLockTime = earliest; CTransaction txNewConst(txNew); @@ -2670,7 +2669,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt ptr = (uint8_t *)&sigdata.scriptSig[0]; siglen = sigdata.scriptSig.size(); for (i=0; i estimated height 1444000 +// 3: 3rd season ending isnt known, so use very far times in future. + // 1751328000 = dummy timestamp, 1 July 2025! + // 7113400 = 5x current KMD blockheight. +// to add 4th season, change NUM_KMD_SEASONS to 4, and add timestamp and height of activation to these arrays. +#define NUM_KMD_SEASONS 3 +#define NUM_KMD_NOTARIES 64 +static const uint32_t KMD_SEASON_TIMESTAMPS[NUM_KMD_SEASONS] = {1525132800, 1563148800, 1751328000}; +static const int32_t KMD_SEASON_HEIGHTS[NUM_KMD_SEASONS] = {814000, 1444000, 7113400}; + +// Era array of pubkeys. Add extra seasons to bottom as requried, after adding appropriate info above. +static const char *notaries_elected[NUM_KMD_SEASONS][NUM_KMD_NOTARIES][2] = +{ + { + { "0_jl777_testA", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, + { "0_jl777_testB", "02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344" }, + { "0_kolo_testA", "0287aa4b73988ba26cf6565d815786caf0d2c4af704d7883d163ee89cd9977edec" }, + { "artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, + { "artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, + { "artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, + { "artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, + { "badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, + { "badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, + { "badass_SH", "026b49dd3923b78a592c1b475f208e23698d3f085c4c3b4906a59faf659fd9530b" }, + { "crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, // 10 + { "crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, + { "crackers_SH", "02be28310e6312d1dd44651fd96f6a44ccc269a321f907502aae81d246fabdb03e" }, + { "durerus_EU", "02bcbd287670bdca2c31e5d50130adb5dea1b53198f18abeec7211825f47485d57" }, + { "etszombi_AR", "031c79168d15edabf17d9ec99531ea9baa20039d0cdc14d9525863b83341b210e9" }, + { "etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, // 15 + { "etszombi_SH", "025d7a193c0757f7437fad3431f027e7b5ed6c925b77daba52a8755d24bf682dde" }, + { "farl4web_EU", "0300ecf9121cccf14cf9423e2adb5d98ce0c4e251721fa345dec2e03abeffbab3f" }, + { "farl4web_SH", "0396bb5ed3c57aa1221d7775ae0ff751e4c7dc9be220d0917fa8bbdf670586c030" }, + { "fullmoon_AR", "0254b1d64840ce9ff6bec9dd10e33beb92af5f7cee628f999cb6bc0fea833347cc" }, + { "fullmoon_NA", "031fb362323b06e165231c887836a8faadb96eda88a79ca434e28b3520b47d235b" }, // 20 + { "fullmoon_SH", "030e12b42ec33a80e12e570b6c8274ce664565b5c3da106859e96a7208b93afd0d" }, + { "grewal_NA", "03adc0834c203d172bce814df7c7a5e13dc603105e6b0adabc942d0421aefd2132" }, + { "grewal_SH", "03212a73f5d38a675ee3cdc6e82542a96c38c3d1c79d25a1ed2e42fcf6a8be4e68" }, + { "indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, + { "indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, + { "indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, + { "indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, + { "jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, + { "jsgalt_NA", "027b3fb6fede798cd17c30dbfb7baf9332b3f8b1c7c513f443070874c410232446" }, + { "karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, // 30 + { "kashifali_EU", "033777c52a0190f261c6f66bd0e2bb299d30f012dcb8bfff384103211edb8bb207" }, + { "kolo_AR", "03016d19344c45341e023b72f9fb6e6152fdcfe105f3b4f50b82a4790ff54e9dc6" }, + { "kolo_SH", "02aa24064500756d9b0959b44d5325f2391d8e95c6127e109184937152c384e185" }, + { "metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, + { "movecrypto_AR", "022783d94518e4dc77cbdf1a97915b29f427d7bc15ea867900a76665d3112be6f3" }, + { "movecrypto_EU", "021ab53bc6cf2c46b8a5456759f9d608966eff87384c2b52c0ac4cc8dd51e9cc42" }, + { "movecrypto_NA", "02efb12f4d78f44b0542d1c60146738e4d5506d27ec98a469142c5c84b29de0a80" }, + { "movecrypto_SH", "031f9739a3ebd6037a967ce1582cde66e79ea9a0551c54731c59c6b80f635bc859" }, + { "muros_AR", "022d77402fd7179335da39479c829be73428b0ef33fb360a4de6890f37c2aa005e" }, + { "noashh_AR", "029d93ef78197dc93892d2a30e5a54865f41e0ca3ab7eb8e3dcbc59c8756b6e355" }, // 40 + { "noashh_EU", "02061c6278b91fd4ac5cab4401100ffa3b2d5a277e8f71db23401cc071b3665546" }, + { "noashh_NA", "033c073366152b6b01535e15dd966a3a8039169584d06e27d92a69889b720d44e1" }, + { "nxtswe_EU", "032fb104e5eaa704a38a52c126af8f67e870d70f82977e5b2f093d5c1c21ae5899" }, + { "polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, + { "pondsea_AR", "032e1c213787312099158f2d74a89e8240a991d162d4ce8017d8504d1d7004f735" }, + { "pondsea_EU", "0225aa6f6f19e543180b31153d9e6d55d41bc7ec2ba191fd29f19a2f973544e29d" }, + { "pondsea_NA", "031bcfdbb62268e2ff8dfffeb9ddff7fe95fca46778c77eebff9c3829dfa1bb411" }, + { "pondsea_SH", "02209073bc0943451498de57f802650311b1f12aa6deffcd893da198a544c04f36" }, + { "popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, + { "popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, // 50 + { "ptytrader_NA", "0328c61467148b207400b23875234f8a825cce65b9c4c9b664f47410b8b8e3c222" }, + { "ptytrader_SH", "0250c93c492d8d5a6b565b90c22bee07c2d8701d6118c6267e99a4efd3c7748fa4" }, + { "rnr_AR", "029bdb08f931c0e98c2c4ba4ef45c8e33a34168cb2e6bf953cef335c359d77bfcd" }, + { "rnr_EU", "03f5c08dadffa0ffcafb8dd7ffc38c22887bd02702a6c9ac3440deddcf2837692b" }, + { "rnr_NA", "02e17c5f8c3c80f584ed343b8dcfa6d710dfef0889ec1e7728ce45ce559347c58c" }, + { "rnr_SH", "037536fb9bdfed10251f71543fb42679e7c52308bcd12146b2568b9a818d8b8377" }, + { "titomane_AR", "03cda6ca5c2d02db201488a54a548dbfc10533bdc275d5ea11928e8d6ab33c2185" }, + { "titomane_EU", "02e41feded94f0cc59f55f82f3c2c005d41da024e9a805b41105207ef89aa4bfbd" }, + { "titomane_SH", "035f49d7a308dd9a209e894321f010d21b7793461b0c89d6d9231a3fe5f68d9960" }, + { "vanbreuk_EU", "024f3cad7601d2399c131fd070e797d9cd8533868685ddbe515daa53c2e26004c3" }, // 60 + { "xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, + { "xxspot1_XX", "02ef445a392fcaf3ad4176a5da7f43580e8056594e003eba6559a713711a27f955" }, + { "xxspot2_XX", "03d85b221ea72ebcd25373e7961f4983d12add66a92f899deaf07bab1d8b6f5573" } + }, + { + {"0dev1_jl777", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, + {"0dev2_kolo", "030f34af4b908fb8eb2099accb56b8d157d49f6cfb691baa80fdd34f385efed961" }, + {"0dev3_kolo", "025af9d2b2a05338478159e9ac84543968fd18c45fd9307866b56f33898653b014" }, + {"0dev4_decker", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, + {"a-team_SH", "03b59ad322b17cb94080dc8e6dc10a0a865de6d47c16fb5b1a0b5f77f9507f3cce" }, + {"artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, + {"artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, + {"artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, + {"artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, + {"badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, + {"badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, // 10 + {"batman_AR", "033ecb640ec5852f42be24c3bf33ca123fb32ced134bed6aa2ba249cf31b0f2563" }, + {"batman_SH", "02ca5898931181d0b8aafc75ef56fce9c43656c0b6c9f64306e7c8542f6207018c" }, + {"ca333_EU", "03fc87b8c804f12a6bd18efd43b0ba2828e4e38834f6b44c0bfee19f966a12ba99" }, + {"chainmakers_EU", "02f3b08938a7f8d2609d567aebc4989eeded6e2e880c058fdf092c5da82c3bc5ee" }, + {"chainmakers_NA", "0276c6d1c65abc64c8559710b8aff4b9e33787072d3dda4ec9a47b30da0725f57a" }, + {"chainstrike_SH", "0370bcf10575d8fb0291afad7bf3a76929734f888228bc49e35c5c49b336002153" }, + {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, + {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, + {"crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, + {"crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, // 20 + {"dwy_EU", "0259c646288580221fdf0e92dbeecaee214504fdc8bbdf4a3019d6ec18b7540424" }, + {"emmanux_SH", "033f316114d950497fc1d9348f03770cd420f14f662ab2db6172df44c389a2667a" }, + {"etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, + {"fullmoon_AR", "03380314c4f42fa854df8c471618751879f9e8f0ff5dbabda2bd77d0f96cb35676" }, + {"fullmoon_NA", "030216211d8e2a48bae9e5d7eb3a42ca2b7aae8770979a791f883869aea2fa6eef" }, + {"fullmoon_SH", "03f34282fa57ecc7aba8afaf66c30099b5601e98dcbfd0d8a58c86c20d8b692c64" }, + {"goldenman_EU", "02d6f13a8f745921cdb811e32237bb98950af1a5952be7b3d429abd9152f8e388d" }, + {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, + {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, + {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, // 30 + {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, + {"jackson_AR", "038ff7cfe34cb13b524e0941d5cf710beca2ffb7e05ddf15ced7d4f14fbb0a6f69" }, + {"jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, + {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, + {"komodoninja_EU", "038e567b99806b200b267b27bbca2abf6a3e8576406df5f872e3b38d30843cd5ba" }, + {"komodoninja_SH", "033178586896915e8456ebf407b1915351a617f46984001790f0cce3d6f3ada5c2" }, + {"komodopioneers_SH", "033ace50aedf8df70035b962a805431363a61cc4e69d99d90726a2d48fb195f68c" }, + {"libscott_SH", "03301a8248d41bc5dc926088a8cf31b65e2daf49eed7eb26af4fb03aae19682b95" }, + {"lukechilds_AR", "031aa66313ee024bbee8c17915cf7d105656d0ace5b4a43a3ab5eae1e14ec02696" }, + {"madmax_AR", "03891555b4a4393d655bf76f0ad0fb74e5159a615b6925907678edc2aac5e06a75" }, // 40 + {"meshbits_AR", "02957fd48ae6cb361b8a28cdb1b8ccf5067ff68eb1f90cba7df5f7934ed8eb4b2c" }, + {"meshbits_SH", "025c6e94877515dfd7b05682b9cc2fe4a49e076efe291e54fcec3add78183c1edb" }, + {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, + {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, + {"patchkez_SH", "0296270f394140640f8fa15684fc11255371abb6b9f253416ea2734e34607799c4" }, + {"pbca26_NA", "0276aca53a058556c485bbb60bdc54b600efe402a8b97f0341a7c04803ce204cb5" }, + {"peer2cloud_AR", "034e5563cb885999ae1530bd66fab728e580016629e8377579493b386bf6cebb15" }, + {"peer2cloud_SH", "03396ac453b3f23e20f30d4793c5b8ab6ded6993242df4f09fd91eb9a4f8aede84" }, + {"polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, + {"hyper_AR", "020f2f984d522051bd5247b61b080b4374a7ab389d959408313e8062acad3266b4" }, // 50 + {"hyper_EU", "03d00cf9ceace209c59fb013e112a786ad583d7de5ca45b1e0df3b4023bb14bf51" }, + {"hyper_SH", "0383d0b37f59f4ee5e3e98a47e461c861d49d0d90c80e9e16f7e63686a2dc071f3" }, + {"hyper_NA", "03d91c43230336c0d4b769c9c940145a8c53168bf62e34d1bccd7f6cfc7e5592de" }, + {"popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, + {"popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, + {"alien_AR", "0348d9b1fc6acf81290405580f525ee49b4749ed4637b51a28b18caa26543b20f0" }, + {"alien_EU", "020aab8308d4df375a846a9e3b1c7e99597b90497efa021d50bcf1bbba23246527" }, + {"thegaltmines_NA", "031bea28bec98b6380958a493a703ddc3353d7b05eb452109a773eefd15a32e421" }, + {"titomane_AR", "029d19215440d8cb9cc6c6b7a4744ae7fb9fb18d986e371b06aeb34b64845f9325" }, + {"titomane_EU", "0360b4805d885ff596f94312eed3e4e17cb56aa8077c6dd78d905f8de89da9499f" }, // 60 + {"titomane_SH", "03573713c5b20c1e682a2e8c0f8437625b3530f278e705af9b6614de29277a435b" }, + {"webworker01_NA", "03bb7d005e052779b1586f071834c5facbb83470094cff5112f0072b64989f97d7" }, + {"xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, + }, + { + {"madmax_NA", "0237e0d3268cebfa235958808db1efc20cc43b31100813b1f3e15cc5aa647ad2c3" }, // 0 + {"alright_AR", "020566fe2fb3874258b2d3cf1809a5d650e0edc7ba746fa5eec72750c5188c9cc9" }, + {"strob_NA", "0206f7a2e972d9dfef1c424c731503a0a27de1ba7a15a91a362dc7ec0d0fb47685" }, + {"dwy_EU", "021c7cf1f10c4dc39d13451123707ab780a741feedab6ac449766affe37515a29e" }, + {"phm87_SH", "021773a38db1bc3ede7f28142f901a161c7b7737875edbb40082a201c55dcf0add" }, + {"chainmakers_NA", "02285d813c30c0bf7eefdab1ff0a8ad08a07a0d26d8b95b3943ce814ac8e24d885" }, + {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, + {"blackjok3r_SH", "021eac26dbad256cbb6f74d41b10763183ee07fb609dbd03480dd50634170547cc" }, + {"chainmakers_EU", "03fdf5a3fce8db7dee89724e706059c32e5aa3f233a6b6cc256fea337f05e3dbf7" }, + {"titomane_AR", "023e3aa9834c46971ff3e7cb86a200ec9c8074a9566a3ea85d400d5739662ee989" }, + {"fullmoon_SH", "023b7252968ea8a955cd63b9e57dee45a74f2d7ba23b4e0595572138ad1fb42d21" }, // 10 + {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, + {"chmex_EU", "0281304ebbcc39e4f09fda85f4232dd8dacd668e20e5fc11fba6b985186c90086e" }, + {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, + {"ca333_DEV", "02856843af2d9457b5b1c907068bef6077ea0904cc8bd4df1ced013f64bf267958" }, + {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, + {"pungocloud_SH", "024dfc76fa1f19b892be9d06e985d0c411e60dbbeb36bd100af9892a39555018f6" }, + {"voskcoin_EU", "034190b1c062a04124ad15b0fa56dfdf34aa06c164c7163b6aec0d654e5f118afb" }, + {"decker_DEV", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, + {"cryptoeconomy_EU", "0290ab4937e85246e048552df3e9a66cba2c1602db76e03763e16c671e750145d1" }, + {"etszombi_EU", "0293ea48d8841af7a419a24d9da11c34b39127ef041f847651bae6ab14dcd1f6b4" }, // 20 + {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, + {"pirate_AR", "03e29c90354815a750db8ea9cb3c1b9550911bb205f83d0355a061ac47c4cf2fde" }, + {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, + {"zatjum_SH", "02d6b0c89cacd58a0af038139a9a90c9e02cd1e33803a1f15fceabea1f7e9c263a" }, + {"madmax_AR", "03c5941fe49d673c094bc8e9bb1a95766b4670c88be76d576e915daf2c30a454d3" }, + {"lukechilds_NA", "03f1051e62c2d280212481c62fe52aab0a5b23c95de5b8e9ad5f80d8af4277a64b" }, + {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, + {"tonyl_AR", "02cc8bc862f2b65ad4f99d5f68d3011c138bf517acdc8d4261166b0be8f64189e1" }, + {"infotech_DEV", "0345ad4ab5254782479f6322c369cec77a7535d2f2162d103d666917d5e4f30c4c" }, + {"fullmoon_NA", "032c716701fe3a6a3f90a97b9d874a9d6eedb066419209eed7060b0cc6b710c60b" }, // 30 + {"etszombi_AR", "02e55e104aa94f70cde68165d7df3e162d4410c76afd4643b161dea044aa6d06ce" }, + {"node-9_EU", "0372e5b51e86e2392bb15039bac0c8f975b852b45028a5e43b324c294e9f12e411" }, + {"phba2061_EU", "03f6bd15dba7e986f0c976ea19d8a9093cb7c989d499f1708a0386c5c5659e6c4e" }, + {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, + {"and1-89_EU", "02736cbf8d7b50835afd50a319f162dd4beffe65f2b1dc6b90e64b32c8e7849ddd" }, + {"komodopioneers_SH", "032a238a5747777da7e819cfa3c859f3677a2daf14e4dce50916fc65d00ad9c52a" }, + {"komodopioneers_EU", "036d02425916444fff8cc7203fcbfc155c956dda5ceb647505836bef59885b6866" }, + {"d0ct0r_NA", "0303725d8525b6f969122faf04152653eb4bf34e10de92182263321769c334bf58" }, + {"kolo_DEV", "02849e12199dcc27ba09c3902686d2ad0adcbfcee9d67520e9abbdda045ba83227" }, + {"peer2cloud_AR", "02acc001fe1fe8fd68685ba26c0bc245924cb592e10cec71e9917df98b0e9d7c37" }, // 40 + {"webworker01_SH", "031e50ba6de3c16f99d414bb89866e578d963a54bde7916c810608966fb5700776" }, + {"webworker01_NA", "032735e9cad1bb00eaababfa6d27864fa4c1db0300c85e01e52176be2ca6a243ce" }, + {"pbca26_NA", "03a97606153d52338bcffd1bf19bb69ef8ce5a7cbdc2dbc3ff4f89d91ea6bbb4dc" }, + {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, + {"pirate_NA", "0255e32d8a56671dee8aa7f717debb00efa7f0086ee802de0692f2d67ee3ee06ee" }, + {"lukechilds_AR", "025c6a73ff6d750b9ddf6755b390948cffdd00f344a639472d398dd5c6b4735d23" }, + {"dragonhound_NA", "0224a9d951d3a06d8e941cc7362b788bb1237bb0d56cc313e797eb027f37c2d375" }, + {"fullmoon_AR", "03da64dd7cd0db4c123c2f79d548a96095a5a103e5b9d956e9832865818ffa7872" }, + {"chainzilla_SH", "0360804b8817fd25ded6e9c0b50e3b0782ac666545b5416644198e18bc3903d9f9" }, + {"titomane_EU", "03772ac0aad6b0e9feec5e591bff5de6775d6132e888633e73d3ba896bdd8e0afb" }, // 50 + {"jeezy_EU", "037f182facbad35684a6e960699f5da4ba89e99f0d0d62a87e8400dd086c8e5dd7" }, + {"titomane_SH", "03850fdddf2413b51790daf51dd30823addb37313c8854b508ea6228205047ef9b" }, + {"alien_AR", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f" }, + {"pirate_EU", "03fff24efd5648870a23badf46e26510e96d9e79ce281b27cfe963993039dd1351" }, + {"thegaltmines_NA", "02db1a16c7043f45d6033ccfbd0a51c2d789b32db428902f98b9e155cf0d7910ed" }, + {"computergenie_NA", "03a78ae070a5e9e935112cf7ea8293f18950f1011694ea0260799e8762c8a6f0a4" }, + {"nutellalicka_SH", "02f7d90d0510c598ce45915e6372a9cd0ba72664cb65ce231f25d526fc3c5479fc" }, + {"chainstrike_SH", "03b806be3bf7a1f2f6290ec5c1ea7d3ea57774dcfcf2129a82b2569e585100e1cb" }, + {"dwy_SH", "036536d2d52d85f630b68b050f29ea1d7f90f3b42c10f8c5cdf3dbe1359af80aff" }, + {"alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd" }, // 60 + {"gt_AR", "0348430538a4944d3162bb4749d8c5ed51299c2434f3ee69c11a1f7815b3f46135" }, + {"patchkez_SH", "03f45e9beb5c4cd46525db8195eb05c1db84ae7ef3603566b3d775770eba3b96ee" }, + {"decker_AR", "03ffdf1a116300a78729608d9930742cd349f11a9d64fcc336b8f18592dd9c91bc" }, // 63 + } +}; + #define SETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] |= (1 << ((bitoffset) & 7))) #define GETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] & (1 << ((bitoffset) & 7))) #define CLEARBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] &= ~(1 << ((bitoffset) & 7))) @@ -82,12 +297,15 @@ extern int32_t VERUS_MIN_STAKEAGE; extern std::string DONATION_PUBKEY; extern uint8_t ASSETCHAINS_PRIVATE; extern int32_t USE_EXTERNAL_PUBKEY; -extern char NOTARYADDRS[64][64]; +extern char NOTARYADDRS[64][64]; // should be depreciated later. Only affects labs. +extern char NOTARY_ADDRESSES[NUM_KMD_SEASONS][64][64]; extern int32_t KOMODO_TESTNODE, KOMODO_SNAPSHOT_INTERVAL; extern int32_t ASSETCHAINS_EARLYTXIDCONTRACT; int tx_height( const uint256 &hash ); extern std::vector vWhiteListAddress; +extern std::map mapHeightEvalActivate; void komodo_netevent(std::vector payload); +int32_t getacseason(uint32_t timestamp); #define IGUANA_MAXSCRIPTSIZE 10001 #define KOMODO_KVDURATION 1440 @@ -116,6 +334,7 @@ uint32_t komodo_heightstamp(int32_t height); int64_t komodo_pricemult(int32_t ind); int32_t komodo_priceget(int64_t *buf64,int32_t ind,int32_t height,int32_t numblocks); uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight); +int32_t komodo_currentheight(); #endif diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 1fafcc856..9a80e5e24 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -627,7 +627,7 @@ int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *base,int32_t to const char *banned_txids[] = { - "78cb4e21245c26b015b888b14c4f5096e18137d2741a6de9734d62b07014dfca", //233559 + "78cb4e21245c26b015b888b14c4f5096e18137d2741a6de9734d62b07014dfca", // vout1 only 233559 "00697be658e05561febdee1aafe368b821ca33fbb89b7027365e3d77b5dfede5", //234172 "e909465788b32047c472d73e882d79a92b0d550f90be008f76e1edaee6d742ea", //234187 "f56c6873748a327d0b92b8108f8ec8505a2843a541b1926022883678fb24f9dc", //234188 @@ -645,8 +645,24 @@ const char *banned_txids[] = // all vouts banned "c4ea1462c207547cd6fb6a4155ca6d042b22170d29801a465db5c09fec55b19d", //246748 "305dc96d8bc23a69d3db955e03a6a87c1832673470c32fe25473a46cc473c7d1", //247204 + //"43416a0c4da6b1a5c1d375bdbe8f7dc8d44d8f60df593d3376aa8221ec66357e", // vout0 only + //"1eb295ed54c47f35cbccd7e7e40d03041f1853581da6d41102a9d8813782b6cb", + //"db121e4012222adfc841824984a2a90b7e5b018dd71307822537d58160195e43", + //"28f95b8148ac4ae6e09c7380e34422fab41d568a411e53dc94823e36a3d6f386", + //"01d8c839463bda2f2f6400ede4611357913684927a767422a8560ead1b22557c", + //"6e4980a9e1bd669f4df04732dc6f11b7773b6de88d1abcf89a6b9007d72ef9ac", + //"6cc1d0495170bc0e11fd3925297623562e529ea1336b66ea61f8a1159041aed2", }; +int32_t komodo_checkvout(int32_t vout,int32_t k,int32_t indallvouts) +{ + if ( k < indallvouts ) + return(vout == 1); + else if ( k == indallvouts || k == indallvouts+1 ) + return(1); + else return(vout == 0); +} + int32_t komodo_bannedset(int32_t *indallvoutsp,uint256 *array,int32_t max) { int32_t i; @@ -691,7 +707,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim { for (k=0; k= indallvouts) ) + if ( block.vtx[i].vin[j].prevout.hash == array[k] && komodo_checkvout(block.vtx[i].vin[j].prevout.n,k,indallvouts) != 0 ) //(block.vtx[i].vin[j].prevout.n == 1 || k >= indallvouts) ) { printf("banned tx.%d being used at ht.%d txi.%d vini.%d\n",k,height,i,j); return(-1); @@ -2017,8 +2033,10 @@ int32_t get_stockprices(uint32_t now,uint32_t *prices,std::vector s { char url[32768],*symbol,*timestr; cJSON *json,*obj; int32_t i,n=0,retval=-1; uint32_t uprice,timestamp; sprintf(url,"https://api.iextrading.com/1.0/tops/last?symbols=%s",GetArg("-ac_stocks","").c_str()); + fprintf(stderr,"url.(%s)\n",url); if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"iex")) != 0 ) // { + fprintf(stderr,"stocks.(%s)\n",jprint(json,0)); if ( (n= cJSON_GetArraySize(json)) > 0 ) { retval = n; @@ -2595,7 +2613,7 @@ static int cmp_llu(const void *a, const void*b) else return(1); } -static int64_t sort64(int64_t *l, int32_t llen) +static void sort64(int64_t *l, int32_t llen) { qsort(l,llen,sizeof(uint64_t),cmp_llu); } @@ -2609,7 +2627,7 @@ static int revcmp_llu(const void *a, const void*b) else return(1); } -static int64_t revsort64(int64_t *l, int32_t llen) +static void revsort64(int64_t *l, int32_t llen) { qsort(l,llen,sizeof(uint64_t),revcmp_llu); } diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 08c633ee7..d8e292431 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -29,6 +29,7 @@ uint64_t komodo_paxtotal(); int32_t komodo_longestchain(); uint64_t komodo_maxallowed(int32_t baseid); int32_t komodo_bannedset(int32_t *indallvoutsp,uint256 *array,int32_t max); +int32_t komodo_checkvout(int32_t vout,int32_t k,int32_t indallvouts); pthread_mutex_t komodo_mutex,staked_mutex; @@ -53,6 +54,7 @@ bool VERUS_MINTBLOCKS; std::vector Mineropret; std::vector vWhiteListAddress; char NOTARYADDRS[64][64]; +char NOTARY_ADDRESSES[NUM_KMD_SEASONS][64][64]; char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096]; uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_BEAMPORT,ASSETCHAINS_CODAPORT; @@ -113,6 +115,8 @@ int32_t KOMODO_TESTNODE, KOMODO_SNAPSHOT_INTERVAL; CScript KOMODO_EARLYTXID_SCRIPTPUB; int32_t ASSETCHAINS_EARLYTXIDCONTRACT; +std::map mapHeightEvalActivate; + struct komodo_kv *KOMODO_KV; pthread_mutex_t KOMODO_KV_mutex,KOMODO_CC_mutex; diff --git a/src/komodo_nk.h b/src/komodo_nk.h index 3c9034dde..68512dfd7 100644 --- a/src/komodo_nk.h +++ b/src/komodo_nk.h @@ -1,6 +1,9 @@ #ifndef KOMODO_NK_H #define KOMODO_NK_H +//#define ASSETCHAINS_N 77 +//#define ASSETCHAINS_K 3 + #define ASSETCHAINS_N 96 #define ASSETCHAINS_K 5 diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 5cdbf237d..028bc4dc2 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -20,6 +20,7 @@ #include "notaries_staked.h" #define KOMODO_MAINNET_START 178999 +#define KOMODO_NOTARIES_HEIGHT1 814000 const char *Notaries_genesis[][2] = { @@ -60,194 +61,78 @@ const char *Notaries_genesis[][2] = { "titomane_SH", "035f49d7a308dd9a209e894321f010d21b7793461b0c89d6d9231a3fe5f68d9960" }, }; -const char *Notaries_elected0[][2] = -{ - { "0_jl777_testA", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, - { "0_jl777_testB", "02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344" }, - { "0_kolo_testA", "0287aa4b73988ba26cf6565d815786caf0d2c4af704d7883d163ee89cd9977edec" }, - { "artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, - { "artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, - { "artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, - { "artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, - { "badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, - { "badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, - { "badass_SH", "026b49dd3923b78a592c1b475f208e23698d3f085c4c3b4906a59faf659fd9530b" }, - { "crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, // 10 - { "crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, - { "crackers_SH", "02be28310e6312d1dd44651fd96f6a44ccc269a321f907502aae81d246fabdb03e" }, - { "durerus_EU", "02bcbd287670bdca2c31e5d50130adb5dea1b53198f18abeec7211825f47485d57" }, - { "etszombi_AR", "031c79168d15edabf17d9ec99531ea9baa20039d0cdc14d9525863b83341b210e9" }, - { "etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, // 15 - { "etszombi_SH", "025d7a193c0757f7437fad3431f027e7b5ed6c925b77daba52a8755d24bf682dde" }, - { "farl4web_EU", "0300ecf9121cccf14cf9423e2adb5d98ce0c4e251721fa345dec2e03abeffbab3f" }, - { "farl4web_SH", "0396bb5ed3c57aa1221d7775ae0ff751e4c7dc9be220d0917fa8bbdf670586c030" }, - { "fullmoon_AR", "0254b1d64840ce9ff6bec9dd10e33beb92af5f7cee628f999cb6bc0fea833347cc" }, - { "fullmoon_NA", "031fb362323b06e165231c887836a8faadb96eda88a79ca434e28b3520b47d235b" }, // 20 - { "fullmoon_SH", "030e12b42ec33a80e12e570b6c8274ce664565b5c3da106859e96a7208b93afd0d" }, - { "grewal_NA", "03adc0834c203d172bce814df7c7a5e13dc603105e6b0adabc942d0421aefd2132" }, - { "grewal_SH", "03212a73f5d38a675ee3cdc6e82542a96c38c3d1c79d25a1ed2e42fcf6a8be4e68" }, - { "indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, - { "indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, - { "indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, - { "indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, - { "jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, - { "jsgalt_NA", "027b3fb6fede798cd17c30dbfb7baf9332b3f8b1c7c513f443070874c410232446" }, - { "karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, // 30 - { "kashifali_EU", "033777c52a0190f261c6f66bd0e2bb299d30f012dcb8bfff384103211edb8bb207" }, - { "kolo_AR", "03016d19344c45341e023b72f9fb6e6152fdcfe105f3b4f50b82a4790ff54e9dc6" }, - { "kolo_SH", "02aa24064500756d9b0959b44d5325f2391d8e95c6127e109184937152c384e185" }, - { "metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, - { "movecrypto_AR", "022783d94518e4dc77cbdf1a97915b29f427d7bc15ea867900a76665d3112be6f3" }, - { "movecrypto_EU", "021ab53bc6cf2c46b8a5456759f9d608966eff87384c2b52c0ac4cc8dd51e9cc42" }, - { "movecrypto_NA", "02efb12f4d78f44b0542d1c60146738e4d5506d27ec98a469142c5c84b29de0a80" }, - { "movecrypto_SH", "031f9739a3ebd6037a967ce1582cde66e79ea9a0551c54731c59c6b80f635bc859" }, - { "muros_AR", "022d77402fd7179335da39479c829be73428b0ef33fb360a4de6890f37c2aa005e" }, - { "noashh_AR", "029d93ef78197dc93892d2a30e5a54865f41e0ca3ab7eb8e3dcbc59c8756b6e355" }, // 40 - { "noashh_EU", "02061c6278b91fd4ac5cab4401100ffa3b2d5a277e8f71db23401cc071b3665546" }, - { "noashh_NA", "033c073366152b6b01535e15dd966a3a8039169584d06e27d92a69889b720d44e1" }, - { "nxtswe_EU", "032fb104e5eaa704a38a52c126af8f67e870d70f82977e5b2f093d5c1c21ae5899" }, - { "polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, - { "pondsea_AR", "032e1c213787312099158f2d74a89e8240a991d162d4ce8017d8504d1d7004f735" }, - { "pondsea_EU", "0225aa6f6f19e543180b31153d9e6d55d41bc7ec2ba191fd29f19a2f973544e29d" }, - { "pondsea_NA", "031bcfdbb62268e2ff8dfffeb9ddff7fe95fca46778c77eebff9c3829dfa1bb411" }, - { "pondsea_SH", "02209073bc0943451498de57f802650311b1f12aa6deffcd893da198a544c04f36" }, - { "popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, - { "popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, // 50 - { "ptytrader_NA", "0328c61467148b207400b23875234f8a825cce65b9c4c9b664f47410b8b8e3c222" }, - { "ptytrader_SH", "0250c93c492d8d5a6b565b90c22bee07c2d8701d6118c6267e99a4efd3c7748fa4" }, - { "rnr_AR", "029bdb08f931c0e98c2c4ba4ef45c8e33a34168cb2e6bf953cef335c359d77bfcd" }, - { "rnr_EU", "03f5c08dadffa0ffcafb8dd7ffc38c22887bd02702a6c9ac3440deddcf2837692b" }, - { "rnr_NA", "02e17c5f8c3c80f584ed343b8dcfa6d710dfef0889ec1e7728ce45ce559347c58c" }, - { "rnr_SH", "037536fb9bdfed10251f71543fb42679e7c52308bcd12146b2568b9a818d8b8377" }, - { "titomane_AR", "03cda6ca5c2d02db201488a54a548dbfc10533bdc275d5ea11928e8d6ab33c2185" }, - { "titomane_EU", "02e41feded94f0cc59f55f82f3c2c005d41da024e9a805b41105207ef89aa4bfbd" }, - { "titomane_SH", "035f49d7a308dd9a209e894321f010d21b7793461b0c89d6d9231a3fe5f68d9960" }, - { "vanbreuk_EU", "024f3cad7601d2399c131fd070e797d9cd8533868685ddbe515daa53c2e26004c3" }, // 60 - { "xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, - { "xxspot1_XX", "02ef445a392fcaf3ad4176a5da7f43580e8056594e003eba6559a713711a27f955" }, - { "xxspot2_XX", "03d85b221ea72ebcd25373e7961f4983d12add66a92f899deaf07bab1d8b6f5573" } -}; - -#define KOMODO_NOTARIES_TIMESTAMP1 1525132800 // May 1st 2018 1530921600 // 7/7/2017 -#define KOMODO_NOTARIES_HEIGHT1 ((814000 / KOMODO_ELECTION_GAP) * KOMODO_ELECTION_GAP) - -const char *Notaries_elected1[][2] = -{ - {"0dev1_jl777", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, - {"0dev2_kolo", "030f34af4b908fb8eb2099accb56b8d157d49f6cfb691baa80fdd34f385efed961" }, - {"0dev3_kolo", "025af9d2b2a05338478159e9ac84543968fd18c45fd9307866b56f33898653b014" }, - {"0dev4_decker", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, - {"a-team_SH", "03b59ad322b17cb94080dc8e6dc10a0a865de6d47c16fb5b1a0b5f77f9507f3cce" }, - {"artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, - {"artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, - {"artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, - {"artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, - {"badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, - {"badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, // 10 - {"batman_AR", "033ecb640ec5852f42be24c3bf33ca123fb32ced134bed6aa2ba249cf31b0f2563" }, - {"batman_SH", "02ca5898931181d0b8aafc75ef56fce9c43656c0b6c9f64306e7c8542f6207018c" }, - {"ca333_EU", "03fc87b8c804f12a6bd18efd43b0ba2828e4e38834f6b44c0bfee19f966a12ba99" }, - {"chainmakers_EU", "02f3b08938a7f8d2609d567aebc4989eeded6e2e880c058fdf092c5da82c3bc5ee" }, - {"chainmakers_NA", "0276c6d1c65abc64c8559710b8aff4b9e33787072d3dda4ec9a47b30da0725f57a" }, - {"chainstrike_SH", "0370bcf10575d8fb0291afad7bf3a76929734f888228bc49e35c5c49b336002153" }, - {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, - {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, - {"crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, - {"crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, // 20 - {"dwy_EU", "0259c646288580221fdf0e92dbeecaee214504fdc8bbdf4a3019d6ec18b7540424" }, - {"emmanux_SH", "033f316114d950497fc1d9348f03770cd420f14f662ab2db6172df44c389a2667a" }, - {"etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, - {"fullmoon_AR", "03380314c4f42fa854df8c471618751879f9e8f0ff5dbabda2bd77d0f96cb35676" }, - {"fullmoon_NA", "030216211d8e2a48bae9e5d7eb3a42ca2b7aae8770979a791f883869aea2fa6eef" }, - {"fullmoon_SH", "03f34282fa57ecc7aba8afaf66c30099b5601e98dcbfd0d8a58c86c20d8b692c64" }, - {"goldenman_EU", "02d6f13a8f745921cdb811e32237bb98950af1a5952be7b3d429abd9152f8e388d" }, - {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, - {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, - {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, // 30 - {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, - {"jackson_AR", "038ff7cfe34cb13b524e0941d5cf710beca2ffb7e05ddf15ced7d4f14fbb0a6f69" }, - {"jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, - {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, - {"komodoninja_EU", "038e567b99806b200b267b27bbca2abf6a3e8576406df5f872e3b38d30843cd5ba" }, - {"komodoninja_SH", "033178586896915e8456ebf407b1915351a617f46984001790f0cce3d6f3ada5c2" }, - {"komodopioneers_SH", "033ace50aedf8df70035b962a805431363a61cc4e69d99d90726a2d48fb195f68c" }, - {"libscott_SH", "03301a8248d41bc5dc926088a8cf31b65e2daf49eed7eb26af4fb03aae19682b95" }, - {"lukechilds_AR", "031aa66313ee024bbee8c17915cf7d105656d0ace5b4a43a3ab5eae1e14ec02696" }, - {"madmax_AR", "03891555b4a4393d655bf76f0ad0fb74e5159a615b6925907678edc2aac5e06a75" }, // 40 - {"meshbits_AR", "02957fd48ae6cb361b8a28cdb1b8ccf5067ff68eb1f90cba7df5f7934ed8eb4b2c" }, - {"meshbits_SH", "025c6e94877515dfd7b05682b9cc2fe4a49e076efe291e54fcec3add78183c1edb" }, - {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, - {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, - {"patchkez_SH", "0296270f394140640f8fa15684fc11255371abb6b9f253416ea2734e34607799c4" }, - {"pbca26_NA", "0276aca53a058556c485bbb60bdc54b600efe402a8b97f0341a7c04803ce204cb5" }, - {"peer2cloud_AR", "034e5563cb885999ae1530bd66fab728e580016629e8377579493b386bf6cebb15" }, - {"peer2cloud_SH", "03396ac453b3f23e20f30d4793c5b8ab6ded6993242df4f09fd91eb9a4f8aede84" }, - {"polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, - {"hyper_AR", "020f2f984d522051bd5247b61b080b4374a7ab389d959408313e8062acad3266b4" }, // 50 - {"hyper_EU", "03d00cf9ceace209c59fb013e112a786ad583d7de5ca45b1e0df3b4023bb14bf51" }, - {"hyper_SH", "0383d0b37f59f4ee5e3e98a47e461c861d49d0d90c80e9e16f7e63686a2dc071f3" }, - {"hyper_NA", "03d91c43230336c0d4b769c9c940145a8c53168bf62e34d1bccd7f6cfc7e5592de" }, - {"popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, - {"popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, - {"alien_AR", "0348d9b1fc6acf81290405580f525ee49b4749ed4637b51a28b18caa26543b20f0" }, - {"alien_EU", "020aab8308d4df375a846a9e3b1c7e99597b90497efa021d50bcf1bbba23246527" }, - {"thegaltmines_NA", "031bea28bec98b6380958a493a703ddc3353d7b05eb452109a773eefd15a32e421" }, - {"titomane_AR", "029d19215440d8cb9cc6c6b7a4744ae7fb9fb18d986e371b06aeb34b64845f9325" }, - {"titomane_EU", "0360b4805d885ff596f94312eed3e4e17cb56aa8077c6dd78d905f8de89da9499f" }, // 60 - {"titomane_SH", "03573713c5b20c1e682a2e8c0f8437625b3530f278e705af9b6614de29277a435b" }, - {"webworker01_NA", "03bb7d005e052779b1586f071834c5facbb83470094cff5112f0072b64989f97d7" }, - {"xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, -}; #define CRYPTO777_PUBSECPSTR "020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9" +int32_t getkmdseason(int32_t height) +{ + if ( height <= KMD_SEASON_HEIGHTS[0] ) + return(1); + for (int32_t i = 1; i < NUM_KMD_SEASONS; i++) + { + if ( height <= KMD_SEASON_HEIGHTS[i] && height >= KMD_SEASON_HEIGHTS[i-1] ) + return(i+1); + } + return(0); +}; + +int32_t getacseason(uint32_t timestamp) +{ + if ( timestamp <= KMD_SEASON_TIMESTAMPS[0] ) + return(1); + for (int32_t i = 1; i < NUM_KMD_SEASONS; i++) + { + if ( timestamp <= KMD_SEASON_TIMESTAMPS[i] && timestamp >= KMD_SEASON_TIMESTAMPS[i-1] ) + return(i+1); + } + return(0); +}; + int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp) { - static uint8_t elected_pubkeys0[64][33],elected_pubkeys1[64][33],did0,did1; static int32_t n0,n1; int32_t i,htind,n; uint64_t mask = 0; struct knotary_entry *kp,*tmp; - + static uint8_t kmd_pubkeys[NUM_KMD_SEASONS][64][33],didinit[NUM_KMD_SEASONS]; + if ( timestamp == 0 && ASSETCHAINS_SYMBOL[0] != 0 ) timestamp = komodo_heightstamp(height); else if ( ASSETCHAINS_SYMBOL[0] == 0 ) timestamp = 0; // If this chain is not a staked chain, use the normal Komodo logic to determine notaries. This allows KMD to still sync and use its proper pubkeys for dPoW. - if (is_STAKED(ASSETCHAINS_SYMBOL) == 0) + if ( is_STAKED(ASSETCHAINS_SYMBOL) == 0 ) { - if ( height >= KOMODO_NOTARIES_HARDCODED || ASSETCHAINS_SYMBOL[0] != 0 ) - timestamp = 0; - if ( (timestamp != 0 && timestamp <= KOMODO_NOTARIES_TIMESTAMP1) || (ASSETCHAINS_SYMBOL[0] == 0 && height <= KOMODO_NOTARIES_HEIGHT1) ) + int32_t kmd_season = 0; + if ( ASSETCHAINS_SYMBOL[0] == 0 ) { - if ( did0 == 0 ) - { - n0 = (int32_t)(sizeof(Notaries_elected0)/sizeof(*Notaries_elected0)); - for (i=0; i= KOMODO_NOTARIES_HARDCODED ) + kmd_season = getkmdseason(height); } - else //if ( (timestamp != 0 && timestamp <= KOMODO_NOTARIES_TIMESTAMP2) || height <= KOMODO_NOTARIES_HEIGHT2 ) + else { - if ( did1 == 0 ) + // This is a non LABS assetchain, use timestamp to detemine notary pubkeys. + kmd_season = getacseason(timestamp); + } + if ( kmd_season != 0 ) + { + if ( didinit[kmd_season-1] == 0 ) { - n1 = (int32_t)(sizeof(Notaries_elected1)/sizeof(*Notaries_elected1)); - for (i=0; i #ifdef _WIN32 @@ -1425,7 +1426,7 @@ void komodo_configfile(char *symbol,uint16_t rpcport) #ifndef FROM_CLI if ( (fp= fopen(fname,"wb")) != 0 ) { - fprintf(fp,"rpcuser=user%u\nrpcpassword=pass%s\nrpcport=%u\nserver=1\ntxindex=1\nrpcworkqueue=256\nrpcallowip=127.0.0.1\n",crc,password,rpcport); + fprintf(fp,"rpcuser=user%u\nrpcpassword=pass%s\nrpcport=%u\nserver=1\ntxindex=1\nrpcworkqueue=256\nrpcallowip=127.0.0.1\nrpcbind=127.0.0.1\n",crc,password,rpcport); fclose(fp); printf("Created (%s)\n",fname); } else printf("Couldnt create (%s)\n",fname); @@ -1691,14 +1692,9 @@ int8_t equihash_params_possible(uint64_t n, uint64_t k) void komodo_args(char *argv0) { - extern const char *Notaries_elected1[][2]; - std::string name,addn,hexstr,symbol; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[32756],disablebits[32],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,nonz=0,baseid,len,n,extralen = 0; uint64_t ccenables[256]; + std::string name,addn,hexstr,symbol; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[32756],disablebits[32],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,nonz=0,baseid,len,n,extralen = 0; uint64_t ccenables[256], ccEnablesHeight[512] = {0}; IS_KOMODO_NOTARY = GetBoolArg("-notary", false); IS_STAKED_NOTARY = GetArg("-stakednotary", -1); - if ( IS_STAKED_NOTARY != -1 && IS_KOMODO_NOTARY == true ) { - fprintf(stderr, "Cannot be STAKED and KMD notary at the same time!\n"); - StartShutdown(); - } memset(ccenables,0,sizeof(ccenables)); memset(disablebits,0,sizeof(disablebits)); if ( GetBoolArg("-gen", false) != 0 ) @@ -1717,17 +1713,26 @@ void komodo_args(char *argv0) USE_EXTERNAL_PUBKEY = 1; if ( IS_KOMODO_NOTARY == 0 ) { + // We dont have any chain data yet, so use system clock to guess. + // I think on season change should reccomend notaries to use -notary to avoid needing this. + int32_t kmd_season = getacseason(time(NULL)); for (i=0; i<64; i++) - if ( strcmp(NOTARY_PUBKEY.c_str(),Notaries_elected1[i][1]) == 0 ) + { + if ( strcmp(NOTARY_PUBKEY.c_str(),notaries_elected[kmd_season-1][i][1]) == 0 ) { IS_KOMODO_NOTARY = 1; KOMODO_MININGTHREADS = 1; mapArgs ["-genproclimit"] = itostr(KOMODO_MININGTHREADS); IS_STAKED_NOTARY = -1; - fprintf(stderr,"running as notary.%d %s\n",i,Notaries_elected1[i][0]); + fprintf(stderr,"running as notary.%d %s\n",i,notaries_elected[kmd_season-1][i][0]); break; } + } } + } + if ( IS_STAKED_NOTARY != -1 && IS_KOMODO_NOTARY == true ) { + fprintf(stderr, "Cannot be STAKED and KMD notary at the same time!\n"); + StartShutdown(); } name = GetArg("-ac_name",""); if ( argv0 != 0 ) @@ -1754,13 +1759,33 @@ void komodo_args(char *argv0) ASSETCHAINS_PRIVATE = GetArg("-ac_private",0); KOMODO_SNAPSHOT_INTERVAL = GetArg("-ac_snapshot",0); Split(GetArg("-ac_nk",""), ASSETCHAINS_NK, 0); + + // -ac_ccactivateht=evalcode,height,evalcode,height,evalcode,height.... + Split(GetArg("-ac_ccactivateht",""), ccEnablesHeight, 0); + // fill map with all eval codes and activation height of 0. + for ( int i = 0; i < 256; i++ ) + mapHeightEvalActivate[i] = 0; + for ( int i = 0; i < 512; i++ ) + { + int32_t ecode = ccEnablesHeight[i]; + int32_t ht = ccEnablesHeight[i+1]; + if ( ecode > 255 || ecode < 0 ) + fprintf(stderr, "ac_ccactivateht: invalid evalcode.%i must be between 0 and 256.\n", ecode); + else if ( ht > 0 ) + { + // update global map. + mapHeightEvalActivate[ecode] = ht; + fprintf(stderr, "ac_ccactivateht: ecode.%i activates at height.%i\n", ecode, mapHeightEvalActivate[ecode]); + } + i++; + } + if ( (KOMODO_REWIND= GetArg("-rewind",0)) != 0 ) { printf("KOMODO_REWIND %d\n",KOMODO_REWIND); } KOMODO_EARLYTXID = Parseuint256(GetArg("-earlytxid","0").c_str()); ASSETCHAINS_EARLYTXIDCONTRACT = GetArg("-ac_earlytxidcontract",0); - fprintf(stderr, "ASSETCHAINS_EARLYTXIDCONTRACT.%i\n", ASSETCHAINS_EARLYTXIDCONTRACT); if ( name.c_str()[0] != 0 ) { std::string selectedAlgo = GetArg("-ac_algo", std::string(ASSETCHAINS_ALGORITHMS[0])); @@ -2295,6 +2320,68 @@ void komodo_args(char *argv0) fprintf(stderr,"-ac_private for a non-PIRATE chain is not supported. The only reason to have an -ac_private chain is for total privacy and that is best achieved with the largest anon set. PIRATE has that and it is recommended to just use PIRATE\n"); StartShutdown(); } + // Set cc enables for all existing ac_cc chains here. + if ( strcmp("AXO",ASSETCHAINS_SYMBOL) == 0 ) + { + // No CCs used on this chain yet. + CCDISABLEALL; + } + if ( strcmp("CCL",ASSETCHAINS_SYMBOL) == 0 ) + { + // No CCs used on this chain yet. + CCDISABLEALL; + CCENABLE(EVAL_TOKENS); + CCENABLE(EVAL_HEIR); + } + if ( strcmp("COQUI",ASSETCHAINS_SYMBOL) == 0 ) + { + CCDISABLEALL; + CCENABLE(EVAL_DICE); + CCENABLE(EVAL_CHANNELS); + CCENABLE(EVAL_ORACLES); + CCENABLE(EVAL_ASSETS); + CCENABLE(EVAL_TOKENS); + } + if ( strcmp("DION",ASSETCHAINS_SYMBOL) == 0 ) + { + // No CCs used on this chain yet. + CCDISABLEALL; + } + + if ( strcmp("EQL",ASSETCHAINS_SYMBOL) == 0 ) + { + // No CCs used on this chain yet. + CCDISABLEALL; + } + if ( strcmp("ILN",ASSETCHAINS_SYMBOL) == 0 ) + { + // No CCs used on this chain yet. + CCDISABLEALL; + } + if ( strcmp("OUR",ASSETCHAINS_SYMBOL) == 0 ) + { + // No CCs used on this chain yet. + CCDISABLEALL; + } + if ( strcmp("ZEXO",ASSETCHAINS_SYMBOL) == 0 ) + { + // No CCs used on this chain yet. + CCDISABLEALL; + } + if ( strcmp("SEC",ASSETCHAINS_SYMBOL) == 0 ) + { + CCDISABLEALL; + CCENABLE(EVAL_ASSETS); + CCENABLE(EVAL_TOKENS); + CCENABLE(EVAL_ORACLES); + } + if ( strcmp("KMDICE",ASSETCHAINS_SYMBOL) == 0 ) + { + CCDISABLEALL; + CCENABLE(EVAL_FAUCET); + CCENABLE(EVAL_DICE); + CCENABLE(EVAL_ORACLES); + } } else BITCOIND_RPCPORT = GetArg("-rpcport", BaseParams().RPCPort()); KOMODO_DPOWCONFS = GetArg("-dpowconfs",dpowconfs); if ( ASSETCHAINS_SYMBOL[0] == 0 || strcmp(ASSETCHAINS_SYMBOL,"SUPERNET") == 0 || strcmp(ASSETCHAINS_SYMBOL,"DEX") == 0 || strcmp(ASSETCHAINS_SYMBOL,"COQUI") == 0 || strcmp(ASSETCHAINS_SYMBOL,"PIRATE") == 0 || strcmp(ASSETCHAINS_SYMBOL,"KMDICE") == 0 ) diff --git a/src/main.cpp b/src/main.cpp index 82b95b146..e01cba61f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -147,10 +147,28 @@ namespace { struct CBlockIndexWorkComparator { - bool operator()(CBlockIndex *pa, CBlockIndex *pb) const { + bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const { // First sort by most total work, ... - if (pa->chainPower > pb->chainPower) return false; - if (pa->chainPower < pb->chainPower) return true; + + if (ASSETCHAINS_LWMAPOS) { + + /* Decker: + + seems we had CChainPower classes compare here from Verus, it's slow, bcz of hard + arith_uint256 math in bool operator<(const CChainPower &p1, const CChainPower &p2), + this slows down setBlockIndexCandidates.insert operations in LoadBlockIndexDB(), + so, for faster block index db loading we will use check from Verus only for LWMAPOS + enabled chains. + */ + + if (pa->chainPower > pb->chainPower) return false; + if (pa->chainPower < pb->chainPower) return true; + } + else + { + if (pa->chainPower.chainWork > pb->chainPower.chainWork) return false; + if (pa->chainPower.chainWork < pb->chainPower.chainWork) return true; + } // ... then by earliest time received, ... if (pa->nSequenceId < pb->nSequenceId) return false; @@ -173,8 +191,10 @@ namespace { * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be * missing the data for the block. */ + + //set> setBlockIndexCandidates; set setBlockIndexCandidates; - + /** Number of nodes with fSyncStarted. */ int nSyncStarted = 0; @@ -656,8 +676,12 @@ std::vector > vAddressSnapshot; bool komodo_dailysnapshot(int32_t height) { - int reorglimit = 10; // CHANGE BACK TO 100 AFTER TESTING! + int reorglimit = 100; uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height,undo_height,extraoffset; + // NOTE: To make this 100% safe under all sync conditions, it should be using a notarized notarization, from the DB. + // Under heavy reorg attack, its possible `komodo_notarized_height` can return a height that can't be found on chain sync. + // However, the DB can reorg the last notarization. By using 2 deep, we know 100% that the previous notarization cannot be reorged by online nodes, + // and as such will always be notarizing the same height. May need to check heights on scan back to make sure they are confirmed in correct order. if ( (extraoffset= height % KOMODO_SNAPSHOT_INTERVAL) != 0 ) { // we are on chain init, and need to scan all the way back to the correct height, other wise our node will have a diffrent snapshot to online nodes. @@ -1337,16 +1361,19 @@ bool CheckTransaction(uint32_t tiptime,const CTransaction& tx, CValidationState if ( *(int32_t *)&array[0] == 0 ) numbanned = komodo_bannedset(&indallvouts,array,(int32_t)(sizeof(array)/sizeof(*array))); n = tx.vin.size(); - for (j=0; j= indallvouts) ) + for (k=0; kGetHeight(),j); - return(false); + if ( tx.vin[j].prevout.hash == array[k] && komodo_checkvout(tx.vin[j].prevout.n,k,indallvouts) != 0 ) //(tx.vin[j].prevout.n == 1 || k >= indallvouts) ) + { + static uint32_t counter; + if ( counter++ < 100 ) + printf("MEMPOOL: banned tx.%d being used at ht.%d vout.%d\n",k,(int32_t)chainActive.Tip()->GetHeight(),j); + return(false); + } } } } @@ -1369,25 +1396,24 @@ bool CheckTransaction(uint32_t tiptime,const CTransaction& tx, CValidationState } } -int32_t komodo_isnotaryvout(char *coinaddr) // from ac_private chains only +int32_t komodo_isnotaryvout(char *coinaddr,uint32_t tiptime) // from ac_private chains only { - static int32_t didinit; static char notaryaddrs[sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) + 1][64]; - int32_t i; - if ( didinit == 0 ) + int32_t season = getacseason(tiptime); + if ( NOTARY_ADDRESSES[season-1][0][0] == 0 ) { - uint8_t pubkey33[33]; - for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++) - { - if ( i < sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) ) - decode_hex(pubkey33,33,(char *)Notaries_elected1[i][1]); - else decode_hex(pubkey33,33,(char *)CRYPTO777_PUBSECPSTR); - pubkey2addr((char *)notaryaddrs[i],(uint8_t *)pubkey33); - } - didinit = 1; + uint8_t pubkeys[64][33]; + komodo_notaries(pubkeys,0,tiptime); } - for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++) - if ( strcmp(coinaddr,notaryaddrs[i]) == 0 ) + if ( strcmp(coinaddr,CRYPTO777_KMDADDR) == 0 ) return(1); + for (int32_t i = 0; i < NUM_KMD_NOTARIES; i++) + { + if ( strcmp(coinaddr,NOTARY_ADDRESSES[season-1][i]) == 0 ) + { + //fprintf(stderr, "coinaddr.%s notaryaddress[%i].%s\n",coinaddr,i,NOTARY_ADDRESSES[season-1][i]); + return(1); + } + } return(0); } @@ -1480,7 +1506,7 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio // char destaddr[65]; Getscriptaddress(destaddr,txout.scriptPubKey); - if ( komodo_isnotaryvout(destaddr) == 0 ) + if ( komodo_isnotaryvout(destaddr,tiptime) == 0 ) { invalid_private_taddr = 1; //return state.DoS(100, error("CheckTransaction(): this is a private chain, no public allowed"),REJECT_INVALID, "bad-txns-acprivacy-chain"); @@ -3099,7 +3125,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex *pfClean = false; bool fClean = true; - komodo_disconnect(pindex,block); + //komodo_disconnect(pindex,block); does nothing? CBlockUndo blockUndo; CDiskBlockPos pos = pindex->GetUndoPos(); if (pos.IsNull()) @@ -3387,7 +3413,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin { // do a full block scan to get notarisation position and to enforce a valid notarization is in position 1. // if notarisation in the block, must be position 1 and the coinbase must pay notaries. - int notarisationTx = komodo_connectblock(true,pindex,*(CBlock *)&block); + int32_t notarisationTx = komodo_connectblock(true,pindex,*(CBlock *)&block); // -1 means that the valid notarization isnt in position 1 or there are too many notarizations in this block. if ( notarisationTx == -1 ) return state.DoS(100, error("ConnectBlock(): Notarization is not in TX position 1 or block contains more than 1 notarization! Invalid Block!"), @@ -4045,7 +4071,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { CValidationState stateDummy; // don't keep staking or invalid transactions - if (tx.IsCoinBase() || ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED && komodo_isPoS((CBlock *)&block,pindexDelete->GetHeight()) != 0)) || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) + if (tx.IsCoinBase() || ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED && komodo_isPoS((CBlock *)&block,pindexDelete->GetHeight(),true) != 0)) || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) { mempool.remove(tx, removed, true); } @@ -4077,11 +4103,11 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { { CTransaction &tx = block.vtx[i]; //if ((i == (block.vtx.size() - 1)) && ((ASSETCHAINS_LWMAPOS && block.IsVerusPOSBlock()) || (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block) != 0)))) - if ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block,pindexDelete->GetHeight()) != 0))) + if ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block,pindexDelete->GetHeight(),true) != 0))) { #ifdef ENABLE_WALLET - LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->EraseFromWallet(tx.GetHash()); + if ( !GetBoolArg("-disablewallet", false) ) + pwalletMain->EraseFromWallet(tx.GetHash()); #endif } else @@ -4262,7 +4288,10 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * { uint64_t start = time(NULL); if ( !komodo_dailysnapshot(pindexNew->GetHeight()) ) - fprintf(stderr, "daily snapshot failed, please reindex your chain\n"); // maybe force shutdown here? + { + fprintf(stderr, "daily snapshot failed, please reindex your chain\n"); + StartShutdown(); + } fprintf(stderr, "snapshot completed in: %lu seconds\n", time(NULL)-start); } return true; @@ -5089,7 +5118,7 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C CValidationState state; CTransaction Tx; const CTransaction &tx = (CTransaction)block.vtx[i]; - if (tx.IsCoinBase() || !tx.vjoinsplit.empty() || !tx.vShieldedSpend.empty() || ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED && komodo_isPoS((CBlock *)&block,height) != 0))) + if (tx.IsCoinBase() || !tx.vjoinsplit.empty() || !tx.vShieldedSpend.empty() || ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED && komodo_isPoS((CBlock *)&block,height,true) != 0))) continue; Tx = tx; if ( myAddtomempool(Tx, &state, true) == false ) // happens with out of order tx in block on resync @@ -6469,7 +6498,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) try { // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor //CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); - CBufferedFile blkdat(fileIn, 32*MAX_BLOCK_SIZE(10000000), MAX_BLOCK_SIZE(10000000)+8, SER_DISK, CLIENT_VERSION); + CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE(10000000), MAX_BLOCK_SIZE(10000000)+8, SER_DISK, CLIENT_VERSION); uint64_t nRewind = blkdat.GetPos(); while (!blkdat.eof()) { boost::this_thread::interruption_point(); @@ -6496,15 +6525,15 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) } try { // read block + CBlock block; uint64_t nBlockPos = blkdat.GetPos(); if (dbp) dbp->nPos = nBlockPos; blkdat.SetLimit(nBlockPos + nSize); blkdat.SetPos(nBlockPos); - CBlock block; blkdat >> block; - nRewind = blkdat.GetPos(); - + + nRewind = blkdat.GetPos(); // detect out of order blocks, and store them for later uint256 hash = block.GetHash(); if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { @@ -6535,6 +6564,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) std::pair::iterator, std::multimap::iterator> range = mapBlocksUnknownParent.equal_range(head); while (range.first != range.second) { std::multimap::iterator it = range.first; + if (ReadBlockFromDisk(mapBlockIndex.count(hash)!=0?mapBlockIndex[hash]->GetHeight():0,block, it->second,1)) { LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), diff --git a/src/miner.cpp b/src/miner.cpp index 8fc658fa9..e4e907447 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -222,9 +222,13 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 boost::optional cheatSpend; uint256 cbHash; - + + boost::this_thread::interruption_point(); // exit thread before entering locks. + CBlockIndex* pindexPrev = 0; { + // this should stop create block ever exiting until it has returned something. + boost::this_thread::disable_interruption(); ENTER_CRITICAL_SECTION(cs_main); ENTER_CRITICAL_SECTION(mempool.cs); pindexPrev = chainActive.LastTip(); @@ -810,12 +814,18 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 //fprintf(stderr,"check validity\n"); if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) // invokes CC checks { - throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed"); + if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) ) + { + LEAVE_CRITICAL_SECTION(cs_main); + LEAVE_CRITICAL_SECTION(mempool.cs); + } + //throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed"); // crashes the node, moved to GetBlockTemplate and issue return. + return(0); } //fprintf(stderr,"valid\n"); } } - if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) ) + if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) ) { LEAVE_CRITICAL_SECTION(cs_main); LEAVE_CRITICAL_SECTION(mempool.cs); @@ -1051,7 +1061,7 @@ int32_t roundrobin_delay; arith_uint256 HASHTarget,HASHTarget_POW; // wait for peers to connect -int32_t waitForPeers(const CChainParams &chainparams) +void waitForPeers(const CChainParams &chainparams) { if (chainparams.MiningRequiresPeers()) { diff --git a/src/notaries_staked.cpp b/src/notaries_staked.cpp index bb1518262..d3281127e 100644 --- a/src/notaries_staked.cpp +++ b/src/notaries_staked.cpp @@ -18,7 +18,7 @@ int8_t is_STAKED(const char *chain_name) if (doneinit == 1 && ASSETCHAINS_SYMBOL[0] != 0) return(STAKED); else STAKED = 0; - if ( (strcmp(chain_name, "LABS") == 0) || (strcmp(chain_name, "LABSRCTEST") == 0) ) + if ( (strcmp(chain_name, "LABS") == 0) ) STAKED = 1; // These chains are allowed coin emissions. else if ( (strncmp(chain_name, "LABS", 4) == 0) ) STAKED = 2; // These chains have no coin emission, block subsidy is always 0, and comission is 0. Notary pay is allowed. @@ -113,7 +113,14 @@ void UpdateNotaryAddrs(uint8_t pubkeys[64][33],int8_t numNotaries) { // staked era is set. pthread_mutex_lock(&staked_mutex); for (int i = 0; iGetBlockHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain @@ -283,6 +288,9 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex) UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { UniValue result(UniValue::VOBJ); + uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height; + notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); + result.push_back(Pair("last_notarized_height", notarized_height)); result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain @@ -1453,6 +1461,23 @@ UniValue pricesgetorderbook(const UniValue& params, bool fHelp) return PricesGetOrderbook(); } +// pricesrekt rpc implementation +UniValue pricesrefillfund(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error("pricesrefillfund amount\n"); + LOCK(cs_main); + UniValue ret(UniValue::VOBJ); + + if (ASSETCHAINS_CBOPRET == 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "only -ac_cbopret chains have prices"); + + CAmount amount = atof(params[0].get_str().c_str()) * COIN; + + return PricesRefillFund(amount); +} + + UniValue gettxout(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) @@ -1689,6 +1714,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("blocks", (int)chainActive.Height())); + obj.push_back(Pair("synced", KOMODO_INSYNC!=0)); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->GetHeight() : -1)); obj.push_back(Pair("bestblockhash", chainActive.LastTip()->GetBlockHash().GetHex())); obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty())); @@ -1827,7 +1853,6 @@ UniValue getchaintips(const UniValue& params, bool fHelp) /* Construct the output array. */ UniValue res(UniValue::VARR); const CBlockIndex *forked; - BOOST_FOREACH(const CBlockIndex* block, setTips) BOOST_FOREACH(const CBlockIndex* block, setTips) { UniValue obj(UniValue::VOBJ); @@ -2082,4 +2107,4 @@ void RegisterBlockchainRPCCommands(CRPCTable &tableRPC) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); -} \ No newline at end of file +} diff --git a/src/rpc/crosschain.cpp b/src/rpc/crosschain.cpp index 35409323d..bf0dbea4c 100644 --- a/src/rpc/crosschain.cpp +++ b/src/rpc/crosschain.cpp @@ -1420,6 +1420,7 @@ UniValue getwalletburntransactions(const UniValue& params, bool fHelp) UnmarshalBurnTx(*pwtx, targetSymbol, &targetCCid, payoutsHash, rawproof)) { UniValue entry(UniValue::VOBJ); entry.push_back(Pair("txid", pwtx->GetHash().GetHex())); + if (vopret.begin()[0] == EVAL_TOKENS) { // get burned token value std::vector> oprets; @@ -1460,6 +1461,12 @@ UniValue getwalletburntransactions(const UniValue& params, bool fHelp) } else entry.push_back(Pair("burnedAmount", ValueFromAmount(pwtx->vout.back().nValue))); // coins + + // check for corrupted strings (look for non-printable chars) from some older versions + // which caused "couldn't parse reply from server" error on client: + if (std::find_if(targetSymbol.begin(), targetSymbol.end(), [](int c) {return !std::isprint(c);}) != targetSymbol.end()) + targetSymbol = ""; + entry.push_back(Pair("targetSymbol", targetSymbol)); entry.push_back(Pair("targetCCid", std::to_string(targetCCid))); if (mytxid_inmempool(pwtx->GetHash())) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 21ae07810..4814d34dd 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -60,7 +60,8 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he * or over the difficulty averaging window if 'lookup' is nonpositive. * If 'height' is nonnegative, compute the estimate at the time when a given block was found. */ -int64_t GetNetworkHashPS(int lookup, int height) { +int64_t GetNetworkHashPS(int lookup, int height) +{ CBlockIndex *pb = chainActive.LastTip(); if (height >= 0 && height < chainActive.Height()) @@ -744,7 +745,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) #endif ENTER_CRITICAL_SECTION(cs_main); if (!pblocktemplate) - throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory or no available utxo for staking"); + throw std::runtime_error("CreateNewBlock(): create block failed"); + //throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory or no available utxo for staking"); // Need to update only after we know CreateNewBlockWithKey succeeded pindexPrev = pindexPrevNew; @@ -1051,6 +1053,7 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp) return result; } + static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 4ea6e94e3..95c2cc343 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -69,7 +69,7 @@ bool komodo_txnotarizedconfirmed(uint256 txid); uint32_t komodo_chainactive_timestamp(); int32_t komodo_whoami(char *pubkeystr,int32_t height,uint32_t timestamp); extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; -extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN,IS_STAKED_NOTARY,IS_KOMODO_NOTARY,STAKED_ERA; +extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN,IS_STAKED_NOTARY,IS_KOMODO_NOTARY,STAKED_ERA,KOMODO_INSYNC; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; uint32_t komodo_segid32(char *coinaddr); int64_t komodo_coinsupply(int64_t *zfundsp,int64_t *sproutfundsp,int32_t height); @@ -78,7 +78,7 @@ int8_t StakedNotaryID(std::string ¬aryname, char *Raddress); uint64_t komodo_notarypayamount(int32_t nHeight, int64_t notarycount); int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); -#define KOMODO_VERSION "0.3.3b" +#define KOMODO_VERSION "0.4.0a" #define VERUS_VERSION "0.4.0g" extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; extern uint32_t ASSETCHAINS_CC; @@ -237,6 +237,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); obj.push_back(Pair("KMDversion", KOMODO_VERSION)); + obj.push_back(Pair("synced", KOMODO_INSYNC!=0)); //obj.push_back(Pair("VRSCversion", VERUS_VERSION)); obj.push_back(Pair("notarized", notarized_height)); obj.push_back(Pair("prevMoMheight", prevMoMheight)); @@ -1383,9 +1384,13 @@ UniValue getsnapshot(const UniValue& params, bool fHelp) if (params.size() > 0 && !params[0].isNull()) { top = atoi(params[0].get_str().c_str()); - if (top < 0) - //throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, top must be a positive integer"); - top = -1; + if ( top < 0 ) + { + if ( KOMODO_SNAPSHOT_INTERVAL == 0 ) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, top must be a positive integer"); + else + top = -1; + } } if ( fHelp || params.size() > 1) @@ -1432,7 +1437,7 @@ UniValue getsnapshot(const UniValue& params, bool fHelp) UniValue getaddresstxids(const UniValue& params, bool fHelp) { - if (fHelp || params.size() > 2) + if (fHelp || params.size() > 2 || params.size() < 1) throw runtime_error( "getaddresstxids (ccvout)\n" "\nReturns the txids for an address(es) (requires addressindex to be enabled).\n" diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index e280b1a0b..56f221a37 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -219,7 +219,6 @@ int32_t komodo_longestchain() depth--; if ( num > (n >> 1) ) { - extern char ASSETCHAINS_SYMBOL[]; if ( 0 && height != KOMODO_LONGESTCHAIN ) fprintf(stderr,"set %s KOMODO_LONGESTCHAIN <- %d\n",ASSETCHAINS_SYMBOL,height); KOMODO_LONGESTCHAIN = height; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 1c3cb96f2..578c2f9ad 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -48,6 +48,8 @@ #include +int32_t komodo_notarized_height(int32_t *prevMoMheightp,uint256 *hashp,uint256 *txidp); + using namespace std; extern char ASSETCHAINS_SYMBOL[]; @@ -185,10 +187,13 @@ int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout) void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, int nHeight = 0, int nConfirmations = 0, int nBlockTime = 0) { + uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height; + notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); uint256 txid = tx.GetHash(); entry.push_back(Pair("txid", txid.GetHex())); entry.push_back(Pair("overwintered", tx.fOverwintered)); entry.push_back(Pair("version", tx.nVersion)); + entry.push_back(Pair("last_notarized_height", notarized_height)); if (tx.fOverwintered) { entry.push_back(Pair("versiongroupid", HexInt(tx.nVersionGroupId))); } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index c35647f8c..75360fd35 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2019 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -45,6 +46,7 @@ using namespace RPCServer; using namespace std; +extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; static bool fRPCRunning = false; static bool fRPCInWarmup = true; @@ -454,9 +456,11 @@ static const CRPCCommand vRPCCommands[] = { "oracles", "oracleslist", &oracleslist, true }, { "oracles", "oraclesinfo", &oraclesinfo, true }, { "oracles", "oraclescreate", &oraclescreate, true }, + { "oracles", "oraclesfund", &oraclesfund, true }, { "oracles", "oraclesregister", &oraclesregister, true }, { "oracles", "oraclessubscribe", &oraclessubscribe, true }, { "oracles", "oraclesdata", &oraclesdata, true }, + { "oracles", "oraclessample", &oraclessample, true }, { "oracles", "oraclessamples", &oraclessamples, true }, // Prices @@ -471,7 +475,7 @@ static const CRPCCommand vRPCCommands[] = { "prices", "pricesrekt", &pricesrekt, true }, { "prices", "pricesaddfunding", &pricesaddfunding, true }, { "prices", "pricesgetorderbook", &pricesgetorderbook, true }, - + { "prices", "pricesrefillfund", &pricesrefillfund, true }, // Pegs { "pegs", "pegsaddress", &pegsaddress, true }, @@ -853,21 +857,30 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms std::string HelpExampleCli(const std::string& methodname, const std::string& args) { - return "> komodo-cli " + methodname + " " + args + "\n"; + if ( ASSETCHAINS_SYMBOL[0] == 0 ) { + return "> komodo-cli " + methodname + " " + args + "\n"; + } else if ((strncmp(ASSETCHAINS_SYMBOL, "HUSH3", 5) == 0) ) { + return "> hush-cli " + methodname + " " + args + "\n"; + } else { + return "> komodo-cli -ac_name=" + strprintf("%s", ASSETCHAINS_SYMBOL) + " " + methodname + " " + args + "\n"; + } } std::string HelpExampleRpc(const std::string& methodname, const std::string& args) { - return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", " - "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:7771/\n"; + return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", " + "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:" + to_string(ASSETCHAINS_RPCPORT) + "/\n"; } string experimentalDisabledHelpMsg(const string& rpc, const string& enableArg) { + string daemon = ASSETCHAINS_SYMBOL[0] == 0 ? "komodod" : "hushd"; + string ticker = ASSETCHAINS_SYMBOL[0] == 0 ? "komodo" : ASSETCHAINS_SYMBOL; + return "\nWARNING: " + rpc + " is disabled.\n" - "To enable it, restart zcashd with the -experimentalfeatures and\n" + "To enable it, restart " + daemon + " with the -experimentalfeatures and\n" "-" + enableArg + " commandline options, or add these two lines\n" - "to the zcash.conf file:\n\n" + "to the " + ticker + ".conf file:\n\n" "experimentalfeatures=1\n" + enableArg + "=1\n"; } diff --git a/src/rpc/server.h b/src/rpc/server.h index c61f62dc3..d447d2472 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -267,9 +267,11 @@ extern UniValue oraclesaddress(const UniValue& params, bool fHelp); extern UniValue oracleslist(const UniValue& params, bool fHelp); extern UniValue oraclesinfo(const UniValue& params, bool fHelp); extern UniValue oraclescreate(const UniValue& params, bool fHelp); +extern UniValue oraclesfund(const UniValue& params, bool fHelp); extern UniValue oraclesregister(const UniValue& params, bool fHelp); extern UniValue oraclessubscribe(const UniValue& params, bool fHelp); extern UniValue oraclesdata(const UniValue& params, bool fHelp); +extern UniValue oraclessample(const UniValue& params, bool fHelp); extern UniValue oraclessamples(const UniValue& params, bool fHelp); extern UniValue pricesaddress(const UniValue& params, bool fHelp); extern UniValue priceslist(const UniValue& params, bool fHelp); @@ -510,6 +512,7 @@ extern UniValue pricescashout(const UniValue& params, bool fHelp); extern UniValue pricesrekt(const UniValue& params, bool fHelp); extern UniValue pricesaddfunding(const UniValue& params, bool fHelp); extern UniValue pricesgetorderbook(const UniValue& params, bool fHelp); +extern UniValue pricesrefillfund(const UniValue& params, bool fHelp); diff --git a/src/script/script_ext.cpp b/src/script/script_ext.cpp index 532e39d6c..f1d903946 100644 --- a/src/script/script_ext.cpp +++ b/src/script/script_ext.cpp @@ -85,6 +85,7 @@ const CScriptExt &CScriptExt::AddCheckLockTimeVerify(int64_t unlocktime) const *((CScript *)this) << OP_DROP; return *this; } + return *this; } // combined CLTV script and P2PKH diff --git a/src/wallet/db.h b/src/wallet/db.h index e1ae52909..8ad246de4 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -33,9 +33,17 @@ #include -// If CCLIB fails to compile with this, use the one below. -#include -//#include "../depends/x86_64-unknown-linux-gnu/include/db_cxx.h" +#ifdef BUILD_ROGUE + #ifdef __APPLE__ + #include "../depends/x86_64-apple-darwin18.6.0/include/db_cxx.h" + #elif defined(_WIN32) + #include "../depends/x86_64-w64-mingw32/include/db_cxx.h" + #else + #include "../depends/x86_64-unknown-linux-gnu/include/db_cxx.h" + #endif +#else + #include +#endif extern unsigned int nWalletDBUpdated; diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index 1fe9db11a..676239d0b 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -1680,6 +1680,63 @@ TEST(WalletTests, WriteWitnessCache) { wallet.SetBestChain(walletdb, loc); } +TEST(WalletTests, SetBestChainIgnoresTxsWithoutShieldedData) { + SelectParams(CBaseChainParams::REGTEST); + + TestWallet wallet; + MockWalletDB walletdb; + CBlockLocator loc; + + // Set up transparent address + CKey tsk = DecodeSecret(tSecretRegtest); + wallet.AddKey(tsk); + auto scriptPubKey = GetScriptForDestination(tsk.GetPubKey().GetID()); + + // Set up a Sprout address + auto sk = libzcash::SproutSpendingKey::random(); + wallet.AddSproutSpendingKey(sk); + + // Generate a transparent transaction that is ours + CMutableTransaction t; + t.vout.resize(1); + t.vout[0].nValue = 90*CENT; + t.vout[0].scriptPubKey = scriptPubKey; + CWalletTx wtxTransparent {nullptr, t}; + wallet.AddToWallet(wtxTransparent, true, NULL); + + // Generate a Sprout transaction that is ours + auto wtxSprout = GetValidReceive(sk, 10, true); + auto noteMap = wallet.FindMySproutNotes(wtxSprout); + wtxSprout.SetSproutNoteData(noteMap); + wallet.AddToWallet(wtxSprout, true, NULL); + + // Generate a Sprout transaction that only involves our transparent address + auto sk2 = libzcash::SproutSpendingKey::random(); + auto wtxInput = GetValidReceive(sk2, 10, true); + auto note = GetNote(sk2, wtxInput, 0, 0); + auto wtxTmp = GetValidSpend(sk2, note, 5); + CMutableTransaction mtx {wtxTmp}; + mtx.vout[0].scriptPubKey = scriptPubKey; + CWalletTx wtxSproutTransparent {NULL, mtx}; + wallet.AddToWallet(wtxSproutTransparent, true, NULL); + + EXPECT_CALL(walletdb, TxnBegin()) + .WillOnce(Return(true)); + EXPECT_CALL(walletdb, WriteTx(wtxTransparent.GetHash(), wtxTransparent)) + .Times(0); + EXPECT_CALL(walletdb, WriteTx(wtxSprout.GetHash(), wtxSprout)) + .Times(1).WillOnce(Return(true)); + EXPECT_CALL(walletdb, WriteTx(wtxSproutTransparent.GetHash(), wtxSproutTransparent)) + .Times(0); + EXPECT_CALL(walletdb, WriteWitnessCacheSize(0)) + .WillOnce(Return(true)); + EXPECT_CALL(walletdb, WriteBestBlock(loc)) + .WillOnce(Return(true)); + EXPECT_CALL(walletdb, TxnCommit()) + .WillOnce(Return(true)); + wallet.SetBestChain(walletdb, loc); +} + TEST(WalletTests, UpdateSproutNullifierNoteMap) { TestWallet wallet; uint256 r {GetRandHash()}; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e8b5481e7..6a47e71a0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -70,9 +70,10 @@ extern std::string ASSETCHAINS_OVERRIDE_PUBKEY; const std::string ADDR_TYPE_SPROUT = "sprout"; const std::string ADDR_TYPE_SAPLING = "sapling"; extern UniValue TxJoinSplitToJSON(const CTransaction& tx); +extern int32_t KOMODO_INSYNC; uint32_t komodo_segid32(char *coinaddr); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); -int32_t komodo_isnotaryvout(char *coinaddr); // from ac_private chains only +int32_t komodo_isnotaryvout(char *coinaddr,uint32_t tiptime); // from ac_private chains only CBlockIndex *komodo_getblockindex(uint256 hash); int64_t nWalletUnlockTime; @@ -84,6 +85,7 @@ UniValue z_getoperationstatus_IMPL(const UniValue&, bool); #define PLAN_NAME_MAX 8 #define VALID_PLAN_NAME(x) (strlen(x) <= PLAN_NAME_MAX) +#define THROW_IF_SYNCING(INSYNC) if (INSYNC == 0) { throw runtime_error(strprintf("%s: Chain still syncing at height %d, aborting to prevent linkability analysis!",__FUNCTION__,chainActive.Tip()->GetHeight())); } int tx_height( const uint256 &hash ); @@ -461,7 +463,6 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); } -int32_t komodo_isnotaryvout(char *coinaddr); UniValue sendtoaddress(const UniValue& params, bool fHelp) { @@ -494,7 +495,7 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp) if ( ASSETCHAINS_PRIVATE != 0 && AmountFromValue(params[1]) > 0 ) { - if ( komodo_isnotaryvout((char *)params[0].get_str().c_str()) == 0 ) + if ( komodo_isnotaryvout((char *)params[0].get_str().c_str(),chainActive.LastTip()->nTime) == 0 ) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address"); } @@ -4250,6 +4251,8 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); + THROW_IF_SYNCING(KOMODO_INSYNC); + // Check that the from address is valid. auto fromaddress = params[0].get_str(); bool fromTaddr = false; @@ -4350,8 +4353,9 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) //else if ( ASSETCHAINS_PRIVATE != 0 && komodo_isnotaryvout((char *)address.c_str()) == 0 ) // throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain"); - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address); + // Allowing duplicate receivers helps various HushList protocol operations + //if (setAddress.count(address)) + // throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address); setAddress.insert(address); UniValue memoValue = find_value(o, "memo"); @@ -4559,6 +4563,8 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); + THROW_IF_SYNCING(KOMODO_INSYNC); + // Validate the from address auto fromaddress = params[0].get_str(); bool isFromWildcard = fromaddress == "*"; @@ -4819,6 +4825,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); + THROW_IF_SYNCING(KOMODO_INSYNC); + bool useAnyUTXO = false; bool useAnySprout = false; bool useAnySapling = false; @@ -5334,8 +5342,13 @@ int32_t ensure_CCrequirements(uint8_t evalcode) CCerror = ""; if ( ASSETCHAINS_CCDISABLES[evalcode] != 0 || (evalcode == EVAL_MARMARA && ASSETCHAINS_MARMARA == 0) ) { - fprintf(stderr,"evalcode %d disabled\n",evalcode); - return(-1); + // check if a height activation has been set. + fprintf(stderr, "evalcode.%i activates at height. %i current height.%i\n", evalcode, mapHeightEvalActivate[evalcode], komodo_currentheight()); + if ( mapHeightEvalActivate[evalcode] == 0 || komodo_currentheight() == 0 || mapHeightEvalActivate[evalcode] > komodo_currentheight() ) + { + fprintf(stderr,"evalcode %d disabled\n",evalcode); + return(-1); + } } if ( NOTARY_PUBKEY33[0] == 0 ) { @@ -5551,6 +5564,8 @@ UniValue cclibinfo(const UniValue& params, bool fHelp) UniValue cclib(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; char *method,*jsonstr=0; uint8_t evalcode = EVAL_FIRSTUSER; + std::string vobjJsonSerialized; + if ( fHelp || params.size() > 3 ) throw runtime_error("cclib method [evalcode] [JSON params]\n"); if ( ASSETCHAINS_CCLIB.size() == 0 ) @@ -5570,7 +5585,12 @@ UniValue cclib(const UniValue& params, bool fHelp) } if ( params.size() == 3 ) { - jsonstr = (char *)params[2].get_str().c_str(); + if (params[2].getType() == UniValue::VOBJ) { + vobjJsonSerialized = params[2].write(0, 0); + jsonstr = (char *)vobjJsonSerialized.c_str(); + } + else // VSTR assumed + jsonstr = (char *)params[2].get_str().c_str(); //fprintf(stderr,"params.(%s %s %s)\n",params[0].get_str().c_str(),params[1].get_str().c_str(),jsonstr); } } @@ -5582,7 +5602,7 @@ UniValue payments_release(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; if ( fHelp || params.size() != 1 ) - throw runtime_error("paymentsrelease \"[%22createtxid%22,amount]\"\n"); + throw runtime_error("paymentsrelease \"[%22createtxid%22,amount,(skipminimum)]\"\n"); if ( ensure_CCrequirements(EVAL_PAYMENTS) < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); const CKeyStore& keystore = *pwalletMain; @@ -5660,7 +5680,7 @@ UniValue payments_airdroptokens(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; if ( fHelp || params.size() != 1 ) - throw runtime_error("paymentsairdrop \"[%22tokenid%22,lockedblocks,minamount,mintoaddress,top,bottom,fixedFlag,%22excludePubKey%22,...,%22excludePubKeyN%22]\"\n"); + throw runtime_error("payments_airdroptokens \"[%22tokenid%22,lockedblocks,minamount,mintoaddress,top,bottom,fixedFlag,%22excludePubKey%22,...,%22excludePubKeyN%22]\"\n"); if ( ensure_CCrequirements(EVAL_PAYMENTS) < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); const CKeyStore& keystore = *pwalletMain; @@ -6753,6 +6773,26 @@ UniValue oraclesinfo(const UniValue& params, bool fHelp) return(OracleInfo(txid)); } +UniValue oraclesfund(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint256 txid; std::string hex; + if ( fHelp || params.size() != 1 ) + throw runtime_error("oraclesfund oracletxid\n"); + if ( ensure_CCrequirements(EVAL_ORACLES) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + txid = Parseuint256((char *)params[0].get_str().c_str()); + hex = OracleFund(0,txid); + RETURN_IF_ERROR(CCerror); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldnt fund with oracle txid"); + return(result); +} + UniValue oraclesregister(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); uint256 txid; int64_t datafee; std::string hex; @@ -6797,19 +6837,33 @@ UniValue oraclessubscribe(const UniValue& params, bool fHelp) return(result); } +UniValue oraclessample(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint256 oracletxid,txid; int32_t num; char *batonaddr; + if ( fHelp || params.size() != 2 ) + throw runtime_error("oraclessample oracletxid txid\n"); + if ( ensure_CCrequirements(EVAL_ORACLES) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + oracletxid = Parseuint256((char *)params[0].get_str().c_str()); + txid = Parseuint256((char *)params[1].get_str().c_str()); + return(OracleDataSample(oracletxid,txid)); +} + UniValue oraclessamples(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); uint256 txid,batontxid; int32_t num; + UniValue result(UniValue::VOBJ); uint256 txid; int32_t num; char *batonaddr; if ( fHelp || params.size() != 3 ) - throw runtime_error("oraclessamples oracletxid batonutxo num\n"); + throw runtime_error("oraclessamples oracletxid batonaddress num\n"); if ( ensure_CCrequirements(EVAL_ORACLES) < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); const CKeyStore& keystore = *pwalletMain; LOCK2(cs_main, pwalletMain->cs_wallet); txid = Parseuint256((char *)params[0].get_str().c_str()); - batontxid = Parseuint256((char *)params[1].get_str().c_str()); + batonaddr = (char *)params[1].get_str().c_str(); num = atoi((char *)params[2].get_str().c_str()); - return(OracleDataSamples(txid,batontxid,num)); + return(OracleDataSamples(txid,batonaddr,num)); } UniValue oraclesdata(const UniValue& params, bool fHelp) @@ -8021,9 +8075,9 @@ UniValue opreturn_burn(const UniValue& params, bool fHelp) if (fHelp || (params.size() != 2)) throw runtime_error("amount to burn, hexstring to send\n"); struct CCcontract_info *cp, C; UniValue ret(UniValue::VOBJ); - if (ensure_CCrequirements(EVAL_PAYMENTS) < 0) + if (ensure_CCrequirements(EVAL_ORACLES) < 0) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - cp = CCinit(&C, EVAL_PAYMENTS); + cp = CCinit(&C, EVAL_ORACLES); CAmount nAmount = AmountFromValue(params[0]); if (nAmount <= 10000) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index fa39d204a..4d834ccee 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2874,21 +2874,18 @@ void CWallet::ReacceptWalletTransactions() bool invalid = state.IsInvalid(nDoS); // log rejection and deletion - // printf("ERROR reaccepting wallet transaction %s to mempool, reason: %s, DoS: %d\n", wtx.GetHash().ToString().c_str(), state.GetRejectReason().c_str(), nDoS); + //printf("ERROR reaccepting wallet transaction %s to mempool, reason: %s, DoS: %d\n", wtx.GetHash().ToString().c_str(), state.GetRejectReason().c_str(), nDoS); - if (!wtx.IsCoinBase() && invalid && nDoS > 0) + if (!wtx.IsCoinBase() && invalid && nDoS > 0 && state.GetRejectReason() != "tx-overwinter-expired") { LogPrintf("erasing transaction %s\n", wtx.GetHash().GetHex().c_str()); vwtxh.push_back(wtx.GetHash()); } } } - if ( IsInitialBlockDownload() == 0 ) + for (auto hash : vwtxh) { - for (auto hash : vwtxh) - { - EraseFromWallet(hash); - } + EraseFromWallet(hash); } } @@ -2896,7 +2893,7 @@ bool CWalletTx::RelayWalletTransaction() { if ( pwallet == 0 ) { - fprintf(stderr,"unexpected null pwallet in RelayWalletTransaction\n"); + //fprintf(stderr,"unexpected null pwallet in RelayWalletTransaction\n"); return(false); } assert(pwallet->GetBroadcastTransactions()); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index b00365a77..296e2fa57 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -807,10 +807,17 @@ protected: } try { for (std::pair& wtxItem : mapWallet) { - if (!walletdb.WriteTx(wtxItem.first, wtxItem.second)) { - LogPrintf("SetBestChain(): Failed to write CWalletTx, aborting atomic write\n"); - walletdb.TxnAbort(); - return; + auto wtx = wtxItem.second; + // We skip transactions for which mapSproutNoteData and mapSaplingNoteData + // are empty. This covers transactions that have no Sprout or Sapling data + // (i.e. are purely transparent), as well as shielding and unshielding + // transactions in which we only have transparent addresses involved. + if (!(wtx.mapSproutNoteData.empty() && wtx.mapSaplingNoteData.empty())) { + if (!walletdb.WriteTx(wtxItem.first, wtx)) { + LogPrintf("SetBestChain(): Failed to write CWalletTx, aborting atomic write\n"); + walletdb.TxnAbort(); + return; + } } } if (!walletdb.WriteWitnessCacheSize(nWitnessCacheSize)) { diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index efba38d9e..d2d90a85f 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -41,6 +41,7 @@ using namespace std; static uint64_t nAccountingEntryNumber = 0; static list deadTxns; +extern CBlockIndex *komodo_blockindex(uint256 hash); // // CWalletDB @@ -487,7 +488,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, auto verifier = libzcash::ProofVerifier::Strict(); // ac_public chains set at height like KMD and ZEX, will force a rescan if we dont ignore this error: bad-txns-acpublic-chain // there cannot be any ztx in the wallet on ac_public chains that started from block 1, so this wont affect those. - if ( !(CheckTransaction(0,wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid()) && (state.GetRejectReason() != "bad-txns-acpublic-chain") ) + // PIRATE fails this check for notary nodes, need exception. Triggers full rescan without it. + if ( !(CheckTransaction(0,wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid()) && (state.GetRejectReason() != "bad-txns-acpublic-chain" && state.GetRejectReason() != "bad-txns-acprivacy-chain") ) { //fprintf(stderr, "tx failed: %s rejectreason.%s\n", wtx.GetHash().GetHex().c_str(), state.GetRejectReason().c_str()); // vin-empty on staking chains is error relating to a failed staking tx, that for some unknown reason did not fully erase. save them here to erase and re-add later on. @@ -964,21 +966,20 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) // staking chains with vin-empty error is a failed staking tx. // we remove then re add the tx here to stop needing a full rescan, which does not actually fix the problem. int32_t reAdded = 0; - CWalletDB walletdb(pwallet->strWalletFile, "r+", false); BOOST_FOREACH (uint256& hash, deadTxns) { - fprintf(stderr, "Removing corrupt tx from wallet.%s\n", hash.ToString().c_str()); + fprintf(stderr, "Removing possible orphaned staking transaction from wallet.%s\n", hash.ToString().c_str()); if (!EraseTx(hash)) fprintf(stderr, "could not delete tx.%s\n",hash.ToString().c_str()); - uint256 blockhash; CTransaction tx; - if (GetTransaction(hash,tx,blockhash,true)) + uint256 blockhash; CTransaction tx; CBlockIndex* pindex; + if ( GetTransaction(hash,tx,blockhash,false) && (pindex= komodo_blockindex(blockhash)) != 0 && chainActive.Contains(pindex) ) { CWalletTx wtx(pwallet,tx); - pwallet->AddToWallet(wtx, false, &walletdb); + pwallet->AddToWallet(wtx, true, NULL); reAdded++; } } - fprintf(stderr, "Cleared %li corrupted transactions from wallet. Readded %i known transactions.\n",deadTxns.size(),reAdded); + fprintf(stderr, "Cleared %li orphaned staking transactions from wallet. Readded %i real transactions.\n",deadTxns.size(),reAdded); fNoncriticalErrors = false; deadTxns.clear(); } diff --git a/toolchain-info.sh b/toolchain-info.sh index 0bb39c19b..6a0fc7e75 100755 --- a/toolchain-info.sh +++ b/toolchain-info.sh @@ -1,6 +1,6 @@ #!/bin/bash -tools=("gcc-6" "g++-6" "otool" "nm") +tools=("gcc-8" "g++-8" "otool" "nm") echo "Platform: `uname -a`" echo "-------------------------------------" diff --git a/zcutil/build-mac.sh b/zcutil/build-mac.sh index df4efd05f..3c0522a90 100755 --- a/zcutil/build-mac.sh +++ b/zcutil/build-mac.sh @@ -1,6 +1,6 @@ #!/bin/bash -export CC=gcc-6 -export CXX=g++-6 +export CC=gcc-8 +export CXX=g++-8 export LIBTOOL=libtool export AR=ar export RANLIB=ranlib @@ -47,12 +47,12 @@ make "$@" -C ./depends/ V=1 NO_QT=1 NO_PROTON=1 WD=$PWD cd src/cc echo $PWD -./makerogue +./makecustom cd $WD ./autogen.sh CPPFLAGS="-I$PREFIX/include -arch x86_64" LDFLAGS="-L$PREFIX/lib -arch x86_64 -Wl,-no_pie" \ -CXXFLAGS='-arch x86_64 -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/ -I$PREFIX/include -fwrapv -fno-strict-aliasing -Werror -g -Wl,-undefined -Wl,dynamic_lookup' \ +CXXFLAGS='-arch x86_64 -I/usr/local/Cellar/gcc\@8/8.3.0/include/c++/8.3.0/ -I$PREFIX/include -fwrapv -fno-strict-aliasing -Wno-builtin-declaration-mismatch -Werror -g -Wl,-undefined -Wl,dynamic_lookup' \ ./configure --prefix="${PREFIX}" --with-gui=no "$HARDENING_ARG" "$LCOV_ARG" make "$@" V=1 NO_GTEST=1 STATIC=1 diff --git a/zcutil/build-win.sh b/zcutil/build-win.sh index 8cf1751af..e8c0465d9 100755 --- a/zcutil/build-win.sh +++ b/zcutil/build-win.sh @@ -14,7 +14,7 @@ cd ../ WD=$PWD cd src/cc echo $PWD -./makerogue +./makecustom cd $WD ./autogen.sh diff --git a/zcutil/build.sh b/zcutil/build.sh index dc4d027b1..96e0b7c2c 100755 --- a/zcutil/build.sh +++ b/zcutil/build.sh @@ -106,7 +106,7 @@ CONFIG_SITE="$PWD/depends/$HOST/share/config.site" ./configure "$HARDENING_ARG" WD=$PWD cd src/cc echo $PWD -./makecclib +./makecustom cd $WD "$MAKE" "$@" V=1