diff --git a/.gitignore b/.gitignore index 2ab07ee0f..6cebf87fe 100644 --- a/.gitignore +++ b/.gitignore @@ -132,6 +132,11 @@ src/cc/rogue/rogue src/cc/rogue/rogue.so src/cc/rogue/test.zip +src/checkfile + +src/foo.zip + +src/log src/rogue.530623577502174316.0 @@ -139,11 +144,6 @@ src/rogue.530623577502174316.pack src/rogue.530623577502174316.player -src/checkfile - -src/log - -src/foo.zip src/cc/rogue/config.h @@ -154,3 +154,4 @@ src/ROGUE.conf src/rogue.scr src/cc/rogue/confdefs.h +src/cc/rogue/x64 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a9fb7a01b..a7354b240 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -71,6 +71,10 @@ build:windows: - cp src/komodod.exe src/komodo-cli.exe src/komodo-tx.exe + src/cc/rogue/rogue.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} @@ -91,6 +95,7 @@ build:macos: key: "${CI_JOB_NAME}${CI_COMMIT_REF_NAME}" paths: - depends/built + allow_failure: true script: - zcutil/build-mac.sh -j$(sysctl -n hw.physicalcpu) - ./makeRelease.sh ${PACKAGE_DIR_MACOS} diff --git a/README.md b/README.md index 9a8582891..6c0002ba4 100644 --- a/README.md +++ b/README.md @@ -71,16 +71,32 @@ cd komodo #This can take some time. ``` + #### OSX -Ensure you have [brew](https://brew.sh) and the command line tools installed (comes automatically with XCode) and run: +Ensure you have [brew](https://brew.sh) and Command Line Tools installed. ```shell -brew update && brew install gcc@6 +# Install brew +/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +# Install Xcode, opens a pop-up window to install CLT without installing the entire Xcode package +xcode-select --install +# Update brew and install dependencies +brew update +brew upgrade +brew tap discoteq/discoteq; brew install flock +brew install autoconf autogen automake +brew install gcc@6 +brew install binutils +brew install protobuf +brew install coreutils +brew install wget +# Clone the Komodo repo git clone https://github.com/komodoplatform/komodo --branch master --single-branch +# Change master branch to other branch you wish to compile cd komodo ./zcutil/fetch-params.sh # -j8 = using 8 threads for the compilation - replace 8 with number of threads you want to use ./zcutil/build-mac.sh -j8 -#This can take some time. +# This can take some time. ``` #### Windows diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 3c180b0ce..800c424c5 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,9 @@ package=boost + $(package)_version=1_66_0 $(package)_download_path=https://dl.bintray.com/boostorg/release/1.66.0/source -$(package)_file_name=$(package)_$($(package)_version).tar.bz2 $(package)_sha256_hash=5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9 +$(package)_file_name=$(package)_$($(package)_version).tar.bz2 define $(package)_set_vars $(package)_config_opts_release=variant=release diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 0cb256e81..89fb6ef1c 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -1,21 +1,21 @@ ifeq ($(host_os),mingw32) -$(package)_version=4.2.2-1 +$(package)_version=4.3.1 $(package)_download_path=https://github.com/ca333/libzmq/archive $(package)_download_file=v$($(package)_version).tar.gz $(package)_file_name=libzmq-$($(package)_version).tar.gz -$(package)_sha256_hash=0e225b85ce11be23bf7eb7d3f25c6686728bf30d5c31f61c12d37bb646c69962 +$(package)_sha256_hash=cb8ebe5b60dadeb526745610d6237f05a98aba287114d8991dad1fa14f4be354 define $(package)_set_vars $(package)_build_env+= $(package)_config_opts=--enable-shared=false --enable-static --host=x86_64-w64-mingw32 - $(package)_config_opts_mingw32=--enable-shared=false --enable-static --host=x86_64-w64-mingw32 + $(package)_config_opts_mingw32=--enable-shared=false --enable-static --prefix=$(host_prefix) --host=x86_64-w64-mingw32 -disable-curve $(package)_cflags=-Wno-error -Wall -Wno-pedantic-ms-format -DLIBCZMQ_EXPORTS -DZMQ_DEFINED_STDINT -lws2_32 -liphlpapi -lrpcrt4 $(package)_conf_tool=./configure endef else package=zeromq $(package)_version=4.3.1 -$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ +$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version) $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=bcbabe1e2c7d0eec4ed612e10b94b112dd5f06fcefa994a0c79a45d835cd21eb diff --git a/doc/release-notes/release-notes-0.3.0.md b/doc/release-notes/release-notes-0.3.0.md new file mode 100644 index 000000000..84ffc8efb --- /dev/null +++ b/doc/release-notes/release-notes-0.3.0.md @@ -0,0 +1,58 @@ + +Komodo specific changelog: + +- add CC functionality and bugfixes +- set sapling activation +- change z-addr prefix byte +- blocksize increased from 2MB to 4 MB +- transaction size increased from 100KB to 200KB + +Sapling related changelog: + +- Decoupled Spend Authority +- Improved Performance for Shielded Transactions (using sapling instead of sprout) +- transaction format changed + +Alex Morcos (1): Output line to debug.log when IsInitialBlockDownload latches to false + +Ariel Gabizon (1): Extend Joinsplit tests to Groth + +Charlie OKeefe (1): Remove extra slash from lockfile path + +Cory Fields (1): crypter: shuffle Makefile so that crypto can be used by the wallet + +Daira Hopwood (1): Support testnet rollback. + +Daniel Cousens (2): move rpc* to rpc/ rpc: update inline comments to refer to new file paths + +Dimitris Apostolou (1): Fix typos + +Duke Leto (3): Fix absurd fee bug reported in #3281, with tests Update comment as per @arielgabizon Improve error message + +Eirik Ogilvie-Wigley (24): Add more options when asserting in RPC tests Add change indicator for notes Fix test broken by change indicator Rename note data to include sprout Remove redundant curly braces Consolidate for loops Add out point for sapling note data Add sapling note data and map Decrement sapling note witnesses Clear sapling witness cache Extract method for copying previous witnesses Extract methods for incrementing witnesses Extract method for incrementing witness heights Pass sapling merkle tree when incrementing witnesses Increment sapling note witnesses Rename sprout specific methods Remove extra indentation Add getter and setter for sapling note data and update tests Add parameter for version in GetValidReceive Rename Merkle Trees to include sprout or sapling Rename Witnesses to include sprout or sapling Rename test objects to include sprout or sapling Only include the change field if we have a spending key Fix assertion and comment + +Gregory Maxwell (2): IBD check uses minimumchain work instead of checkpoints. IsInitialBlockDownload no longer uses header-only timestamps. + +Jack Grigg (41): Add some more checkpoints, up to the 1.1.0 release Add Sapling support to z_validateaddress Update payment-api.md with type field of z_validateaddress Alter SaplingNote::nullifier() to take a SaplingFullViewingKey Expose note position in IncrementalMerkleWitness TransactionBuilder with support for creating Sapling-only transactions TransactionBuilder: Check that all anchors in a transaction are identical Formatting test: Move ECC_Start() call into src/gtest/main.cpp TransactionBuilder: Add support for transparent inputs and outputs TransactionBuilder: Add change output to transaction TransactionBuilder: Make fee configurable Rename xsk to expsk Implement CKeyStore::GetSaplingPaymentAddresses() Raise the 90-character limit on Bech32 encodings Add Sapling support to z_getnewaddress and z_listaddresses Fix block hash for checkpoint at height 270000 Formatting test: Deduplicate logic in wallet_addresses RPC test test: Another assert in wallet_zkeys_tests.store_and_load_sapling_zkeys test: Fix permissions of wallet_addresses test: Update rpc_wallet_z_importexport to account for Sapling changes Rename DecryptSpendingKey -> DecryptSproutSpendingKey Rename CryptedSpendingKeyMap -> CryptedSproutSpendingKeyMap Add Sapling decryption check to CCryptoKeyStore::Unlock() Check for unencrypted Sapling keys in CCryptoKeyStore::SetCrypted() Remove outdated comment Add CWallet::AddCryptedSaplingSpendingKey() hook Pass SaplingPaymentAddress to store through the CKeyStore Rename SpendingKeyMap -> SproutSpendingKeyMap Rename SerializedSize -> SerializedSproutSize Rename ViewingKey -> SproutViewingKey Formatting nits Rename *SpendingKey -> *SproutSpendingKey chainparams: Add BIP 44 coin type (as registered in SLIP 44) Upgrade Rust to 1.28.0 stable Adjust Makefile so that common can be used by the wallet Move RewindBlockIndex log message inside rewindLength check test: gtest for Sapling encoding and decoding test: Use regtest in key_tests/zs_address_test Disable Sapling features on mainnet + +Jay Graber (13): Add Sapling Add/Have/Get to keystore Add SaplingIncomingViewingKeys map, SaplingFullViewingKey methods Add StoreAndRetrieveSaplingSpendingKey test Change default_address to return SaplingPaymentAddr and not boost::optional Add crypted keystore sapling add key Discard sk if ivk == 0 Add Sapling support to z_exportkey Add Sapling support to z_importkey Add Sapling to rpc_wallet_z_importexport test Refactor into visitors and throw errors for invalid key or address. Take expiryheight as param to createrawtransaction Add Sapling have/get sk crypter overrides Add Sapling keys to CCryptoKeyStore::EncryptKeys + +Jonas Schnelli (2): [RPC, Wallet] Move RPC dispatch table registration to wallet/ code Fix test_bitcoin circular dependency issue + +Kaz Wesley (1): IsInitialBlockDownload: usually avoid locking + +Larry Ruane (4): Disable libsnark debug logging in Boost tests add extra help how to enable experimental features Add call to sync_all() after (z_sendmany, wait) don't ban peers when loading pre-overwinter blocks + +Pejvan (2): Update README.md Update README.md + +Richard Littauer (1): docs(LICENSE): update license year to 2018 + +Sean Bowe (21): Update librustzcash Implementation of Sapling in-band secret distribution. Swap types in OutputDescription to use new NoteEncryption interfaces. Prevent nonce reuse in Sapling note encryption API. Add get_esk() function to Sapling note encryption. Minor edits Decryption and tests of note/outgoing encryption. Update librustzcash and sapling-crypto. Fix bug in return value. Ensure sum of valueBalance and all vpub_new's does not exceed MAX_MONEY inside of CheckTransactionWithoutProofVerification. Move extern params to beginning of test_checktransaction. Relocate ECC_Start() to avoid test failures. Don't call ECC_Start/ECC_Stop outside the test harness. Make changes to gtest ECC behavior suggested by @str4d. Check the hash of the (Sapling+) zk-SNARK parameters during initialization. Switch to use the official Sapling parameters. make-release.py: Versioning changes for 2.0.0-rc1. make-release.py: Updated manpages for 2.0.0-rc1. make-release.py: Updated release notes and changelog for 2.0.0-rc1. Always write the empty root down as the best root, since we may roll back. Sapling mainnet activation height + +Simon Liu (11): Add encryption of SaplingNotePlaintext and SaplingOutgoingPlaintext classes. Update and fix per review comments, the test for absurd fee. Minor update to address nits in review. Implement Sapling note decryption using full viewing key. Rename AttemptSaplingEncDecryptionUsingFullViewingKey and use function overloading. Only check for a valid Sapling anchor after Sapling activation. Clean up for rebase: rename mapNoteData to mapSproutNoteData. Clean up help messages for RPC createrawtransaction. Add tests for expiryheight parameter of RPC createrawtransaction. make-release.py: Versioning changes for 2.0.0. make-release.py: Updated manpages for 2.0.0. + +Wladimir J. van der Laan (2): Make max tip age an option instead of chainparam rpc: Register calls where they are defined + +kozyilmaz (1): Add -Wl,-pie linker option for macOS and use it instead of -pie + +mdr0id (1): Fix minor references to auto-senescence in code diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 226c16b11..c4775fa85 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -11,6 +11,8 @@ export BITCOIND=${REAL_BITCOIND} #Run the tests testScripts=( + 'dpow.py' + 'dpowconfs.py' 'ac_private.py' 'verushash.py' 'paymentdisclosure.py' diff --git a/qa/rpc-tests/cryptoconditions_channels.py b/qa/rpc-tests/cryptoconditions_channels.py index 722cce66e..71f62f49d 100755 --- a/qa/rpc-tests/cryptoconditions_channels.py +++ b/qa/rpc-tests/cryptoconditions_channels.py @@ -31,7 +31,8 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework): result = rpc.channelsaddress(self.pubkey) assert_success(result) # test that additional CCaddress key is returned - for x in ['myCCaddress', 'ChannelsCCaddress', 'Channelsmarker', 'myaddress', 'CCaddress']: + for x in ['ChannelsCC1of2TokensAddress', 'myCCAddress(Channels)', 'ChannelsCC1of2Address', 'myAddress', \ + 'myCCaddress', 'ChannelsNormalAddress', 'PubkeyCCaddress(Channels)', 'ChannelsCCAddress']: assert_equal(result[x][0], 'R') # getting empty channels list diff --git a/qa/rpc-tests/cryptoconditions_dice.py b/qa/rpc-tests/cryptoconditions_dice.py index 51fd18908..7b960cb67 100755 --- a/qa/rpc-tests/cryptoconditions_dice.py +++ b/qa/rpc-tests/cryptoconditions_dice.py @@ -24,15 +24,19 @@ class CryptoconditionsDiceTest(CryptoconditionsTestFramework): result = rpc1.getbalance() assert_greater_than(result, 100000) - dice = rpc.diceaddress() - assert_equal(dice['result'], 'success') - for x in ['myCCaddress', 'DiceCCaddress', 'Dicemarker', 'myaddress']: - assert_equal(dice[x][0], 'R') + result = rpc.diceaddress() + for x in result.keys(): + print(x+": "+str(result[x])) + assert_equal(result['result'], 'success') + for x in ['myCCaddress', 'DiceCCAddress', 'myaddress']: + assert_equal(result[x][0], 'R') - dice = rpc.diceaddress(self.pubkey) - assert_equal(dice['result'], 'success') - for x in ['myCCaddress', 'DiceCCaddress', 'Dicemarker', 'myaddress', 'CCaddress']: - assert_equal(dice[x][0], 'R') + result = rpc.diceaddress(self.pubkey) + for x in result.keys(): + print(x+": "+str(result[x])) + assert_equal(result['result'], 'success') + for x in ['myCCaddress', 'DiceCCAddress', 'myaddress', 'DiceCCTokensAddress', 'DiceNormalAddress']: + assert_equal(result[x][0], 'R') # no dice created yet result = rpc.dicelist() diff --git a/qa/rpc-tests/cryptoconditions_faucet.py b/qa/rpc-tests/cryptoconditions_faucet.py index a3cbdeb15..c02522cc5 100755 --- a/qa/rpc-tests/cryptoconditions_faucet.py +++ b/qa/rpc-tests/cryptoconditions_faucet.py @@ -24,16 +24,20 @@ class CryptoconditionsFaucetTest(CryptoconditionsTestFramework): assert_greater_than(result['balance'], 0.0) balance = result['balance'] - faucet = rpc.faucetaddress() - assert_equal(faucet['result'], 'success') + result = rpc.faucetaddress() + assert_equal(result['result'], 'success') + for x in result.keys(): + print(x+": "+str(result[x])) # verify all keys look like valid AC addrs, could be better - for x in ['myCCaddress', 'FaucetCCaddress', 'Faucetmarker', 'myaddress']: - assert_equal(faucet[x][0], 'R') + for x in ['myCCaddress', 'FaucetCCTokensAddress', 'FaucetNormalAddress', 'myaddress']: + assert_equal(result[x][0], 'R') result = rpc.faucetaddress(self.pubkey) assert_success(result) + for x in result.keys(): + print(x+": "+str(result[x])) # test that additional CCaddress key is returned - for x in ['myCCaddress', 'FaucetCCaddress', 'Faucetmarker', 'myaddress', 'CCaddress']: + for x in ['myCCaddress', 'FaucetCCTokensAddress', 'FaucetNormalAddress', 'myaddress']: assert_equal(result[x][0], 'R') # no funds in the faucet yet diff --git a/qa/rpc-tests/cryptoconditions_heir.py b/qa/rpc-tests/cryptoconditions_heir.py index b79ae7bba..a2443f0b3 100755 --- a/qa/rpc-tests/cryptoconditions_heir.py +++ b/qa/rpc-tests/cryptoconditions_heir.py @@ -20,16 +20,16 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework): rpc = self.nodes[0] rpc1 = self.nodes[1] - result = rpc.heiraddress() + result = rpc.heiraddress('') assert_success(result) # verify all keys look like valid AC addrs, could be better - for x in ['myCCaddress', 'HeirCCaddress', 'Heirmarker', 'myaddress']: + for x in ['HeirNormalAddress', 'HeirCCTokensAddress', 'myaddress', 'myCCaddress', 'HeirCCAddress']: assert_equal(result[x][0], 'R') result = rpc.heiraddress(self.pubkey) assert_success(result) # test that additional CCaddress key is returned - for x in ['myCCaddress', 'HeirCCaddress', 'Heirmarker', 'myaddress', 'CCaddress']: + for x in ['HeirNormalAddress', 'myCCaddress', 'myaddress', 'HeirCC1of2Address', 'HeirCCAddress', 'HeirCC1of2TokensAddress']: assert_equal(result[x][0], 'R') # getting empty heir list diff --git a/qa/rpc-tests/cryptoconditions_oracles.py b/qa/rpc-tests/cryptoconditions_oracles.py index 048b577d1..008ab6256 100755 --- a/qa/rpc-tests/cryptoconditions_oracles.py +++ b/qa/rpc-tests/cryptoconditions_oracles.py @@ -22,12 +22,12 @@ class CryptoconditionsOraclesTest(CryptoconditionsTestFramework): result = rpc.oraclesaddress() assert_success(result) - for x in ['OraclesCCaddress', 'Oraclesmarker', 'myCCaddress', 'myaddress']: + for x in ['myCCaddress', 'OraclesCCAddress', 'OraclesNormalAddress', 'myaddress', 'OraclesCCTokensAddress']: assert_equal(result[x][0], 'R') result = rpc.oraclesaddress(self.pubkey) assert_success(result) - for x in ['OraclesCCaddress', 'Oraclesmarker', 'myCCaddress', 'myaddress']: + for x in ['myCCaddress', 'OraclesCCAddress', 'OraclesNormalAddress', 'myaddress', 'OraclesCCTokensAddress']: assert_equal(result[x][0], 'R') # there are no oracles created yet diff --git a/qa/rpc-tests/cryptoconditions_rewards.py b/qa/rpc-tests/cryptoconditions_rewards.py index 7bda54eaf..d70e40740 100755 --- a/qa/rpc-tests/cryptoconditions_rewards.py +++ b/qa/rpc-tests/cryptoconditions_rewards.py @@ -15,13 +15,15 @@ from cryptoconditions import assert_success, assert_error, generate_random_strin class CryptoconditionsRewardsTest(CryptoconditionsTestFramework): def run_rewards_tests(self): + rpc = self.nodes[0] + result = rpc.rewardsaddress() - for x in ['RewardsCCaddress', 'myCCaddress', 'Rewardsmarker', 'myaddress']: + for x in ['myCCaddress', 'myaddress', 'RewardsCCAddress', 'RewardsCCTokensAddress', 'RewardsNormalAddress']: assert_equal(result[x][0], 'R') result = rpc.rewardsaddress(self.pubkey) - for x in ['RewardsCCaddress', 'myCCaddress', 'Rewardsmarker', 'myaddress', 'CCaddress']: + for x in ['myCCaddress', 'myaddress', 'RewardsCCAddress', 'RewardsCCTokensAddress', 'RewardsNormalAddress']: assert_equal(result[x][0], 'R') # no rewards yet diff --git a/qa/rpc-tests/cryptoconditions_token.py b/qa/rpc-tests/cryptoconditions_token.py index 97ed86f8d..faf2cbc8d 100755 --- a/qa/rpc-tests/cryptoconditions_token.py +++ b/qa/rpc-tests/cryptoconditions_token.py @@ -21,22 +21,22 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework): result = rpc.tokenaddress() assert_success(result) - for x in ['TokensCCaddress', 'myCCaddress', 'Tokensmarker', 'myaddress']: + for x in ['TokensCCAddress', 'myCCaddress', 'myCCAddress(Tokens)', 'myaddress', 'TokensNormalAddress']: assert_equal(result[x][0], 'R') result = rpc.tokenaddress(self.pubkey) assert_success(result) - for x in ['TokensCCaddress', 'myCCaddress', 'Tokensmarker', 'myaddress', 'CCaddress']: + for x in ['TokensCCAddress', 'myCCaddress', 'myCCAddress(Tokens)', 'myaddress', 'TokensNormalAddress']: assert_equal(result[x][0], 'R') result = rpc.assetsaddress() assert_success(result) - for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress']: + for x in ['AssetsCCAddress', 'myCCaddress', 'myCCAddress(Assets)', 'myaddress', 'AssetsNormalAddress']: assert_equal(result[x][0], 'R') result = rpc.assetsaddress(self.pubkey) assert_success(result) - for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress', 'CCaddress']: + for x in ['AssetsCCAddress', 'myCCaddress', 'myCCAddress(Assets)', 'myaddress', 'AssetsNormalAddress']: assert_equal(result[x][0], 'R') # there are no tokens created yet @@ -61,7 +61,7 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework): assert_equal(result[0], tokenid) # there are no token orders yet - result = rpc.tokenorders() + result = rpc.tokenorders(tokenid) assert_equal(result, []) # getting token balance for non existing tokenid @@ -117,7 +117,7 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework): tokenask = rpc.tokenask("100", tokenid, "7.77") tokenaskhex = tokenask['hex'] tokenaskid = self.send_and_mine(tokenask['hex'], rpc) - result = rpc.tokenorders() + result = rpc.tokenorders(tokenid) order = result[0] assert order, "found order" @@ -136,7 +136,7 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework): assert txid, "found txid" # should be no token orders - result = rpc.tokenorders() + result = rpc.tokenorders(tokenid) assert_equal(result, []) # checking ask cancellation @@ -157,7 +157,7 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework): # from valid node cancel = rpc.tokencancelask(tokenid, testorderid) self.send_and_mine(cancel["hex"], rpc) - result = rpc.tokenorders() + result = rpc.tokenorders(tokenid) assert_equal(result, []) @@ -184,7 +184,7 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework): tokenbid = rpc.tokenbid("100", tokenid, "10") tokenbidhex = tokenbid['hex'] tokenbidid = self.send_and_mine(tokenbid['hex'], rpc) - result = rpc.tokenorders() + result = rpc.tokenorders(tokenid) order = result[0] assert order, "found order" @@ -203,7 +203,7 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework): assert txid, "found txid" # should be no token orders - result = rpc.tokenorders() + result = rpc.tokenorders(tokenid) assert_equal(result, []) # checking bid cancellation @@ -220,7 +220,7 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework): # from valid node cancel = rpc.tokencancelbid(tokenid, testorderid) self.send_and_mine(cancel["hex"], rpc) - result = rpc.tokenorders() + result = rpc.tokenorders(tokenid) assert_equal(result, []) # invalid token transfer amount (have to add status to CC code!) diff --git a/qa/rpc-tests/dpowconfs.py b/qa/rpc-tests/dpowconfs.py new file mode 100755 index 000000000..9c449923e --- /dev/null +++ b/qa/rpc-tests/dpowconfs.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Hush developers +# Copyright (c) 2019 The SuperNET developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time + +class DPoWConfsTest(BitcoinTestFramework): + def debug_info(self): + rpc = self.nodes[0] + print "-- DEBUG --" + getinfo = rpc.getinfo() + getwalletinfo = rpc.getwalletinfo() + listreceivedbyaddress = rpc.listreceivedbyaddress() + print "notarized=", getinfo['notarized'], " blocks=", getinfo['blocks'] + #print "getinfo=", getinfo + print "balance=", getwalletinfo['balance'] + #print "getwalletinfo=", getwalletinfo + print "listreceivedbyaddress=", listreceivedbyaddress + print "-- DEBUG --" + + def setup_chain(self): + self.num_nodes = 1 + print("Initializing DPoWconfs test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, self.num_nodes) + + def setup_network(self): + print("Setting up network...") + self.nodes = [] + self.is_network_split = False + self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" + self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" + self.nodes = start_nodes( self.num_nodes, self.options.tmpdir, + extra_args=[[ + '-ac_name=REGTEST', + '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', + '-port=64367', + '-rpcport=64368', + '-regtest', + '-addressindex=1', + '-spentindex=1', + '-ac_supply=5555555', + '-ac_reward=10000000000000', + #'-pubkey=' + self.pubkey, + '-ac_cc=2', + '-whitelist=127.0.0.1', + '-debug', + '--daemon', + '-rpcuser=rt', + '-rpcpassword=rt' + ]] + ) + self.sync_all() + + def run_test(self): + rpc = self.nodes[0] + # 98 is notarized, next will be 105. Must mine at least 101 + # blocks for 100 block maturity rule + blockhashes = rpc.generate(101) + # block 98, this is 0 indexed + notarizedhash = blockhashes[97] + self.debug_info() + + taddr = rpc.getnewaddress() + txid = rpc.sendtoaddress(taddr, 5.55) + # blocks 102,103 + rpc.generate(2) + self.debug_info() + + info = rpc.getinfo() + print "notarizedhash=", notarizedhash, "\n" + print "info[notarizedhash]", info['notarizedhash'], "\n" + assert_equal( info['notarizedhash'], notarizedhash) + + result = rpc.listunspent() + + # this xtn has 2 raw confs, but not in a notarized block, + # so dpowconfs holds it at 1 + for res in result: + if (res['address'] == taddr and res['generated'] == 'false'): + assert_equal( result[0]['confirmations'], 1 ) + assert_equal( result[0]['rawconfirmations'], 2 ) + + # we will now have 3 rawconfs but confirmations=1 because not notarized + # block 104 + rpc.generate(1) + self.debug_info() + minconf = 2 + result = rpc.listreceivedbyaddress(minconf) + print "listreceivedbyaddress(2)=", result, "\n" + + # nothing is notarized, so we should see no results for minconf=2 + assert len(result) == 0 + + print "getreceivedaddress" + received = rpc.getreceivedbyaddress(taddr, minconf) + assert_equal( received, 0.00000000) + + #received = rpc.getreceivedbyaddress(taddr) + #assert_equal( received, "5.55000000") + taddr = rpc.getnewaddress() + zaddr = rpc.z_getnewaddress() + # should get insufficient funds error + recipients = [ { "amount" : Decimal('4.20'), "address" : zaddr } ] + txid = rpc.z_sendmany( taddr, recipients, minconf) + + # generate a notarized block, block 105 and block 106 + # only generating the notarized block seems to have + # race conditions about whether the block is notarized + txids = rpc.generate(2) + self.debug_info() + + getinfo = rpc.getinfo() + # try to allow notarization data to update + print "Sleeping" + while (getinfo['blocks'] != 106) or (getinfo['notarized'] != 105): + printf(".") + time.sleep(1) + getinfo = rpc.getinfo() + + # make sure this block was notarized as we expect + #assert_equal(getinfo['blocks'], getinfo['notarized']) + #assert_equal(getinfo['notarizedhash'], txids[0]) + + result = rpc.listreceivedbyaddress(minconf) + print "listreceivedbyaddress(2)=", result + + assert_equal( len(result), 1, 'got one xtn with minconf=2' ) + + # verify we see the correct dpowconfs + rawconfs + assert_greater_than( result[0]['confirmations'], 1) + assert_greater_than( result[0]['rawconfirmations'], 1) + + print "listtransactions" + xtns = rpc.listtransactions() + # verify this rpc agrees with listreceivedbyaddress + assert_greater_than(xtns[0]['confirmations'], 1) + assert_greater_than(xtns[0]['rawconfirmations'], 1) + + print "getreceivedaddress" + received = rpc.getreceivedbyaddress(taddr, minconf) + assert_equal( "%.8f" % received, "5.55000000") + + received = rpc.getreceivedbyaddress(taddr) + assert_equal( "%.8f" % received, "5.55000000") + +if __name__ == '__main__': + DPoWConfsTest().main() diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index e9130171b..6bcf4cd18 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -1,9 +1,7 @@ # Copyright (c) 2014 The Bitcoin Core developers -# Copyright (c) 2018 The SuperNET developers +# Copyright (c) 2018-2019 The SuperNET developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. - - # # Helpful routines for regression testing # @@ -415,10 +413,16 @@ def assert_true(condition, message = ""): def assert_false(condition, message = ""): assert_true(not condition, message) +# assert thing2 > thing1 def assert_greater_than(thing1, thing2): if thing1 <= thing2: raise AssertionError("%s <= %s"%(str(thing1),str(thing2))) +# assert thing2 >= thing1 +def assert_greater_than_or_equal(thing1, thing2): + if thing1 < thing2: + raise AssertionError("%s < %s"%(str(thing1),str(thing2))) + def assert_raises(exc, fun, *args, **kwds): try: fun(*args, **kwds) diff --git a/src/Makefile.am b/src/Makefile.am index f06de8910..ce7fd1731 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -204,6 +204,7 @@ BITCOIN_CORE_H = \ mruset.h \ net.h \ netbase.h \ + notaries_staked.h \ noui.h \ paymentdisclosure.h \ paymentdisclosuredb.h \ @@ -311,6 +312,7 @@ libbitcoin_server_a_SOURCES = \ chain.cpp \ checkpoints.cpp \ crosschain.cpp \ + crosschain_authority.cpp \ crypto/haraka.h \ crypto/haraka_portable.h \ crypto/verus_hash.h \ @@ -325,6 +327,7 @@ libbitcoin_server_a_SOURCES = \ metrics.h \ miner.cpp \ net.cpp \ + notaries_staked.cpp \ noui.cpp \ notarisationdb.cpp \ paymentdisclosure.cpp \ @@ -487,6 +490,8 @@ libbitcoin_common_a_SOURCES = \ script/sign.cpp \ script/standard.cpp \ transaction_builder.cpp \ + cc/CCtokensOpRet.cpp \ + cc/CCutilbits.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) diff --git a/src/ac/ilien b/src/ac/ilien new file mode 100755 index 000000000..53e571661 --- /dev/null +++ b/src/ac/ilien @@ -0,0 +1,3 @@ +#!/bin/bash +./komodo-cli -ac_name=ILN $1 $2 $3 $4 $5 $6 + diff --git a/src/ac/iln b/src/ac/iln new file mode 100755 index 000000000..f453c338e --- /dev/null +++ b/src/ac/iln @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=ILN $1 $2 $3 $4 $5 $6 diff --git a/src/ac/our b/src/ac/our new file mode 100755 index 000000000..66c774476 --- /dev/null +++ b/src/ac/our @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=OUR $1 $2 $3 $4 $5 $6 diff --git a/src/assetchains.json b/src/assetchains.json index 91baf9829..dfc352a2f 100644 --- a/src/assetchains.json +++ b/src/assetchains.json @@ -64,13 +64,10 @@ "ac_name": "MESH", "ac_supply": "1000007" }, - { - "ac_name": "MNZ", - "ac_supply": "257142858" - }, { "ac_name": "AXO", - "ac_supply": "200000000" + "ac_supply": "200000000", + "ac_ccactivate": "130000" }, { "ac_name": "ETOMIC", @@ -182,7 +179,7 @@ "190.114.254.104" ] }, - { + { "ac_name": "DION", "ac_supply": "3900000000", "ac_reward": "22260000000", @@ -238,7 +235,14 @@ "addnode": [ "51.255.195.65", "217.182.129.38", - "95.216.150.177" - ] -} + "37.187.225.231" + ] + }, + { + "ac_name": "ILN", + "ac_supply": "10000000000", + "ac_cc": "2", + "addnode": ["51.75.122.83"] + } + ] diff --git a/src/assetchains.old b/src/assetchains.old index 136f7c709..cc85f1cd1 100755 --- a/src/assetchains.old +++ b/src/assetchains.old @@ -20,8 +20,7 @@ echo $pubkey ./komodod -pubkey=$pubkey -ac_name=KV -ac_supply=1000000 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=CEAL -ac_supply=366666666 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=MESH -ac_supply=1000007 -addnode=78.47.196.146 $1 & -./komodod -pubkey=$pubkey -ac_name=MNZ -ac_supply=257142858 -addnode=51.15.138.138 $1 & -./komodod -pubkey=$pubkey -ac_name=AXO -ac_supply=200000000 -addnode=78.47.196.146 & +./komodod -pubkey=$pubkey -ac_name=AXO -ac_supply=200000000 -ac_ccactivate=130000 -addnode=78.47.196.146 & ./komodod -pubkey=$pubkey -ac_name=ETOMIC -ac_supply=100000000 -addnode=78.47.196.146 & ./komodod -pubkey=$pubkey -ac_name=BTCH -ac_supply=20998641 -addnode=78.47.196.146 & ./komodod -pubkey=$pubkey -ac_name=BEER -ac_supply=100000000 -addnode=78.47.196.146 & @@ -46,3 +45,6 @@ echo $pubkey ./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 & + diff --git a/src/cc/CCPayments.h b/src/cc/CCPayments.h index 187d9c9ad..247a0f2ec 100644 --- a/src/cc/CCPayments.h +++ b/src/cc/CCPayments.h @@ -19,9 +19,16 @@ #include "CCinclude.h" +#define PAYMENTS_TXFEE 10000 + bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); // CCcustom -UniValue PaymentsInfo(); +UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr); +UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr); +UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr); +UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr); +UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr); +UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr); #endif diff --git a/src/cc/CCassets.h b/src/cc/CCassets.h index af9ec5bd1..7b31c094d 100644 --- a/src/cc/CCassets.h +++ b/src/cc/CCassets.h @@ -29,7 +29,7 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); // CCassetsCore -CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector origpubkey); +vscript_t EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector origpubkey); uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &assetsEvalCode, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CTransaction &tx); int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid); diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 63c94d920..06d843b40 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -239,30 +239,30 @@ CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector origpubkey,st } */ -CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector origpubkey) +vscript_t EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector origpubkey) { - CScript opret; + vscript_t vopret; uint8_t evalcode = EVAL_ASSETS; switch ( assetFuncId ) { //case 't': this cannot be here case 'x': case 'o': - opret << OP_RETURN << E_MARSHAL(ss << evalcode << assetFuncId); + vopret = /*<< OP_RETURN <<*/ E_MARSHAL(ss << evalcode << assetFuncId); break; case 's': case 'b': case 'S': case 'B': - opret << OP_RETURN << E_MARSHAL(ss << evalcode << assetFuncId << price << origpubkey); + vopret = /*<< OP_RETURN <<*/ E_MARSHAL(ss << evalcode << assetFuncId << price << origpubkey); break; case 'E': case 'e': assetid2 = revuint256(assetid2); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << assetFuncId << assetid2 << price << origpubkey); + vopret = /*<< OP_RETURN <<*/ E_MARSHAL(ss << evalcode << assetFuncId << assetid2 << price << origpubkey); break; default: fprintf(stderr,"EncodeAssetOpRet: illegal funcid.%02x\n", assetFuncId); - opret << OP_RETURN; + //opret << OP_RETURN; break; } - return(opret); + return(vopret); } /* it is for compatibility, do not use this for new contracts (use DecodeTokenCreateOpRet) @@ -281,10 +281,11 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &o uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &assetsEvalCode, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey) { - std::vector vopretAssets; //, vopretAssetsStripped; + vscript_t vopretAssets; //, vopretAssetsStripped; uint8_t *script, funcId = 0, assetsFuncId = 0, dummyEvalCode, dummyAssetFuncId; uint256 dummyTokenid; std::vector voutPubkeysDummy; + std::vector> oprets; tokenid = zeroid; assetid2 = zeroid; @@ -293,7 +294,9 @@ uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &assetsEvalCo assetsFuncId = 0; // First - decode token opret: - funcId = DecodeTokenOpRet(scriptPubKey, dummyEvalCode, tokenid, voutPubkeysDummy, vopretAssets); + funcId = DecodeTokenOpRet(scriptPubKey, dummyEvalCode, tokenid, voutPubkeysDummy, oprets); + GetOpretBlob(oprets, OPRETID_ASSETSDATA, vopretAssets); + LOGSTREAM((char *)"ccassets", CCLOG_DEBUG2, stream << "DecodeAssetTokenOpRet() from DecodeTokenOpRet returned funcId=" << (int)funcId << std::endl); if (funcId == 0 || vopretAssets.size() < 2) { diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 14be084b4..dfe04fcb2 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -353,9 +353,9 @@ std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, in mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); std::vector voutTokenPubkeys; // should be empty - no token vouts - return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, + return FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeTokenOpRet(assetid, voutTokenPubkeys, // TODO: actually this tx is not 'tokens', maybe it is better not to have token opret here but only asset opret. - EncodeAssetOpRet('b', zeroid, pricetotal, Mypubkey())))); // But still such token opret should not make problems because no token eval in these vouts + std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('b', zeroid, pricetotal, Mypubkey())))); // But still such token opret should not make problems because no token eval in these vouts } CCerror = strprintf("no coins found to make buy offer"); return(""); @@ -419,7 +419,7 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p return FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeTokenOpRet(assetid, voutTokenPubkeys, - EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey()))); + std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey())))); } else { fprintf(stderr, "need some tokens to place ask\n"); @@ -540,7 +540,7 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeTokenOpRet(assetid, voutTokenPubkeys, - EncodeAssetOpRet('o', zeroid, 0, Mypubkey())))); + std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('o', zeroid, 0, Mypubkey()))))); } } return(""); @@ -608,7 +608,7 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeTokenOpRet(assetid, voutTokenPubkeys, - EncodeAssetOpRet('x', zeroid, 0, Mypubkey())))); + std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('x', zeroid, 0, Mypubkey()))))); } } return(""); @@ -695,7 +695,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeTokenOpRet(assetid, voutTokenPubkeys, - EncodeAssetOpRet('B', zeroid, remaining_required, origpubkey)))); + std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('B', zeroid, remaining_required, origpubkey))))); } else return("dont have any assets to fill bid"); } } @@ -820,7 +820,7 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeTokenOpRet(assetid, voutTokenPubkeys, - EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid2, remaining_nValue, origpubkey)))); + std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid2, remaining_nValue, origpubkey))))); } else { CCerror = strprintf("filltx not enough utxos"); fprintf(stderr,"%s\n", CCerror.c_str()); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index ca51506e8..f5877c711 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -67,12 +67,29 @@ one other technical note is that komodod has the insight-explorer extensions bui #include "../komodo_cJSON.h" -// opret data block ids: - enum { - OPRETID_NONFUNGIBLEDATA = 0x11 - // TODO: OPRETID_ASSETSDATA = 0x12 +// token opret additional data block ids: + enum opretid : uint8_t { + // cc contracts data: + OPRETID_NONFUNGIBLEDATA = 0x11, + OPRETID_ASSETSDATA = 0x12, + OPRETID_GATEWAYSDATA = 0x13, + OPRETID_CHANNELSDATA = 0x14, + OPRETID_HEIRDATA = 0x15, + OPRETID_ROGUEGAMEDATA = 0x16, + + // non cc contract data: + OPRETID_FIRSTNONCCDATA = 0x80, + OPRETID_BURNDATA = 0x80, + OPRETID_IMPORTDATA = 0x81 }; + // find opret blob by opretid + inline bool GetOpretBlob(const std::vector>> &oprets, uint8_t id, std::vector &vopret) { + vopret.clear(); + for(auto p : oprets) if (p.first == id) { vopret = p.second; return true; } + return false; + } + struct CC_utxo { uint256 txid; @@ -129,6 +146,8 @@ struct oracleprice_info int32_t height; }; +typedef std::vector vscript_t; + #ifdef ENABLE_WALLET extern CWallet* pwalletMain; #endif @@ -151,7 +170,7 @@ static int32_t ignorevin; bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock); int32_t is_hexstr(char *str,int32_t n); bool myAddtomempool(CTransaction &tx, CValidationState *pstate = NULL, bool fSkipExpiry = false); -int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag); +int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag,int32_t lockflag); bool myIsutxo_spentinmempool(uint256 &spenttxid,int32_t &spentvini,uint256 txid,int32_t vout); bool mytxid_inmempool(uint256 txid); int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout); @@ -172,18 +191,23 @@ uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk); //int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs); int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); -int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs, std::vector &vopretNonfungible); +int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs, vscript_t &vopretNonfungible); int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, int32_t v, uint256 reftokenid); bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); -CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, std::vector vopretNonfungible); -CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload); //old version -CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, CScript payload); +CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, vscript_t vopretNonfungible); +CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, std::vector> oprets); +CScript EncodeTokenImportOpRet(std::vector origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector> oprets); +CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, std::pair opretWithId); +CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, std::vector> oprets); +int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk); uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); -uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, std::vector &vopretNonfungible); -uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector &voutPubkeys, std::vector &vopretExtra); -void GetNonfungibleData(uint256 tokenid, std::vector &vopretNonfungible); +uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, std::vector> &oprets); +uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector> &oprets); +uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector &voutPubkeys, std::vector> &oprets); +void GetNonfungibleData(uint256 tokenid, vscript_t &vopretNonfungible); +bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector &vinPubkeys); uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector &data); int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen); @@ -227,7 +251,7 @@ uint256 revuint256(uint256 txid); bool pubkey2addr(char *destaddr,uint8_t *pubkey33); char *uint256_str(char *dest,uint256 txid); char *pubkey33_str(char *dest,uint8_t *pubkey33); -uint256 Parseuint256(char *hexstr); +uint256 Parseuint256(const char *hexstr); CPubKey pubkey2pk(std::vector pubkey); int64_t CCfullsupply(uint256 tokenid); int64_t CCtoken_balance(char *destaddr,uint256 tokenid); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index d5fffdf5b..a81a69b1f 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -34,197 +34,13 @@ Yes, this is quite confusing... - In ValudateTokenRemainder the naming convention is nValue is the coin/token with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or tokens, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits. + In ValidateTokenRemainder the naming convention is nValue is the coin/token with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or tokens, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits. We assume that the effective unit cost in the orderbook is valid and that that amount was paid and also that any remainder will be close enough in effective unit cost to not matter. At the edge cases, this will probably be not true and maybe some orders wont be practically fillable when reduced to fractional state. However, the original pubkey that created the offer can always reclaim it. ------------------------------ */ -// NOTE: this inital tx won't be used by other contract -// for tokens to be used there should be at least one 't' tx with other contract's custom opret -CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, std::vector vopretNonfungible ) -{ - CScript opret; - uint8_t evalcode = EVAL_TOKENS; - funcid = 'c'; // override the param - - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description; \ - if (!vopretNonfungible.empty()) { \ - ss << (uint8_t)OPRETID_NONFUNGIBLEDATA; \ - ss << vopretNonfungible; \ - }); - return(opret); -} - - -CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, CScript payload) -{ - CScript opret; - uint8_t tokenFuncId = 't'; - uint8_t evalCodeInOpret = EVAL_TOKENS; - - tokenid = revuint256(tokenid); - - uint8_t ccType = 0; - if (voutPubkeys.size() >= 0 && voutPubkeys.size() <= 2) - ccType = voutPubkeys.size(); - else { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "EncodeTokenOpRet voutPubkeys.size()=" << voutPubkeys.size() << " not supported" << std::endl); - } - - std::vector vpayload; - GetOpReturnData(payload, vpayload); - - opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ - if (ccType >= 1) ss << voutPubkeys[0]; \ - if (ccType == 2) ss << voutPubkeys[1]; \ - if (vpayload.size() > 0) ss << vpayload); - - // bad opret cases (retries to attach payload without re-serialization): - - // "error 64: scriptpubkey": - // if (payload.size() > 0) - // opret += payload; - - // error 64: scriptpubkey: - // CScript opretPayloadNoOpcode(vpayload); - // return opret + opretPayloadNoOpcode; - - // error sig_aborted: - // opret.resize(opret.size() + vpayload.size()); - // CScript::iterator it = opret.begin() + opret.size(); - // for (int i = 0; i < vpayload.size(); i++, it++) - // *it = vpayload[i]; - - return opret; -} - -// overload for compatibility -CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload) -{ - return EncodeTokenOpRet(tokenid, voutPubkeys, payload); -} - -// overload for fungible: -uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description) { - std::vector vopretNonfungibleDummy; - return DecodeTokenCreateOpRet(scriptPubKey, origpubkey, name, description, vopretNonfungibleDummy); -} - -uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description, std::vector &vopretNonfungible) -{ - std::vector vopret; uint8_t dummyEvalcode, funcid, *script, fieldId = 0; - - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - - if ( script != 0 && vopret.size() > 2 && script[0] == EVAL_TOKENS && script[1] == 'c' ) - { - if (E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description; \ - // we suppose in 'c' opret it might be only non-fungible payload and not any assets/heir/etc payloads - if (!ss.eof()) { \ - ss >> fieldId; \ - if( fieldId == OPRETID_NONFUNGIBLEDATA ) \ - ss >> vopretNonfungible; \ - })) - return(funcid); - } - return (uint8_t)0; -} - -// overload for compatibility allows only usual fungible tokens: -// warning: it makes vopret marshalling to CScript because this is what caller would expect -/*uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &voutPubkeys, std::vector &vopretExtra) { - std::vector vopret1, vopret2; - uint8_t funcId = DecodeTokenOpRet(scriptPubKey, evalCode, tokenid, voutPubkeys, vopret1, vopret2); - - CScript opretExtra; - vopretExtra.clear(); - - // make marshalling for compatibility - // callers of this func expect length of full array at the beginning (and they will make 'vopretStripped' from vopretExtra) - if (vopret2.empty()) - opretExtra << OP_RETURN << E_MARSHAL(ss << vopret1); // if first opret (or no oprets) - else - opretExtra << OP_RETURN << E_MARSHAL(ss << vopret2); // if both oprets present, return assets/heir/gateways/... opret (dump non-fungible opret) - - GetOpReturnData(opretExtra, vopretExtra); - return funcId; -} */ - -// decodes token opret: -// for 't' returns all data from opret, vopretExtra contains other contract's data (currently only assets'). -// for 'c' returns only funcid. NOTE: nonfungible data is not returned -uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector &voutPubkeys, std::vector &vopretExtra) -{ - std::vector vopret, extra, dummyPubkey, vnonfungibleDummy; - uint8_t funcId=0, *script, dummyEvalCode, dummyFuncId, ccType, fieldId = 0; - std::string dummyName; std::string dummyDescription; - CPubKey voutPubkey1, voutPubkey2; - - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - tokenid = zeroid; - vopretExtra.clear(); - - if (script != NULL && vopret.size() > 2) - { - // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set! - bool isEof = true; - - evalCodeTokens = script[0]; - if (evalCodeTokens != EVAL_TOKENS) - return (uint8_t)0; - - funcId = script[1]; - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "DecodeTokenOpRet decoded funcId=" << (char)(funcId?funcId:' ') << std::endl); - - switch( funcId ) - { - case 'c': - return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, vnonfungibleDummy); - //break; - case 't': - //not used yet: case 'l': - // NOTE: 'E_UNMARSHAL result==false' means 'parse error' OR 'not eof state'. Consequently, 'result==false' but 'isEof==true' means just 'parse error' - if (E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> tokenid; ss >> ccType; \ - if (ccType >= 1) ss >> voutPubkey1; \ - if (ccType == 2) ss >> voutPubkey2; \ - isEof = ss.eof(); \ - if (!isEof) ss >> vopretExtra; \ - // if something else remains -> bad format - isEof = ss.eof()) || !isEof) - { - - if (!(ccType >= 0 && ccType <= 2)) { //incorrect ccType - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() incorrect ccType=" << (int)ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl); - return (uint8_t)0; - } - - // add verification pubkeys: - voutPubkeys.clear(); - if (voutPubkey1.IsValid()) - voutPubkeys.push_back(voutPubkey1); - if (voutPubkey2.IsValid()) - voutPubkeys.push_back(voutPubkey2); - - tokenid = revuint256(tokenid); - return(funcId); - } - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() bad opret format, isEof=" << isEof << " ccType=" << ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl); - return (uint8_t)0; - - default: - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() illegal funcid=" << (int)funcId << std::endl); - return (uint8_t)0; - } - } - else { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() empty opret, could not parse" << std::endl); - } - return (uint8_t)0; -} // tx validation bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn) @@ -233,7 +49,8 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & CTxDestination address; CTransaction vinTx, createTx; uint256 hashBlock, tokenid, tokenid2; int32_t i, starti, numvins, numvouts, preventCCvins, preventCCvouts; int64_t remaining_price, nValue, tokenoshis, outputs, inputs, tmpprice, totalunits, ignore; - std::vector vopretExtra, tmporigpubkey, ignorepubkey; + std::vector> oprets; + vscript_t /*vopretExtra,*/ tmporigpubkey, ignorepubkey; uint8_t funcid, evalCodeInOpret; char destaddr[64], origaddr[64], CCaddr[64]; std::vector voutTokenPubkeys, vinTokenPubkeys; @@ -250,7 +67,7 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & if (numvouts < 1) return eval->Invalid("no vouts"); - if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, vopretExtra)) == 0) + if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets)) == 0) return eval->Invalid("TokenValidate: invalid opreturn payload"); LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokensValidate funcId=" << (char)(funcid?funcid:' ') << " evalcode=" << std::hex << (int)cp->evalcode << std::endl); @@ -272,11 +89,11 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & } // validate spending from token cc addr: allowed only for burned non-fungible tokens: - if (ExtractTokensVinPubkeys(tx, vinTokenPubkeys) && std::find(vinTokenPubkeys.begin(), vinTokenPubkeys.end(), GetUnspendable(cp, NULL)) != vinTokenPubkeys.end()) { + if (ExtractTokensCCVinPubkeys(tx, vinTokenPubkeys) && std::find(vinTokenPubkeys.begin(), vinTokenPubkeys.end(), GetUnspendable(cp, NULL)) != vinTokenPubkeys.end()) { // validate spending from token unspendable cc addr: int64_t burnedAmount = HasBurnedTokensvouts(cp, eval, tx, tokenid); if (burnedAmount > 0) { - std::vector vopretNonfungible; + vscript_t vopretNonfungible; GetNonfungibleData(tokenid, vopretNonfungible); if( vopretNonfungible.empty() ) return eval->Invalid("spending cc marker not supported for fungible tokens"); @@ -331,13 +148,14 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & // helper funcs: // extract cc token vins' pubkeys: -bool ExtractTokensVinPubkeys(CTransaction tx, std::vector &vinPubkeys) { +bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector &vinPubkeys) { bool found = false; CPubKey pubkey; struct CCcontract_info *cpTokens, tokensC; cpTokens = CCinit(&tokensC, EVAL_TOKENS); + vinPubkeys.clear(); for (int32_t i = 0; i < tx.vin.size(); i++) { @@ -384,7 +202,7 @@ uint8_t ValidateTokenOpret(CTransaction tx, uint256 tokenid) { uint8_t funcid; uint8_t dummyEvalCode; std::vector voutPubkeysDummy; - std::vector vopretExtraDummy; + std::vector> opretsDummy; // this is just for log messages indentation fur debugging recursive calls: std::string indentStr = std::string().append(tokenValIndentSize, '.'); @@ -392,7 +210,7 @@ uint8_t ValidateTokenOpret(CTransaction tx, uint256 tokenid) { if (tx.vout.size() == 0) return (uint8_t)0; - if ((funcid = DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenidOpret, voutPubkeysDummy, vopretExtraDummy)) == 0) + if ((funcid = DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenidOpret, voutPubkeysDummy, opretsDummy)) == 0) { LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "ValidateTokenOpret() DecodeTokenOpret could not parse opret for txid=" << tx.GetHash().GetHex() << std::endl); return (uint8_t)0; @@ -400,13 +218,23 @@ uint8_t ValidateTokenOpret(CTransaction tx, uint256 tokenid) { else if (funcid == 'c') { if (tokenid != zeroid && tokenid == tx.GetHash()) { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " returning true" << std::endl); + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() this is tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " returning true" << std::endl); return funcid; } else { LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not my tokenbase txid=" << tx.GetHash().GetHex() << std::endl); } } + else if (funcid == 'i') + { + if (tokenid != zeroid && tokenid == tx.GetHash()) { + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() this is import 'i' tx, txid=" << tx.GetHash().GetHex() << " returning true" << std::endl); + return funcid; + } + else { + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not my import txid=" << tx.GetHash().GetHex() << std::endl); + } + } else if (funcid == 't') { //std::cerr << indentStr << "ValidateTokenOpret() tokenid=" << tokenid.GetHex() << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl; @@ -425,17 +253,31 @@ uint8_t ValidateTokenOpret(CTransaction tx, uint256 tokenid) { } // remove token->unspendablePk (it is only for marker usage) -std::vector FilterOutTokensUnspendablePk(std::vector sourcePubkeys) { +void FilterOutTokensUnspendablePk(const std::vector &sourcePubkeys, std::vector &destPubkeys) { struct CCcontract_info *cpTokens, tokensC; cpTokens = CCinit(&tokensC, EVAL_TOKENS); CPubKey tokensUnspendablePk = GetUnspendable(cpTokens, NULL); - std::vector destPubkeys; + destPubkeys.clear(); for (auto pk : sourcePubkeys) if (pk != tokensUnspendablePk) destPubkeys.push_back(pk); - return destPubkeys; +} + +void FilterOutNonCCOprets(const std::vector> &oprets, vscript_t &vopret) { + + vopret.clear(); + + if (oprets.size() > 2) + LOGSTREAM("cctokens", CCLOG_INFO, stream << "FilterOutNonCCOprets() warning!! oprets.size > 2 currently not supported" << oprets.size() << std::endl); + + for (auto o : oprets) { + if (o.first < OPRETID_FIRSTNONCCDATA) { // skip burn, import, etc opret data + vopret = o.second; // return first contract opret (more than 1 is not supported yet) + break; + } + } } // Checks if the vout is a really Tokens CC vout @@ -488,7 +330,8 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true uint8_t dummyEvalCode; uint256 tokenIdOpret; std::vector voutPubkeys, voutPubkeysInOpret; - std::vector vopretExtra, vopretNonfungible; + vscript_t vopretExtra, vopretNonfungible; + std::vector> oprets; uint8_t evalCode = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim uint8_t evalCode2 = 0; // will be checked if zero or not @@ -496,12 +339,16 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true // test vouts for possible token use-cases: std::vector> testVouts; - DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenIdOpret, voutPubkeysInOpret, vopretExtra); + DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenIdOpret, voutPubkeysInOpret, oprets); + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "IsTokensvout() oprets.size()=" << oprets.size() << std::endl); + + // get assets/channels/gateways token data: + FilterOutNonCCOprets(oprets, vopretExtra); // NOTE: only 1 additional evalcode in token opret is currently supported LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "IsTokensvout() vopretExtra=" << HexStr(vopretExtra) << std::endl); + // get non-fungible data GetNonfungibleData(reftokenid, vopretNonfungible); - - voutPubkeys = FilterOutTokensUnspendablePk(voutPubkeysInOpret); // cannot send tokens to token unspendable cc addr (only marker is allowed there) + FilterOutTokensUnspendablePk(voutPubkeysInOpret, voutPubkeys); // cannot send tokens to token unspendable cc addr (only marker is allowed there) // NOTE: evalcode order in vouts is important: // non-fungible-eval -> EVAL_TOKENS -> assets-eval @@ -512,7 +359,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true evalCode2 = vopretExtra.begin()[0]; if (evalCode == EVAL_TOKENS && evalCode2 != 0) { - evalCode = evalCode2; + evalCode = evalCode2; // for using MakeTokensCC1vout(evalcode,...) instead of MakeCC1vout(EVAL_TOKENS, evalcode...) evalCode2 = 0; } @@ -562,8 +409,8 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true // maybe it is single-eval or dual/three-eval token change? std::vector vinPubkeys, vinPubkeysUnfiltered; - ExtractTokensVinPubkeys(tx, vinPubkeysUnfiltered); - vinPubkeys = FilterOutTokensUnspendablePk(vinPubkeysUnfiltered); // cannot send tokens to token unspendable cc addr (only marker is allowed there) + ExtractTokensCCVinPubkeys(tx, vinPubkeysUnfiltered); + FilterOutTokensUnspendablePk(vinPubkeysUnfiltered, vinPubkeys); // cannot send tokens to token unspendable cc addr (only marker is allowed there) for(std::vector::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) { testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it), std::string("single-eval cc1 self vin pk"))); @@ -577,11 +424,11 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true } else { CPubKey origPubkey; - std::vector vorigPubkey; + vscript_t vorigPubkey; std::string dummyName, dummyDescription; - std::vector vopret1; + std::vector> oprets; - if (DecodeTokenCreateOpRet(tx.vout.back().scriptPubKey, vorigPubkey, dummyName, dummyDescription, vopret1) == 0) { + if (DecodeTokenCreateOpRet(tx.vout.back().scriptPubKey, vorigPubkey, dummyName, dummyDescription, oprets) == 0) { LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() could not decode create opret" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); return 0; } @@ -689,7 +536,7 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cp, int64_t &inpu // get non-fungible data from 'tokenbase' tx (the data might be empty) -void GetNonfungibleData(uint256 tokenid, std::vector &vopretNonfungible) +void GetNonfungibleData(uint256 tokenid, vscript_t &vopretNonfungible) { CTransaction tokenbasetx; uint256 hashBlock; @@ -704,22 +551,24 @@ void GetNonfungibleData(uint256 tokenid, std::vector &vopretNonfungible if (tokenbasetx.vout.size() > 0) { std::vector origpubkey; std::string name, description; - std::vector vopretExtra; - if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, origpubkey, name, description, vopretExtra) == 'c') - vopretNonfungible = vopretExtra; + std::vector> oprets; + + if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, origpubkey, name, description, oprets) == 'c') { + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); + } } } // overload, adds inputs from token cc addr int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs) { - std::vector vopretNonfungibleDummy; + vscript_t vopretNonfungibleDummy; return AddTokenCCInputs(cp, mtx, pk, tokenid, total, maxinputs, vopretNonfungibleDummy); } // adds inputs from token cc addr and returns non-fungible opret payload if present // also sets evalcode in cp, if needed -int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs, std::vector &vopretNonfungible) +int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs, vscript_t &vopretNonfungible) { char tokenaddr[64], destaddr[64]; int64_t threshold, nValue, price, totalinputs = 0; @@ -737,8 +586,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "AddTokenCCInputs() no utxos for token dual/three eval addr=" << tokenaddr << " evalcode=" << (int)cp->evalcode << " additionalTokensEvalcode2=" << (int)cp->additionalTokensEvalcode2 << std::endl); } - threshold = total / (maxinputs != 0 ? maxinputs : 64); // TODO: maxinputs really could not be over 64? what if i want to calc total balance for all available uxtos? - // maybe it is better to add all uxtos if maxinputs == 0 + threshold = total / (maxinputs != 0 ? maxinputs : CC_MAXVINS); for (std::vector >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { @@ -771,7 +619,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C { //for non-fungible tokens check payload: if (!vopretNonfungible.empty()) { - std::vector vopret; + vscript_t vopret; // check if it is non-fungible token: GetNonfungibleData(tokenid, vopret); @@ -807,7 +655,8 @@ int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTran uint8_t dummyEvalCode; uint256 tokenIdOpret; std::vector voutPubkeys, voutPubkeysDummy; - std::vector vopretExtra, vopretNonfungible; + std::vector> oprets; + vscript_t vopretExtra, vopretNonfungible; uint8_t evalCode = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim uint8_t evalCode2 = 0; // will be checked if zero or not @@ -823,11 +672,14 @@ int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTran } - if (DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenIdOpret, voutPubkeysDummy, vopretExtra) == 0) { + if (DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenIdOpret, voutPubkeysDummy, oprets) == 0) { LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "HasBurnedTokensvouts() cannot parse opret DecodeTokenOpRet returned 0, txid=" << tx.GetHash().GetHex() << std::endl); return 0; } + // get assets/channels/gateways token data: + FilterOutNonCCOprets(oprets, vopretExtra); // NOTE: only 1 additional evalcode in token opret is currently supported + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "HasBurnedTokensvouts() vopretExtra=" << HexStr(vopretExtra) << std::endl); GetNonfungibleData(reftokenid, vopretNonfungible); @@ -874,18 +726,40 @@ int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTran return burnedAmount; } -std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, std::string description, std::vector nonfungibleData) +CPubKey GetTokenOriginatorPubKey(CScript scriptPubKey) { + + uint8_t funcId, evalCode; + uint256 tokenid; + std::vector voutTokenPubkeys; + std::vector> oprets; + + if ((funcId = DecodeTokenOpRet(scriptPubKey, evalCode, tokenid, voutTokenPubkeys, oprets)) != 0) { + CTransaction tokenbasetx; + uint256 hashBlock; + + if (myGetTransaction(tokenid, tokenbasetx, hashBlock) && tokenbasetx.vout.size() > 0) { + vscript_t vorigpubkey; + std::string name, desc; + if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, vorigpubkey, name, desc) != 0) + return pubkey2pk(vorigpubkey); + } + } + return CPubKey(); //return invalid pubkey +} + + +std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, std::string description, vscript_t nonfungibleData) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CPubKey mypk; struct CCcontract_info *cp, C; - if (tokensupply < 0) - { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() negative tokensupply=" << tokensupply << std::endl); + if (tokensupply < 0) { + CCerror = "negative tokensupply"; + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() =" << CCerror << "=" << tokensupply << std::endl); return std::string(""); } if (!nonfungibleData.empty() && tokensupply != 1) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() for non-fungible tokens tokensupply should be equal to 1" << std::endl); CCerror = "for non-fungible tokens tokensupply should be equal to 1"; + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() " << CCerror << std::endl); return std::string(""); } @@ -893,8 +767,8 @@ std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, st cp = CCinit(&C, EVAL_TOKENS); if (name.size() > 32 || description.size() > 4096) // this is also checked on rpc level { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "name of=" << name.size() << " or description of=" << description.size() << " is too big" << std::endl); - CCerror = "name should be < 32, description should be < 4096"; + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "name len=" << name.size() << " or description len=" << description.size() << " is too big" << std::endl); + CCerror = "name should be <= 32, description should be <= 4096"; return(""); } if (txfee == 0) @@ -916,21 +790,22 @@ std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, st return(FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeTokenCreateOpRet('c', Mypubkey(), name, description, nonfungibleData))); } - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "cant find normal inputs" << std::endl); CCerror = "cant find normal inputs"; + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() " << CCerror << std::endl); return std::string(""); } // transfer tokens to another pubkey // param additionalEvalCode allows transfer of dual-eval non-fungible tokens -std::string TokenTransfer(int64_t txfee, uint256 tokenid, std::vector destpubkey, int64_t total) +std::string TokenTransfer(int64_t txfee, uint256 tokenid, vscript_t destpubkey, int64_t total) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CPubKey mypk; uint64_t mask; int64_t CCchange = 0, inputs = 0; struct CCcontract_info *cp, C; - std::vector vopretNonfungible; + vscript_t vopretNonfungible, vopretEmpty; if (total < 0) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "negative total=" << total << std::endl); + CCerror = strprintf("negative total"); + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << CCerror << "=" << total << std::endl); return(""); } @@ -946,8 +821,8 @@ std::string TokenTransfer(int64_t txfee, uint256 tokenid, std::vector d if ((inputs = AddTokenCCInputs(cp, mtx, mypk, tokenid, total, 60, vopretNonfungible)) > 0) // NOTE: AddTokenCCInputs might set cp->additionalEvalCode which is used in FinalizeCCtx! { if (inputs < total) { //added dimxy - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer(): insufficient token funds" << std::endl); CCerror = strprintf("insufficient token inputs"); + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << std::endl); return std::string(""); } @@ -964,17 +839,17 @@ std::string TokenTransfer(int64_t txfee, uint256 tokenid, std::vector d std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(pubkey2pk(destpubkey)); // dest pubkey for validating vout - return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet(tokenid, voutTokenPubkeys, CScript()))); + return FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet(tokenid, voutTokenPubkeys, std::make_pair((uint8_t)0, vopretEmpty))); } else { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "not enough CC token inputs for amount=" << total << std::endl); CCerror = strprintf("no token inputs"); + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << total << std::endl); } //} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size()); } else { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "not enough normal inputs for txfee" << std::endl); - CCerror = strprintf("insufficient normal inputs"); + CCerror = strprintf("insufficient normal inputs for tx fee"); + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << std::endl); } return(""); } @@ -1007,7 +882,8 @@ UniValue TokenInfo(uint256 tokenid) uint256 hashBlock; CTransaction vintx; std::vector origpubkey; - std::vector vopretNonfungible; + std::vector> oprets; + vscript_t vopretNonfungible; std::string name, description; struct CCcontract_info *cpTokens, tokensCCinfo; @@ -1020,7 +896,7 @@ UniValue TokenInfo(uint256 tokenid) result.push_back(Pair("error", "cant find tokenid")); return(result); } - if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description, vopretNonfungible) == 0) + if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description, oprets) != 'c') { LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenInfo() passed tokenid isnt token creation txid" << std::endl); result.push_back(Pair("result", "error")); @@ -1038,6 +914,8 @@ UniValue TokenInfo(uint256 tokenid) supply += output; result.push_back(Pair("supply", supply)); result.push_back(Pair("description", description)); + + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); if( !vopretNonfungible.empty() ) result.push_back(Pair("data", HexStr(vopretNonfungible))); diff --git a/src/cc/CCtokens.h b/src/cc/CCtokens.h index 791107648..f63c563a9 100644 --- a/src/cc/CCtokens.h +++ b/src/cc/CCtokens.h @@ -30,8 +30,8 @@ bool TokensValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid); std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description, std::vector nonfungibleData); std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector destpubkey, int64_t total); -bool ExtractTokensVinPubkeys(CTransaction tx, std::vector &vinPubkeys); int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, uint256 reftokenid); +CPubKey GetTokenOriginatorPubKey(CScript scriptPubKey); int64_t GetTokenBalance(CPubKey pk, uint256 tokenid); UniValue TokenInfo(uint256 tokenid); diff --git a/src/cc/CCtokensOpRet.cpp b/src/cc/CCtokensOpRet.cpp new file mode 100644 index 000000000..4c6dc4b6d --- /dev/null +++ b/src/cc/CCtokensOpRet.cpp @@ -0,0 +1,296 @@ +// encode decode tokens opret +// (moved to a separate file to enable linking lib common.so with importcoin.cpp) + +#include "CCtokens.h" + +#ifndef IS_CHARINSTR +#define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos) +#endif + +// NOTE: this inital tx won't be used by other contract +// for tokens to be used there should be at least one 't' tx with other contract's custom opret +CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, vscript_t vopretNonfungible) +{ + /* CScript opret; + uint8_t evalcode = EVAL_TOKENS; + funcid = 'c'; // override the param + + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description; \ + if (!vopretNonfungible.empty()) { + ss << (uint8_t)OPRETID_NONFUNGIBLEDATA; + ss << vopretNonfungible; + }); */ + + std::vector> oprets; + + if(!vopretNonfungible.empty()) + oprets.push_back(std::make_pair(OPRETID_NONFUNGIBLEDATA, vopretNonfungible)); + return EncodeTokenCreateOpRet(funcid, origpubkey, name, description, oprets); +} + +CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, std::vector> oprets) +{ + CScript opret; + uint8_t evalcode = EVAL_TOKENS; + funcid = 'c'; // override the param + + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description; + for (auto o : oprets) { + if (o.first != 0) { + ss << (uint8_t)o.first; + ss << o.second; + } + }); + return(opret); +} + +// opret 'i' for imported tokens +CScript EncodeTokenImportOpRet(std::vector origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector> oprets) +{ + CScript opret; + uint8_t evalcode = EVAL_TOKENS; + uint8_t funcid = 'i'; + + srctokenid = revuint256(srctokenid); // do not forget this + + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description << srctokenid; + for (auto o : oprets) { + if (o.first != 0) { + ss << (uint8_t)o.first; + ss << o.second; + } + }); + return(opret); +} + + + +CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, std::pair opretWithId) +{ + std::vector> oprets; + oprets.push_back(opretWithId); + return EncodeTokenOpRet(tokenid, voutPubkeys, oprets); +} + +CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, std::vector> oprets) +{ + CScript opret; + uint8_t tokenFuncId = 't'; + uint8_t evalCodeInOpret = EVAL_TOKENS; + + tokenid = revuint256(tokenid); + + uint8_t ccType = 0; + if (voutPubkeys.size() >= 0 && voutPubkeys.size() <= 2) + ccType = voutPubkeys.size(); + else { + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "EncodeTokenOpRet voutPubkeys.size()=" << voutPubkeys.size() << " not supported" << std::endl); + } + + //vopret_t vpayload; + //GetOpReturnData(payload, vpayload); + + opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; + if (ccType >= 1) ss << voutPubkeys[0]; + if (ccType == 2) ss << voutPubkeys[1]; + for (auto o : oprets) { + if (o.first != 0) { + ss << (uint8_t)o.first; + ss << o.second; + } + }); + + // bad opret cases (tries to attach payload without re-serialization): + + // error "64: scriptpubkey": + // if (payload.size() > 0) + // opret += payload; + + // error "64: scriptpubkey": + // CScript opretPayloadNoOpcode(vpayload); + // return opret + opretPayloadNoOpcode; + + // error "sig_aborted": + // opret.resize(opret.size() + vpayload.size()); + // CScript::iterator it = opret.begin() + opret.size(); + // for (int i = 0; i < vpayload.size(); i++, it++) + // *it = vpayload[i]; + + return opret; +} + +// overload for compatibility +//CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload) +//{ +// return EncodeTokenOpRet(tokenid, voutPubkeys, payload); +//} + +// overload for fungible tokens (no additional data in opret): +uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description) { + //vopret_t vopretNonfungibleDummy; + std::vector> opretsDummy; + return DecodeTokenCreateOpRet(scriptPubKey, origpubkey, name, description, opretsDummy); +} + +uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, std::vector> &oprets) +{ + vscript_t vopret, vblob; + uint8_t dummyEvalcode, funcid, opretId = 0; + + GetOpReturnData(scriptPubKey, vopret); + oprets.clear(); + + if (vopret.size() > 2 && vopret.begin()[0] == EVAL_TOKENS && vopret.begin()[1] == 'c') + { + if (E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description; + while (!ss.eof()) { + ss >> opretId; + if (!ss.eof()) { + ss >> vblob; + oprets.push_back(std::make_pair(opretId, vblob)); + } + })) + { + return(funcid); + } + } + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenCreateOpRet() incorrect token create opret" << std::endl); + return (uint8_t)0; +} + +// for imported tokens +uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector> &oprets) +{ + vscript_t vopret, vblob; + uint8_t dummyEvalcode, funcid, opretId = 0; + + GetOpReturnData(scriptPubKey, vopret); + oprets.clear(); + + if (vopret.size() > 2 && vopret.begin()[0] == EVAL_TOKENS && vopret.begin()[1] == 'i') + { + if (E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description; ss >> srctokenid; + while (!ss.eof()) { + ss >> opretId; + if (!ss.eof()) { + ss >> vblob; + oprets.push_back(std::make_pair(opretId, vblob)); + } + })) + { + srctokenid = revuint256(srctokenid); // do not forget this + return(funcid); + } + } + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenImportOpRet() incorrect token import opret" << std::endl); + return (uint8_t)0; +} + +// decodes token opret: +// for 't' returns all data from opret, vopretExtra contains other contract's data (currently only assets'). +// for 'c' and 'i' returns only funcid. NOTE: nonfungible data is not returned +uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector &voutPubkeys, std::vector> &oprets) +{ + vscript_t vopret, vblob, dummyPubkey, vnonfungibleDummy; + uint8_t funcId = 0, *script, dummyEvalCode, dummyFuncId, ccType, opretId = 0; + std::string dummyName; std::string dummyDescription; + uint256 dummySrcTokenId; + CPubKey voutPubkey1, voutPubkey2; + + vscript_t voldstyledata; + bool foundOldstyle = false; + + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + tokenid = zeroid; + oprets.clear(); + + if (script != NULL && vopret.size() > 2) + { + // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set! + // bool isEof = true; + + evalCodeTokens = script[0]; + if (evalCodeTokens != EVAL_TOKENS) { + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() incorrect evalcode in tokens opret" << std::endl); + return (uint8_t)0; + } + + funcId = script[1]; + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "DecodeTokenOpRet decoded funcId=" << (char)(funcId ? funcId : ' ') << std::endl); + + switch (funcId) + { + case 'c': + return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, oprets); + case 'i': + return DecodeTokenImportOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, dummySrcTokenId, oprets); + //break; + case 't': + + // compatibility with old-style rogue or assets data (with no opretid): + // try to unmarshal old-style rogue or assets data: + foundOldstyle = E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> tokenid; ss >> ccType; + if (ccType >= 1) ss >> voutPubkey1; + if (ccType == 2) ss >> voutPubkey2; + if (!ss.eof()) { + ss >> voldstyledata; + }) && voldstyledata.size() >= 2 && + (voldstyledata.begin()[0] == 0x11 /*EVAL_ROGUE*/ && IS_CHARINSTR(voldstyledata.begin()[1], "RHQKG") || + voldstyledata.begin()[0] == EVAL_ASSETS && IS_CHARINSTR(voldstyledata.begin()[1], "sbSBxo")) ; + + if (foundOldstyle || // fix for compatibility with old style data (no opretid) + E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> tokenid; ss >> ccType; + if (ccType >= 1) ss >> voutPubkey1; + if (ccType == 2) ss >> voutPubkey2; + while (!ss.eof()) { + ss >> opretId; + if (!ss.eof()) { + ss >> vblob; + oprets.push_back(std::make_pair(opretId, vblob)); + } + })) + { + if (!(ccType >= 0 && ccType <= 2)) { //incorrect ccType + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() incorrect ccType=" << (int)ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl); + return (uint8_t)0; + } + + // add verification pubkeys: + voutPubkeys.clear(); + if (voutPubkey1.IsValid()) + voutPubkeys.push_back(voutPubkey1); + if (voutPubkey2.IsValid()) + voutPubkeys.push_back(voutPubkey2); + + tokenid = revuint256(tokenid); + + if (foundOldstyle) { //patch for old-style opret data with no opretid + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "DecodeTokenOpRet() found old-style rogue/asset data, evalcode=" << (int)voldstyledata.begin()[0] << " funcid=" << (char)voldstyledata.begin()[1] << " for tokenid=" << revuint256(tokenid).GetHex() << std::endl); + uint8_t opretIdRestored; + if (voldstyledata.begin()[0] == 0x11 /*EVAL_ROGUE*/) + opretIdRestored = OPRETID_ROGUEGAMEDATA; + else // EVAL_ASSETS + opretIdRestored = OPRETID_ASSETSDATA; + + oprets.push_back(std::make_pair(opretIdRestored, voldstyledata)); + } + + return(funcId); + } + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() bad opret format," << " ccType=" << (int)ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl); + return (uint8_t)0; + + default: + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() illegal funcid=" << (int)funcId << std::endl); + return (uint8_t)0; + } + } + else { + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() empty opret, could not parse" << std::endl); + } + return (uint8_t)0; +} + + + diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 0f7e103f9..cb3f8b1a6 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -290,6 +290,16 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran cc_free(othercond3); if ( othercond4 != 0 ) cc_free(othercond4); + if ( othercond1of2 != 0 ) + cc_free(othercond1of2); + if ( othercond1of2tokens != 0 ) + cc_free(othercond1of2tokens); + if ( mytokenscond != 0 ) + cc_free(mytokenscond); + if ( mysingletokenscond != 0 ) + cc_free(mysingletokenscond); + if ( othertokenscond != 0 ) + cc_free(othertokenscond); std::string strHex = EncodeHexTx(mtx); if ( strHex.size() > 0 ) return(strHex); @@ -347,17 +357,29 @@ int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout) return(0); } -int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag) +int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag,int32_t lockflag) { CCoins coins; + //fprintf(stderr,"CCgettxoud %s/v%d\n",txid.GetHex().c_str(),vout); if ( mempoolflag != 0 ) { - LOCK(mempool.cs); - CCoinsViewMemPool view(pcoinsTip, mempool); - if (!view.GetCoins(txid, coins)) - return(-1); - if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) != 0 ) - return(-1); + if ( lockflag != 0 ) + { + LOCK(mempool.cs); + CCoinsViewMemPool view(pcoinsTip, mempool); + if (!view.GetCoins(txid, coins)) + return(-1); + else if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) != 0 ) + return(-1); + } + else + { + CCoinsViewMemPool view(pcoinsTip, mempool); + if (!view.GetCoins(txid, coins)) + return(-1); + else if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) != 0 ) + return(-1); + } } else { @@ -399,7 +421,7 @@ int64_t CCfullsupply(uint256 tokenid) { if (DecodeTokenCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description)) { - return(tx.vout[0].nValue); + return(tx.vout[1].nValue); } } return(0); @@ -420,7 +442,8 @@ int64_t CCtoken_balance(char *coinaddr,uint256 reftokenid) { char str[65]; std::vector voutTokenPubkeys; - if ( reftokenid==txid || (DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, tokenid, voutTokenPubkeys, vopretExtra) != 0 && reftokenid == tokenid)) + std::vector> oprets; + if ( reftokenid==txid || (DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, tokenid, voutTokenPubkeys, oprets) != 0 && reftokenid == tokenid)) { sum += it->second.satoshis; } @@ -486,16 +509,18 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t * int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs) { - int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=CC_MAXVINS; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up; + int32_t abovei,belowi,ind,vout,i,n = 0; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up; #ifdef ENABLE_WALLET assert(pwalletMain != NULL); const CKeyStore& keystore = *pwalletMain; LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); - utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos)); - threshold = total/(maxinputs+1); - if ( maxinputs > maxutxos ) - maxutxos = maxinputs; + utxos = (struct CC_utxo *)calloc(CC_MAXVINS,sizeof(*utxos)); + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; + if ( maxinputs > 0 ) + threshold = total/maxinputs; + else threshold = total; sum = 0; BOOST_FOREACH(const COutput& out, vecOutputs) { @@ -530,7 +555,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3 up->vout = vout; sum += up->nValue; //fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos); - if ( n >= maxutxos || sum >= total ) + if ( n >= maxinputs || sum >= total ) break; } } @@ -579,12 +604,14 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3 int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinputs) { - int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=CC_MAXVINS; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up; + int32_t abovei,belowi,ind,vout,i,n = 0; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up; std::vector > unspentOutputs; - utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos)); - threshold = total/(maxinputs+1); - if ( maxinputs > maxutxos ) - maxutxos = maxinputs; + utxos = (struct CC_utxo *)calloc(CC_MAXVINS,sizeof(*utxos)); + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; + if ( maxinputs > 0 ) + threshold = total/maxinputs; + else threshold = total; sum = 0; Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG); SetCCunspents(unspentOutputs,coinaddr); @@ -621,7 +648,7 @@ int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinput up->vout = vout; sum += up->nValue; //fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos); - if ( n >= maxutxos || sum >= total ) + if ( n >= maxinputs || sum >= total ) break; } } diff --git a/src/cc/CCutilbits.cpp b/src/cc/CCutilbits.cpp new file mode 100644 index 000000000..d50fb971c --- /dev/null +++ b/src/cc/CCutilbits.cpp @@ -0,0 +1,105 @@ +/****************************************************************************** + * Copyright © 2014-2019 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +/* + CCutilbits.cpp has very low level functions that are universally useful for all contracts and have low dependency from other sources + */ + +#include "CCinclude.h" +#include "komodo_structs.h" + +int32_t unstringbits(char *buf,uint64_t bits) +{ + int32_t i; + for (i=0; i<8; i++,bits>>=8) + if ( (buf[i]= (char)(bits & 0xff)) == 0 ) + break; + buf[i] = 0; + return(i); +} + +uint64_t stringbits(char *str) +{ + uint64_t bits = 0; + if ( str == 0 ) + return(0); + int32_t i,n = (int32_t)strlen(str); + if ( n > 8 ) + n = 8; + for (i=n-1; i>=0; i--) + bits = (bits << 8) | (str[i] & 0xff); + //printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits); + return(bits); +} + +uint256 revuint256(uint256 txid) +{ + uint256 revtxid; int32_t i; + for (i=31; i>=0; i--) + ((uint8_t *)&revtxid)[31-i] = ((uint8_t *)&txid)[i]; + return(revtxid); +} + +char *uint256_str(char *dest,uint256 txid) +{ + int32_t i,j=0; + for (i=31; i>=0; i--) + sprintf(&dest[j++ * 2],"%02x",((uint8_t *)&txid)[i]); + dest[64] = 0; + return(dest); +} + +char *pubkey33_str(char *dest,uint8_t *pubkey33) +{ + int32_t i; + if ( pubkey33 != 0 ) + { + for (i=0; i<33; i++) + sprintf(&dest[i * 2],"%02x",pubkey33[i]); + } else dest[0] = 0; + return(dest); +} + +uint256 Parseuint256(const char *hexstr) +{ + uint256 txid; int32_t i; std::vector txidbytes(ParseHex(hexstr)); + memset(&txid,0,sizeof(txid)); + if ( strlen(hexstr) == 64 ) + { + for (i=31; i>=0; i--) + ((uint8_t *)&txid)[31-i] = ((uint8_t *)txidbytes.data())[i]; + } + return(txid); +} + +CPubKey buf2pk(uint8_t *buf33) +{ + CPubKey pk; int32_t i; uint8_t *dest; + dest = (uint8_t *)pk.begin(); + for (i=0; i<33; i++) + dest[i] = buf33[i]; + return(pk); +} + +CPubKey pubkey2pk(std::vector pubkey) +{ + CPubKey pk; int32_t i,n; uint8_t *dest,*pubkey33; + n = pubkey.size(); + dest = (uint8_t *)pk.begin(); + pubkey33 = (uint8_t *)pubkey.data(); + for (i=0; i>=8) - if ( (buf[i]= (char)(bits & 0xff)) == 0 ) - break; - buf[i] = 0; - return(i); -} - -uint64_t stringbits(char *str) -{ - uint64_t bits = 0; - if ( str == 0 ) - return(0); - int32_t i,n = (int32_t)strlen(str); - if ( n > 8 ) - n = 8; - for (i=n-1; i>=0; i--) - bits = (bits << 8) | (str[i] & 0xff); - //printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits); - return(bits); -} - -uint256 revuint256(uint256 txid) -{ - uint256 revtxid; int32_t i; - for (i=31; i>=0; i--) - ((uint8_t *)&revtxid)[31-i] = ((uint8_t *)&txid)[i]; - return(revtxid); -} - -char *uint256_str(char *dest,uint256 txid) -{ - int32_t i,j=0; - for (i=31; i>=0; i--) - sprintf(&dest[j++ * 2],"%02x",((uint8_t *)&txid)[i]); - dest[64] = 0; - return(dest); -} - -char *pubkey33_str(char *dest,uint8_t *pubkey33) -{ - int32_t i; - if ( pubkey33 != 0 ) - { - for (i=0; i<33; i++) - sprintf(&dest[i * 2],"%02x",pubkey33[i]); - } else dest[0] = 0; - return(dest); -} - -uint256 Parseuint256(char *hexstr) -{ - uint256 txid; int32_t i; std::vector txidbytes(ParseHex(hexstr)); - memset(&txid,0,sizeof(txid)); - if ( strlen(hexstr) == 64 ) - { - for (i=31; i>=0; i--) - ((uint8_t *)&txid)[31-i] = ((uint8_t *)txidbytes.data())[i]; - } - return(txid); -} - -CPubKey buf2pk(uint8_t *buf33) -{ - CPubKey pk; int32_t i; uint8_t *dest; - dest = (uint8_t *)pk.begin(); - for (i=0; i<33; i++) - dest[i] = buf33[i]; - return(pk); -} - -CPubKey pubkey2pk(std::vector pubkey) -{ - CPubKey pk; int32_t i,n; uint8_t *dest,*pubkey33; - n = pubkey.size(); - dest = (uint8_t *)pk.begin(); - pubkey33 = (uint8_t *)pubkey.data(); - for (i=0; iInvalid("vout2 doesnt go to origpubkey fillbuy"); else if ( inputs != tx.vout[2].nValue + tx.vout[4].nValue ) return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy"); + preventCCvouts ++; } else if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, inputs) == 0 ) // tokens to originator cc addr (tokens+nonfungible evals) return eval->Invalid("vout2 doesnt match inputs fillbuy"); @@ -461,7 +469,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti } // what does this do? - bool bPrevent = PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts); + bool bPrevent = PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts); // seems we do not need this call as we already checked vouts well //std::cerr << "AssetsValidate() PreventCC returned=" << bPrevent << std::endl; return (bPrevent); } diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index f7749d99f..1330c6b3e 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -33,8 +33,12 @@ #ifdef BUILD_ROGUE #define EVAL_ROGUE 17 std::string MYCCLIBNAME = (char *)"rogue"; -#else + +#elif BUILD_CUSTOMCC +#include "customcc.h" + +#else #define EVAL_SUDOKU 17 #define EVAL_MUSIG 18 #define EVAL_DILITHIUM 19 @@ -67,6 +71,8 @@ CClib_methods[] = { (char *)"rogue", (char *)"games", (char *)"", 0, 0, 'F', EVAL_ROGUE }, { (char *)"rogue", (char *)"setname", (char *)"pname", 1, 1, 'N', EVAL_ROGUE }, { (char *)"rogue", (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, 'X', EVAL_ROGUE }, +#elif BUILD_CUSTOMCC + RPC_FUNCS #else { (char *)"sudoku", (char *)"gen", (char *)"", 0, 0, 'G', EVAL_SUDOKU }, { (char *)"sudoku", (char *)"txidinfo", (char *)"txid", 1, 1, 'T', EVAL_SUDOKU }, @@ -83,10 +89,12 @@ CClib_methods[] = { (char *)"musig", (char *)"spend", (char *)"sendtxid sig scriptPubKey", 3, 3, 'y', EVAL_MUSIG }, { (char *)"dilithium", (char *)"keypair", (char *)"[hexseed]", 0, 1, 'K', EVAL_DILITHIUM }, { (char *)"dilithium", (char *)"register", (char *)"handle, [hexseed]", 1, 2, 'R', EVAL_DILITHIUM }, + { (char *)"dilithium", (char *)"handleinfo", (char *)"handle", 1, 1, 'I', EVAL_DILITHIUM }, { (char *)"dilithium", (char *)"sign", (char *)"msg [hexseed]", 1, 2, 'S', EVAL_DILITHIUM }, { (char *)"dilithium", (char *)"verify", (char *)"pubtxid msg sig", 3, 3, 'V', EVAL_DILITHIUM }, { (char *)"dilithium", (char *)"send", (char *)"handle pubtxid amount", 3, 3, 'x', EVAL_DILITHIUM }, { (char *)"dilithium", (char *)"spend", (char *)"sendtxid scriptPubKey [hexseed]", 2, 3, 'y', EVAL_DILITHIUM }, + { (char *)"dilithium", (char *)"Qsend", (char *)"mypubtxid hexseed/'mypriv' destpubtxid,amount, ...", 4, 66, 'Q', EVAL_DILITHIUM }, #endif }; @@ -129,11 +137,13 @@ UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); bool dilithium_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx); UniValue dilithium_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue dilithium_handleinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue dilithium_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue dilithium_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue dilithium_keypair(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue dilithium_sign(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue dilithium_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue dilithium_Qsend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); #endif @@ -210,6 +220,8 @@ UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr) return(result); } } +#elif BUILD_CUSTOMCC + CUSTOM_DISPATCH #else if ( cp->evalcode == EVAL_SUDOKU ) { @@ -261,7 +273,9 @@ UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr) } else if ( cp->evalcode == EVAL_DILITHIUM ) { - if ( strcmp(method,"send") == 0 ) + if ( strcmp(method,"Qsend") == 0 ) + return(dilithium_Qsend(txfee,cp,params)); + else if ( strcmp(method,"send") == 0 ) return(dilithium_send(txfee,cp,params)); else if ( strcmp(method,"spend") == 0 ) return(dilithium_spend(txfee,cp,params)); @@ -269,6 +283,8 @@ UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr) return(dilithium_keypair(txfee,cp,params)); else if ( strcmp(method,"register") == 0 ) return(dilithium_register(txfee,cp,params)); + else if ( strcmp(method,"handleinfo") == 0 ) + return(dilithium_handleinfo(txfee,cp,params)); else if ( strcmp(method,"sign") == 0 ) return(dilithium_sign(txfee,cp,params)); else if ( strcmp(method,"verify") == 0 ) @@ -402,6 +418,8 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C { #ifdef BUILD_ROGUE return(rogue_validate(cp,height,eval,tx)); +#elif BUILD_CUSTOMCC + return(custom_validate(cp,height,eval,tx)); #else if ( cp->evalcode == EVAL_SUDOKU ) return(sudoku_validate(cp,height,eval,tx)); @@ -474,7 +492,11 @@ int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); - threshold = total/(maxinputs+1); + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; + if ( maxinputs != 0 ) + threshold = total/maxinputs; + else threshold = total; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; @@ -500,6 +522,31 @@ int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK return(totalinputs); } +int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk) +{ + char coinaddr[64]; int64_t nValue,txfee = 10000; uint256 txid,hashBlock; CTransaction vintx; int32_t vout; + std::vector > unspentOutputs; + GetCCaddress(cp,coinaddr,pk); + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f vs %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN,(double)threshold/COIN); + if ( it->second.satoshis < txfee ) + continue; + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + { + if ( (nValue= IsCClibvout(cp,vintx,vout,coinaddr)) != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) + { + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + return(it->second.satoshis); + } //else fprintf(stderr,"nValue %.8f too small or already spent in mempool\n",(double)nValue/COIN); + } else fprintf(stderr,"couldnt get tx\n"); + } + return(0); +} + std::string Faucet2Fund(struct CCcontract_info *cp,uint64_t txfee,int64_t funds) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); @@ -627,6 +674,9 @@ int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len) #include "rogue/weapons.c" #include "rogue/wizard.c" +#elif BUILD_CUSTOMCC +#include "customcc.cpp" + #else #include "sudoku.cpp" #include "musig.cpp" diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index fd20314bb..504ba629a 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -92,24 +92,27 @@ int64_t IsChannelsMarkervout(struct CCcontract_info *cp,const CTransaction& tx,C CScript EncodeChannelsOpRet(uint8_t funcid,uint256 tokenid,uint256 opentxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain) { CScript opret; uint8_t evalcode = EVAL_CHANNELS; + vscript_t vopret; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << opentxid << srcpub << destpub << numpayments << payment << hashchain); + vopret = E_MARSHAL(ss << evalcode << funcid << opentxid << srcpub << destpub << numpayments << payment << hashchain); if (tokenid!=zeroid) { std::vector pks; pks.push_back(srcpub); pks.push_back(destpub); - return(EncodeTokenOpRet(tokenid,pks,opret)); + return(EncodeTokenOpRet(tokenid,pks, std::make_pair(OPRETID_CHANNELSDATA, vopret))); } + opret << OP_RETURN << vopret; return(opret); } uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey, uint256 &tokenid, uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain) { + std::vector> oprets; std::vector vopret,vOpretExtra; uint8_t *script,e,f,tokenevalcode; std::vector pubkeys; - if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,oprets)!=0 && GetOpretBlob(oprets, OPRETID_CHANNELSDATA, vOpretExtra) && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) { vopret=vOpretExtra; } diff --git a/src/cc/customcc.cpp b/src/cc/customcc.cpp new file mode 100644 index 000000000..9f58c5c8b --- /dev/null +++ b/src/cc/customcc.cpp @@ -0,0 +1,88 @@ +/* + simple stub custom cc + + Just update the functions in this file, then from ~/komodo/src/cc + + ../komodo-cli -ac_name=CUSTOM stop + ./makecustom + ../komodod -ac_name=CUSTOM -ac_cclib=custom -ac_cc=2 ... + + The above will rebuild komodod and get it running again + */ + +CScript custom_opret(uint8_t funcid,CPubKey pk) +{ + CScript opret; uint8_t evalcode = EVAL_CUSTOM; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk); + return(opret); +} + +uint8_t custom_opretdecode(CPubKey &pk,CScript scriptPubKey) +{ + std::vector vopret; uint8_t e,f; + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk) != 0 && e == EVAL_CUSTOM ) + { + return(f); + } + return(0); +} + +UniValue custom_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag) +{ + CTransaction tx; + if ( rawtx.size() > 0 ) + { + result.push_back(Pair("hex",rawtx)); + if ( DecodeHexTx(tx,rawtx) != 0 ) + { + if ( broadcastflag != 0 && myAddtomempool(tx) != 0 ) + RelayTransaction(tx); + result.push_back(Pair("txid",tx.GetHash().ToString())); + result.push_back(Pair("result","success")); + } else result.push_back(Pair("error","decode hex")); + } else result.push_back(Pair("error","couldnt finalize CCtx")); + return(result); +} + +UniValue custom_func0(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); + result.push_back(Pair("result","success")); + result.push_back(Pair("message","just an example of an information returning rpc")); + return(result); +} + +// send yourself 1 coin to your CC address using normal utxo from your -pubkey + +UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); std::string rawtx; + UniValue result(UniValue::VOBJ); CPubKey mypk; int64_t amount = COIN; int32_t broadcastflag=0; + if ( txfee == 0 ) + txfee = CUSTOM_TXFEE; + mypk = pubkey2pk(Mypubkey()); + if ( AddNormalinputs(mtx,mypk,COIN+txfee,64) >= COIN+txfee ) // add utxo to mtx + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk)); // make vout0 + // add opreturn, change is automatically added and tx is properly signed + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,custom_opret('1',mypk)); + return(custom_rawtxresult(result,rawtx,broadcastflag)); + } + return(result); +} + +bool custom_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) +{ + char expectedaddress[64]; CPubKey pk; + if ( tx.vout.size() != 2 ) // make sure the tx only has 2 outputs + return eval->Invalid("invalid number of vouts"); + else if ( custom_opretdecode(pk,tx.vout[1].scriptPubKey) != '1' ) // verify has opreturn + return eval->Invalid("invalid opreturn"); + GetCCaddress(cp,expectedaddress,pk); + if ( IsCClibvout(cp,tx,0,expectedaddress) == COIN ) // make sure amount and destination matches + return(true); + else return eval->Invalid("invalid vout0 amount"); +} + + diff --git a/src/cc/customcc.h b/src/cc/customcc.h new file mode 100644 index 000000000..436937391 --- /dev/null +++ b/src/cc/customcc.h @@ -0,0 +1,45 @@ +/* + to create a custom libcc.so: + + 1. change "func0" and "func1" to method names that fit your custom cc. Of course, you can create more functions by adding another entry to RPC_FUNCS. there is not any practical limit to the number of methods. + + 2. For each method make sure there is a UniValue function declaration and CUSTOM_DISPATCH has an if statement checking for it that calls the custom_func + + 3. write the actual custom_func0, custom_func1 and custom_validate in customcc.cpp + + 4. ./makecustom, which builds cclib.cpp with -DBUILD_CUSTOMCC and puts the libcc.so in ~/komodo/src and rebuilds komodod + + 5. launch your chain with -ac_cclib=customcc -ac_cc=2 + + */ + +std::string MYCCLIBNAME = (char *)"customcc"; + +#define EVAL_CUSTOM (EVAL_FAUCET2+1) +#define CUSTOM_TXFEE 10000 + +#define MYCCNAME "custom" + +#define RPC_FUNCS \ + { (char *)MYCCNAME, (char *)"func0", (char *)"", 1, 1, '0', EVAL_CUSTOM }, \ + { (char *)MYCCNAME, (char *)"func1", (char *)"", 0, 0, '1', EVAL_CUSTOM }, + +bool custom_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx); +UniValue custom_func0(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); + +#define CUSTOM_DISPATCH \ +if ( cp->evalcode == EVAL_CUSTOM ) \ +{ \ + if ( strcmp(method,"func0") == 0 ) \ + return(custom_func0(txfee,cp,params)); \ + else if ( strcmp(method,"func1") == 0 ) \ + return(custom_func1(txfee,cp,params)); \ + else \ + { \ + result.push_back(Pair("result","error")); \ + result.push_back(Pair("error","invalid customcc method")); \ + result.push_back(Pair("method",method)); \ + return(result); \ + } \ +} diff --git a/src/cc/dice.cpp b/src/cc/dice.cpp index 1bb44af18..ca1ad7b53 100644 --- a/src/cc/dice.cpp +++ b/src/cc/dice.cpp @@ -1052,9 +1052,11 @@ uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; if ( maxinputs > 0 ) threshold = total / maxinputs; - else threshold = total / 64; + else threshold = total; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; @@ -1213,6 +1215,9 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit } else { return(0); } + //fprintf(stderr,"numentropy tx %d: %.8f\n",n,(double)totalinputs/COIN); + entropytxs = n; + return(totalinputs); } bool DicePlanExists(CScript &fundingPubKey,uint256 &fundingtxid,struct CCcontract_info *cp,uint64_t refsbits,CPubKey dicepk,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &timeoutblocks) diff --git a/src/cc/dilithium.c b/src/cc/dilithium.c index ab8ca9ae5..7ba522f0f 100644 --- a/src/cc/dilithium.c +++ b/src/cc/dilithium.c @@ -2908,6 +2908,20 @@ int32_t main(void) this generates a really big hex, broadcast it and if all went well it will get confirmed. a dilithium spend! + to generate a seed that wont be directly derivable from an secp256k1 keypair, do: + cclib keypair 19 \"[%22rand%22]\" + + to do a Qsend (multiple dilithium inputs and outputs) + + cclib Qsend 19 \"[%22mypubtxid%22,%22%22,%22%22,0.777]\" + there can be up to 64 outputs, where each one can be a different destpubtxid or scriptPubKey. The only restriction is that scriptPubKey hex cant be 32 bytes. + + Qsend is able to spend many Qvins as long as they are for the same dilithium bigpub + secp pub33. And the outputs can be to many different Qvouts or normal vouts. This allows to keep funds totally within the dilithium system and also to transfer back to normal taddrs. Qsend currently only sends from Qfunds, though it could also use funds from normal inputs. + + Currently, to get funds from normal inputs to a dilithium, the send rpc can be used as above. So that provides a way to push funds into dilithium. The spend rpc becomes redundant with Qsend. + + To properly test this, we need to make sure that transactions Qsend can use send outputs, and Qsend outputs and a combination. Of course, it needs to be validated that funds are not lost, Qsends work properly, etc. + */ #define DILITHIUM_TXFEE 10000 @@ -2915,6 +2929,69 @@ int32_t main(void) void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen); char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len); +struct dilithium_handle +{ + UT_hash_handle hh; + uint256 destpubtxid; + char handle[32]; +} *Dilithium_handles; + +pthread_mutex_t DILITHIUM_MUTEX; + +struct dilithium_handle *dilithium_handlenew(char *handle) +{ + struct dilithium_handle *hashstr = 0; int32_t len = (int32_t)strlen(handle); + if ( len < sizeof(Dilithium_handles[0].handle)-1 ) + { + pthread_mutex_lock(&DILITHIUM_MUTEX); + HASH_FIND(hh,Dilithium_handles,handle,len,hashstr); + if ( hashstr == 0 ) + { + hashstr = (struct dilithium_handle *)calloc(1,sizeof(*hashstr)); + strncpy(hashstr->handle,handle,sizeof(hashstr->handle)); + HASH_ADD_KEYPTR(hh,Dilithium_handles,hashstr->handle,len,hashstr); + } + pthread_mutex_unlock(&DILITHIUM_MUTEX); + } + return(hashstr); +} + +struct dilithium_handle *dilithium_handlefind(char *handle) +{ + struct dilithium_handle *hashstr = 0; int32_t len = (int32_t)strlen(handle); + if ( len < sizeof(Dilithium_handles[0].handle)-1 ) + { + pthread_mutex_lock(&DILITHIUM_MUTEX); + HASH_FIND(hh,Dilithium_handles,handle,len,hashstr); + pthread_mutex_unlock(&DILITHIUM_MUTEX); + } + return(hashstr); +} + +int32_t dilithium_Qmsghash(uint8_t *msg,CTransaction tx,int32_t numvouts,std::vector voutpubtxids) +{ + CScript data; uint256 hash; int32_t i,numvins,len = 0; std::vector vintxids; std::vector vinprevns; std::vector vouts; + numvins = tx.vin.size(); + for (i=0; i bigpub) { CScript opret; uint8_t evalcode = EVAL_DILITHIUM; @@ -2969,6 +3046,24 @@ uint8_t dilithium_spendopretdecode(uint256 &destpubtxid,std::vector &si return(0); } +CScript dilithium_Qsendopret(uint256 destpubtxid,std::vectorsig,std::vector voutpubtxids) +{ + CScript opret; uint8_t evalcode = EVAL_DILITHIUM; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'Q' << destpubtxid << sig << voutpubtxids); + return(opret); +} + +uint8_t dilithium_Qsendopretdecode(uint256 &destpubtxid,std::vector&sig,std::vector &voutpubtxids,CScript scriptPubKey) +{ + std::vector vopret; uint8_t e,f; + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> destpubtxid; ss >> sig; ss >> voutpubtxids) != 0 && e == EVAL_DILITHIUM && f == 'Q' ) + { + return(f); + } + return(0); +} + UniValue dilithium_rawtxresult(UniValue &result,std::string rawtx) { CTransaction tx; @@ -3014,14 +3109,17 @@ char *dilithium_hexstr(char *str,uint8_t *buf,int32_t len) int32_t dilithium_bigpubget(std::string &handle,CPubKey &pk33,uint8_t *pk,uint256 pubtxid) { - CTransaction tx; uint256 hashBlock; int32_t numvouts; std::vector bigpub; - if ( myGetTransaction(pubtxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) + CTransaction tx; uint8_t funcid; uint256 hashBlock; int32_t numvouts=0; std::vector bigpub; + if ( myGetTransaction(pubtxid,tx,hashBlock) != 0 ) { - if ( dilithium_registeropretdecode(handle,pk33,bigpub,tx.vout[numvouts-1].scriptPubKey) == 'R' && bigpub.size() == CRYPTO_PUBLICKEYBYTES ) + if ( (numvouts= tx.vout.size()) > 1 ) { - memcpy(pk,&bigpub[0],CRYPTO_PUBLICKEYBYTES); - return(0); - } else return(-2); + if ( (funcid= dilithium_registeropretdecode(handle,pk33,bigpub,tx.vout[numvouts-1].scriptPubKey)) == 'R' && bigpub.size() == CRYPTO_PUBLICKEYBYTES ) + { + memcpy(pk,&bigpub[0],CRYPTO_PUBLICKEYBYTES); + return(0); + } else return(-2); + } } return(-1); } @@ -3051,12 +3149,20 @@ UniValue dilithium_keypair(uint64_t txfee,struct CCcontract_info *cp,cJSON *para return(result); } +CPubKey Faucet_pubkeyget() +{ + struct CCcontract_info *cp,C; + cp = CCinit(&C,EVAL_FAUCET); + return(GetUnspendable(cp,0)); +} + UniValue dilithium_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,dilithiumpk; uint8_t seed[SEEDBYTES],pk[CRYPTO_PUBLICKEYBYTES],sk[CRYPTO_SECRETKEYBYTES]; char coinaddr[64],str[CRYPTO_SECRETKEYBYTES*2+1]; std::vector bigpub; int32_t i,n,warningflag = 0; + UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey faucetpk,mypk,dilithiumpk; uint8_t seed[SEEDBYTES],pk[CRYPTO_PUBLICKEYBYTES],sk[CRYPTO_SECRETKEYBYTES]; char coinaddr[64],str[CRYPTO_SECRETKEYBYTES*2+1]; int64_t CCchange,inputs; std::vector bigpub; int32_t i,n,warningflag = 0; if ( txfee == 0 ) txfee = DILITHIUM_TXFEE; + faucetpk = Faucet_pubkeyget(); mypk = pubkey2pk(Mypubkey()); dilithiumpk = GetUnspendable(cp,0); if ( params != 0 && ((n= cJSON_GetArraySize(params)) == 1 || n == 2) ) @@ -3073,14 +3179,23 @@ UniValue dilithium_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *par result.push_back(Pair("skaddr",dilithium_addr(coinaddr,sk,CRYPTO_SECRETKEYBYTES))); for (i=0; i= 3*txfee ) + if ( (inputs= AddCClibtxfee(cp,mtx,dilithiumpk)) > 0 ) { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,dilithiumpk)); - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk)); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,dilithium_registeropret(handle,mypk,bigpub)); - return(musig_rawtxresult(result,rawtx)); - } else return(cclib_error(result,"couldnt find enough funds")); - } else return(cclib_error(result,"not enough parameters")); + if ( inputs > txfee ) + CCchange = (inputs - txfee); + else CCchange = 0; + if ( AddNormalinputs(mtx,mypk,COIN+3*txfee,64) >= 3*txfee ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,2*txfee,dilithiumpk)); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET,COIN,faucetpk)); + if ( CCchange != 0 ) + mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dilithiumpk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,dilithium_registeropret(handle,mypk,bigpub)); + return(musig_rawtxresult(result,rawtx)); + } else return(cclib_error(result,"couldnt find enough funds")); + } else return(cclib_error(result,"not enough parameters")); + } else return(cclib_error(result,"not dilithiumpk funds")); } UniValue dilithium_sign(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) @@ -3169,16 +3284,6 @@ UniValue dilithium_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) } else return(cclib_error(result,"not enough parameters")); } -/* - ultimately what is needed is to be able to scan all utxos to the CC address and be able to spend many vins in the same tx. to do this the opreturn would need to be able to have txid of special with the sigs. However, it is complicated by the need to create a specific message to sign that is the desired outputs and all the inputs. Also, to properly be able to do change and keep everything in dilithium outputs, there needs to be a second destpub. - - so the proposed opreturn for spend would be: - - destpubtxid0, destpubtxid1 (zeroid if only 1), vector of sigs/sigtxid where if it is len 32 it is a txid that just has the sig in the opreturn. - - however, for now, to keep things simple we will only support spending a specific txid to normal output to avoid needing a combined opreturn and other complications. - */ - UniValue dilithium_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); @@ -3229,10 +3334,320 @@ UniValue dilithium_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params } else return(cclib_error(result,"need to have exactly 2 params sendtxid, scriptPubKey")); } +int64_t dilithium_inputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 destpubtxid,int64_t total,int32_t maxinputs,char *cmpaddr) +{ + char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 checktxid,txid,hashBlock; std::vector origpubkey,tmpsig; CTransaction vintx; int32_t vout,numvouts,n = 0; std::vector voutpubtxids; + std::vector > unspentOutputs; + GetCCaddress(cp,coinaddr,pk); + SetCCunspents(unspentOutputs,coinaddr); + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; + if ( maxinputs > 0 ) + threshold = total/maxinputs; + else threshold = total; + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f vs %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN,(double)threshold/COIN); + if ( it->second.satoshis < threshold || it->second.satoshis == DILITHIUM_TXFEE ) + continue; + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 && (numvouts= vintx.vout.size()) > 1 ) + { + if ( (nValue= IsCClibvout(cp,vintx,vout,cmpaddr)) > DILITHIUM_TXFEE && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) + { + if ( (dilithium_Qsendopretdecode(checktxid,tmpsig,voutpubtxids,vintx.vout[numvouts-1].scriptPubKey) == 'Q' && vout < voutpubtxids.size() && destpubtxid == voutpubtxids[vout]) || (dilithium_sendopretdecode(checktxid,vintx.vout[numvouts-1].scriptPubKey) == 'x' && destpubtxid == checktxid) ) + { + if ( total != 0 && maxinputs != 0 ) + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + nValue = it->second.satoshis; + totalinputs += nValue; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) + break; + } + } //else fprintf(stderr,"nValue %.8f too small or already spent in mempool\n",(double)nValue/COIN); + } else fprintf(stderr,"couldnt get tx\n"); + } + return(totalinputs); +} + +UniValue dilithium_Qsend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,destpub33; CTransaction tx,vintx; uint256 prevhash,mypubtxid,hashBlock,destpubtxid; int64_t amount,inputsum,outputsum,change; int32_t i,smlen,n,numvouts; char str[129],myCCaddr[64],*scriptstr; CTxOut vout; std::string handle; uint8_t pk[CRYPTO_PUBLICKEYBYTES],pk2[CRYPTO_PUBLICKEYBYTES],sk[CRYPTO_SECRETKEYBYTES],msg[32],seed[32]; std::vector sig; std::vector voutpubtxids; + if ( txfee == 0 ) + txfee = DILITHIUM_TXFEE; + mypk = pubkey2pk(Mypubkey()); + GetCCaddress(cp,myCCaddr,mypk); + if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 4 && (n & 1) == 0 ) + { + mypubtxid = juint256(jitem(params,0)); + if ( cclib_parsehash(seed,jitem(params,1),32) < 0 ) + { + Myprivkey(seed); + result.push_back(Pair("warning","test mode using privkey for -pubkey, only for testing. there is no point using quantum secure signing if you are using a privkey with a known secp256k1 pubkey!!")); + } + _dilithium_keypair(pk,sk,seed); + outputsum = 0; + for (i=2; ievalcode,amount,destpub33)); + voutpubtxids.push_back(prevhash); // binds destpub22 CC addr with dilithium bigpub + } + } + else + { + CScript scriptPubKey; + scriptPubKey.resize(strlen(scriptstr)/2); + decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr); + vout.nValue = amount; + vout.scriptPubKey = scriptPubKey; + mtx.vout.push_back(vout); + voutpubtxids.push_back(zeroid); + } + outputsum += amount; + } + if ( (inputsum= dilithium_inputs(cp,mtx,mypk,mypubtxid,outputsum+txfee,64,myCCaddr)) >= outputsum+txfee ) + { + change = (inputsum - outputsum - txfee); + if ( change >= txfee ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,change,mypk)); + voutpubtxids.push_back(mypubtxid); + } + tx = mtx; + dilithium_Qmsghash(msg,tx,(int32_t)voutpubtxids.size(),voutpubtxids); + //for (i=0; i<32; i++) + // fprintf(stderr,"%02x",msg[i]); + //fprintf(stderr," msg\n"); + sig.resize(32+CRYPTO_BYTES); + if ( dilithium_bigpubget(handle,destpub33,pk2,mypubtxid) < 0 ) + return(cclib_error(result,"couldnt get bigpub")); + else if ( memcmp(pk,pk2,sizeof(pk)) != 0 ) + return(cclib_error(result,"dilithium bigpub mismatch")); + else if ( destpub33 != mypk ) + return(cclib_error(result,"destpub33 is not for this -pubkey")); + else if ( _dilithium_sign(&sig[0],&smlen,msg,32,sk) < 0 ) + return(cclib_error(result,"dilithium signing error")); + else if ( smlen != 32+CRYPTO_BYTES ) + return(cclib_error(result,"siglen error")); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,dilithium_Qsendopret(mypubtxid,sig,voutpubtxids)); + return(dilithium_rawtxresult(result,rawtx)); + } else return(cclib_error(result,"Q couldnt find enough Q or x inputs")); + } else return(cclib_error(result,"need to have exactly 2 params sendtxid, scriptPubKey")); +} + +bool dilithium_Qvalidate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) +{ + int32_t i,numvins,numvouts,mlen,smlen=CRYPTO_BYTES+32; CPubKey destpub33; std::string handle; uint256 tmptxid,hashBlock,destpubtxid,signerpubtxid; CTransaction vintx; std::vector tmpsig,sig,vopret; uint8_t msg[32],msg2[CRYPTO_BYTES+32],pk[CRYPTO_PUBLICKEYBYTES],*script; std::vector voutpubtxids; + numvins = tx.vin.size(); + signerpubtxid = zeroid; + for (i=0; i 1 ) + { + GetOpReturnData(vintx.vout[numvouts-1].scriptPubKey,vopret); + script = (uint8_t *)vopret.data(); + if ( script[1] == 'Q' ) + { + if ( dilithium_Qsendopretdecode(tmptxid,tmpsig,voutpubtxids,vintx.vout[numvouts-1].scriptPubKey) != 'Q' ) + return eval->Invalid("couldnt decode destpubtxid from Qsend"); + else if ( tx.vin[i].prevout.n > voutpubtxids.size() ) + return eval->Invalid("no destpubtxid for prevout.n"); + destpubtxid = voutpubtxids[tx.vin[i].prevout.n]; + } + else + { + if ( dilithium_sendopretdecode(destpubtxid,vintx.vout[numvouts-1].scriptPubKey) != 'x' ) + return eval->Invalid("couldnt decode destpubtxid from send"); + } + if ( signerpubtxid == zeroid ) + signerpubtxid = destpubtxid; + else if ( destpubtxid != signerpubtxid ) + return eval->Invalid("destpubtxid of vini doesnt match first one"); + } + } + } + if ( signerpubtxid != zeroid ) + { + numvouts = tx.vout.size(); + if ( dilithium_Qsendopretdecode(destpubtxid,sig,voutpubtxids,tx.vout[numvouts-1].scriptPubKey) == 'Q' && destpubtxid == signerpubtxid && sig.size() == smlen ) + { + if ( dilithium_Qmsghash(msg,tx,numvouts-1,voutpubtxids) < 0 ) + return eval->Invalid("couldnt get Qmsghash"); + else if ( dilithium_bigpubget(handle,destpub33,pk,signerpubtxid) < 0 ) + return eval->Invalid("couldnt get bigpub"); + else + { + if ( _dilithium_verify(msg2,&mlen,&sig[0],smlen,pk) < 0 ) + return eval->Invalid("failed dilithium verify"); + else if ( mlen != 32 || memcmp(msg,msg2,32) != 0 ) + { + for (i=0; i<32; i++) + fprintf(stderr,"%02x",msg[i]); + fprintf(stderr," vs "); + for (i=0; iInvalid("failed dilithium msg verify"); + } + else return true; + } + } else return eval->Invalid("failed decode Qsend"); + } else return eval->Invalid("unexpected zero signerpubtxid"); +} + +int32_t dilithium_registrationpub33(char *pkaddr,CPubKey &pub33,uint256 txid) +{ + std::string handle; std::vector bigpub; CTransaction tx; uint256 hashBlock; int32_t numvouts; + pkaddr[0] = 0; + if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) + { + if ( dilithium_registeropretdecode(handle,pub33,bigpub,tx.vout[numvouts-1].scriptPubKey) == 'R' ) + { + dilithium_addr(pkaddr,&bigpub[0],CRYPTO_PUBLICKEYBYTES); + return(0); + } + } + return(-1); +} + +void dilithium_handleinit(struct CCcontract_info *cp) +{ + static int32_t didinit; + std::vector > txids; struct dilithium_handle *hashstr; CPubKey dilithiumpk,pub33; uint256 txid,hashBlock; CTransaction txi; int32_t numvouts; std::vector bigpub; std::string handle; char CCaddr[64]; + if ( didinit != 0 ) + return; + pthread_mutex_init(&DILITHIUM_MUTEX,NULL); + dilithiumpk = GetUnspendable(cp,0); + GetCCaddress(cp,CCaddr,dilithiumpk); + SetCCtxids(txids,CCaddr); + for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) + { + txid = it->first.txhash; + if ( myGetTransaction(txid,txi,hashBlock) != 0 && (numvouts= txi.vout.size()) > 1 ) + { + if ( dilithium_registeropretdecode(handle,pub33,bigpub,txi.vout[numvouts-1].scriptPubKey) == 'R' ) + { + if ( (hashstr= dilithium_handlenew((char *)handle.c_str())) != 0 ) + { + if ( hashstr->destpubtxid != txid ) + { + if ( hashstr->destpubtxid != zeroid ) + fprintf(stderr,"overwriting %s %s with %s\n",handle.c_str(),hashstr->destpubtxid.GetHex().c_str(),txid.GetHex().c_str()); + fprintf(stderr,"%s <- %s\n",handle.c_str(),txid.GetHex().c_str()); + hashstr->destpubtxid = txid; + } + } + } + } + } + didinit = 1; +} + +UniValue dilithium_handleinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); CPubKey pub33; int32_t i,n; char *handlestr,pkaddr[64],str[67]; struct dilithium_handle *hashstr; + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 1 ) + { + dilithium_handleinit(cp); + if ( (handlestr= jstr(jitem(params,0),0)) != 0 ) + { + result.push_back(Pair("result","success")); + result.push_back(Pair("handle",handlestr)); + if ( (hashstr= dilithium_handlefind(handlestr)) != 0 ) + { + result.push_back(Pair("destpubtxid",hashstr->destpubtxid.GetHex().c_str())); + if ( dilithium_registrationpub33(pkaddr,pub33,hashstr->destpubtxid) == 0 ) + { + for (i=0; i<33; i++) + sprintf(&str[i<<1],"%02x",((uint8_t *)pub33.begin())[i]); + str[i<<1] = 0; + result.push_back(Pair("pkaddr",pkaddr)); + } + result.push_back(Pair("pubkey",str)); + } else result.push_back(Pair("status","available")); + return(result); + } + } + result.push_back(Pair("result","error")); + return(result); +} + +bool dilithium_Rvalidate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) +{ + static int32_t didinit; + uint256 txid; int32_t numvouts; struct dilithium_handle *hashstr; std::string handle; std::vector bigpub; CPubKey oldpub33,pub33,dilithiumpk; CTxOut vout,vout0; char pkaddr[64]; + if ( height < 14500 ) + return(true); + dilithium_handleinit(cp); + dilithiumpk = GetUnspendable(cp,0); + if ( (numvouts= tx.vout.size()) <= 1 ) + return eval->Invalid("not enough vouts for registration tx"); + else if ( dilithium_registeropretdecode(handle,pub33,bigpub,tx.vout[numvouts-1].scriptPubKey) == 'R' ) + { + // relies on all current block tx to be put into mempool + txid = tx.GetHash(); + vout0 = MakeCC1vout(cp->evalcode,2*DILITHIUM_TXFEE,dilithiumpk); + vout = MakeCC1vout(EVAL_FAUCET,COIN,Faucet_pubkeyget()); + if ( tx.vout[0] != vout0 ) + return eval->Invalid("mismatched vout0 for register"); + else if ( tx.vout[1].nValue != DILITHIUM_TXFEE ) + return eval->Invalid("vout1 for register not txfee"); + else if ( tx.vout[2] != vout ) + return eval->Invalid("register not sending to faucet"); + else if ( (hashstr= dilithium_handlenew((char *)handle.c_str())) == 0 ) + return eval->Invalid("error creating dilithium handle"); + else if ( hashstr->destpubtxid == zeroid ) + { + hashstr->destpubtxid = txid; + return(true); + } + else + { + if ( hashstr->destpubtxid == txid ) + return(true); + else if ( dilithium_registrationpub33(pkaddr,oldpub33,hashstr->destpubtxid) == 0 ) + { + if ( oldpub33 == pub33 ) + { + hashstr->destpubtxid = txid; + fprintf(stderr,"ht.%d %s <- %s\n",height,handle.c_str(),txid.GetHex().c_str()); + return(true); + } + } + return eval->Invalid("duplicate dilithium handle rejected"); + } + } else return eval->Invalid("couldnt decode register opret"); +} + bool dilithium_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { - CPubKey destpub33; std::string handle; uint256 hashBlock,destpubtxid,checktxid; CTransaction vintx; int32_t numvouts,mlen,smlen=CRYPTO_BYTES+32; std::vector sig; uint8_t msg[32],msg2[CRYPTO_BYTES+32],pk[CRYPTO_PUBLICKEYBYTES]; - if ( tx.vout.size() != 2 ) + CPubKey destpub33; std::string handle; uint256 hashBlock,destpubtxid,checktxid; CTransaction vintx; int32_t numvouts,mlen,smlen=CRYPTO_BYTES+32; std::vector sig,vopret; uint8_t msg[32],msg2[CRYPTO_BYTES+32],pk[CRYPTO_PUBLICKEYBYTES],*script; + // if all dilithium tx -> do multispend/send, else: + numvouts = tx.vout.size(); + GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); + script = (uint8_t *)vopret.data(); + if ( script[1] == 'R' ) + return(dilithium_Rvalidate(cp,height,eval,tx)); + else if ( script[1] == 'Q' ) + return(dilithium_Qvalidate(cp,height,eval,tx)); + else if ( tx.vout.size() != 2 ) return eval->Invalid("numvouts != 2"); else if ( tx.vin.size() != 1 ) return eval->Invalid("numvins != 1"); diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 405f02cc4..62f020063 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -154,46 +154,17 @@ int32_t Eval::GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t time return komodo_notaries(pubkeys, height, timestamp); } - bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const { if (tx.vin.size() < 11) return false; - uint8_t seenNotaries[64] = {0}; - uint8_t notaries[64][33]; - int nNotaries = GetNotaries(notaries, height, timestamp); + CrosschainAuthority auth; + auth.requiredSigs = 11; + auth.size = GetNotaries(auth.notaries, height, timestamp); - BOOST_FOREACH(const CTxIn &txIn, tx.vin) - { - // Get notary pubkey - CTransaction tx; - uint256 hashBlock; - if (!GetTxUnconfirmed(txIn.prevout.hash, tx, hashBlock)) return false; - if (tx.vout.size() < txIn.prevout.n) return false; - CScript spk = tx.vout[txIn.prevout.n].scriptPubKey; - if (spk.size() != 35) return false; - std::vector scriptVec = std::vector(spk.begin(),spk.end()); - const unsigned char *pk = scriptVec.data(); - if (pk++[0] != 33) return false; - if (pk[33] != OP_CHECKSIG) return false; - - // Check it's a notary - for (int i=0; i > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); - threshold = total/(maxinputs+1); + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; + if ( maxinputs > 0 ) + threshold = total/maxinputs; + else threshold = total; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index 5d803a80e..18fc43004 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -157,19 +157,21 @@ CScript EncodeGatewaysBindOpRet(uint8_t funcid,uint256 tokenid,std::string coin, { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; struct CCcontract_info *cp,C; CPubKey gatewayspk; std::vector pubkeys; + vscript_t vopret; cp = CCinit(&C,EVAL_GATEWAYS); gatewayspk = GetUnspendable(cp,0); pubkeys.push_back(gatewayspk); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << totalsupply << oracletxid << M << N << gatewaypubkeys << taddr << prefix << prefix2 << wiftype); - return(EncodeTokenOpRet(tokenid,pubkeys,opret)); + vopret = E_MARSHAL(ss << evalcode << funcid << coin << totalsupply << oracletxid << M << N << gatewaypubkeys << taddr << prefix << prefix2 << wiftype); + return(EncodeTokenOpRet(tokenid,pubkeys, std::make_pair(OPRETID_GATEWAYSDATA, vopret))); } -uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,uint256 &tokenid,std::string &coin,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &gatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t wiftype) +uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,uint256 &tokenid,std::string &coin,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &gatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype) { + std::vector> oprets; std::vector vopret,vOpretExtra; uint8_t *script,e,f,tokenevalcode; std::vector pubkeys; - if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,oprets)!=0 && GetOpretBlob(oprets, OPRETID_GATEWAYSDATA, vOpretExtra) && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) { vopret=vOpretExtra; } @@ -183,7 +185,7 @@ uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,ui if ( N > 1 ) { strcpy(depositaddr,CBitcoinAddress(CScriptID(GetScriptForMultisig(M,gatewaypubkeys))).ToString().c_str()); - LogPrint("gatewayscc-1","f.%c M.%d of N.%d size.%d -> %s\n",f,M,N,(int32_t)gatewaypubkeys.size(),depositaddr); + LOGSTREAM("gatewayscc", CCLOG_DEBUG1, stream << "f." << f << " M." << M << " of N." << N << " size." << (int32_t)gatewaypubkeys.size() << " -> " << depositaddr << std::endl); } else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(gatewaypubkeys[0])) << OP_CHECKSIG); } else @@ -192,7 +194,7 @@ uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,ui else GetCustomscriptaddress(depositaddr,CScript() << ParseHex(HexStr(gatewaypubkeys[0])) << OP_CHECKSIG,taddr,prefix,prefix2); } return(f); - } else LogPrint("gatewayscc-1","error decoding bind opret\n"); + } else LOGSTREAM("gatewayscc",CCLOG_DEBUG1, stream << "error decoding bind opret" << std::endl); return(0); } @@ -221,17 +223,19 @@ CScript EncodeGatewaysClaimOpRet(uint8_t funcid,uint256 tokenid,uint256 bindtxid { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; struct CCcontract_info *cp,C; CPubKey gatewayspk; std::vector pubkeys; + vscript_t vopret; pubkeys.push_back(destpub); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << deposittxid << destpub << amount); - return(EncodeTokenOpRet(tokenid,pubkeys,opret)); + vopret = /*<< OP_RETURN <<*/ E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << deposittxid << destpub << amount); + return(EncodeTokenOpRet(tokenid,pubkeys, make_pair(OPRETID_GATEWAYSDATA, vopret))); } uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &tokenid,uint256 &bindtxid,std::string &refcoin,uint256 &deposittxid,CPubKey &destpub,int64_t &amount) { + std::vector> oprets; std::vector vopret,vOpretExtra; uint8_t *script,e,f,tokenevalcode; std::vector pubkeys; - if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys, oprets)!=0 && GetOpretBlob(oprets, OPRETID_GATEWAYSDATA, vOpretExtra) && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) { vopret=vOpretExtra; } @@ -248,19 +252,21 @@ CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid,uint256 tokenid,uint256 bindt { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; struct CCcontract_info *cp,C; CPubKey gatewayspk; std::vector pubkeys; + vscript_t vopret; cp = CCinit(&C,EVAL_GATEWAYS); gatewayspk = GetUnspendable(cp,0); pubkeys.push_back(gatewayspk); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << withdrawpub << amount); - return(EncodeTokenOpRet(tokenid,pubkeys,opret)); + vopret = /*opret << OP_RETURN << */ E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << withdrawpub << amount); + return(EncodeTokenOpRet(tokenid,pubkeys, std::make_pair(OPRETID_GATEWAYSDATA, vopret))); } uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256& tokenid, uint256 &bindtxid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) { + std::vector> oprets; std::vector vopret,vOpretExtra; uint8_t *script,e,f,tokenevalcode; std::vector pubkeys; - if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys, oprets)!=0 && GetOpretBlob(oprets, OPRETID_GATEWAYSDATA, vOpretExtra) && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) { vopret=vOpretExtra; } @@ -336,9 +342,10 @@ uint8_t DecodeGatewaysMarkDoneOpRet(const CScript &scriptPubKey, uint256 &withdr uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey) { + std::vector> oprets; std::vector vopret,vOpretExtra; uint8_t *script,e,f,tokenevalcode; std::vector pubkeys; uint256 tokenid; - if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys, oprets)!=0 && GetOpretBlob(oprets, OPRETID_GATEWAYSDATA, vOpretExtra) && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) { vopret=vOpretExtra; } @@ -374,15 +381,15 @@ bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti numvouts = tx.vout.size(); for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) { - //LogPrint("gatewayscc","vini.%d check mempool\n",i); + LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "vini." << i << " check mempool" << std::endl); if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) return eval->Invalid("cant find vinTx"); else { - //LogPrint("gatewayscc","vini.%d check hash and vout\n",i); + LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "vini." << i << " check hash and vout" << std::endl); if ( hashBlock == zerohash ) return eval->Invalid("cant Gateways from mempool"); if ( (assetoshis= IsGatewaysvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) @@ -392,13 +399,13 @@ bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti } for (i=0; iInvalid("mismatched inputs != outputs + txfee"); } else return(true); @@ -418,7 +425,7 @@ static int32_t myIs_coinaddr_inmempoolvout(char *coinaddr) Getscriptaddress(destaddr,tx.vout[i].scriptPubKey); if ( strcmp(destaddr,coinaddr) == 0 ) { - LogPrint("gatewayscc-1","found (%s) vout in mempool\n",coinaddr); + LOGSTREAM("gatewayscc",CCLOG_DEBUG1, stream << "found (" << coinaddr << ") vout in mempool" << std::endl); return(1); } } @@ -431,36 +438,35 @@ uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,u { CTransaction tx; uint256 hash,mhash,bhash,hashBlock,oracletxid; int32_t len,len2,numvouts; int64_t val,merkleht; CPubKey pk; std::vectordata; txid = zeroid; - char str[65]; - LogPrint("gatewayscc-2","start reverse scan %s\n",uint256_str(str,batontxid)); + LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "start reverse scan " << batontxid.GetHex() << std::endl); while ( myGetTransaction(batontxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 ) { - LogPrint("gatewayscc-2","check %s\n",uint256_str(str,batontxid)); + LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "check " << batontxid.GetHex() << std::endl); if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid ) { - LogPrint("gatewayscc-2","decoded %s\n",uint256_str(str,batontxid)); + LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "decoded " << batontxid.GetHex() << std::endl); if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height ) { len = oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()); len2 = oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()); - char str2[65]; LogPrint("gatewayscc","found merkleht.%d len.%d len2.%d %s %s\n",(int32_t)merkleht,len,len2,uint256_str(str,hash),uint256_str(str2,mhash)); + LOGSTREAM("gatewayscc",CCLOG_DEBUG1, stream << "found merkleht." << (int32_t)merkleht << " len." << len << " len2." << len2 << " " << hash.GetHex() << " " << mhash.GetHex() << std::endl); if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid ) { txid = batontxid; - LogPrint("gatewayscc-2","set txid\n"); + LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "set txid" << std::endl); return(mhash); } else { - LogPrint("gatewayscc-2","missing hash\n"); + LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "missing hash" << std::endl); return(zeroid); } - } else LogPrint("gatewayscc-2","height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height); + } else LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "height." << (int32_t)merkleht << " vs search ht." << (int32_t)height << std::endl); batontxid = bhash; - LogPrint("gatewayscc-2","new hash %s\n",uint256_str(str,batontxid)); + LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "new hash " << batontxid.GetHex() << std::endl); } else break; } - LogPrint("gatewayscc-2","end of loop\n"); + LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "end of loop\n"); return(zeroid); } @@ -493,27 +499,27 @@ uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::ve int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub,uint8_t taddr,uint8_t prefix,uint8_t prefix2) { std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; - char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,numvouts; int64_t nValue = 0; + char destaddr[64],destpubaddr[64],claimaddr[64]; int32_t i,numvouts; int64_t nValue = 0; if ( myGetTransaction(oracletxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) { - LogPrint("gatewayscc","GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid)); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "GatewaysVerify cant find oracletxid " << oracletxid.GetHex() << std::endl); return(0); } if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin ) { - LogPrint("gatewayscc","GatewaysVerify mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str()); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "GatewaysVerify mismatched oracle name " << name << " != " << refcoin << std::endl); return(0); } proofroot = BitcoinGetProofMerkleRoot(proof,txids); if ( proofroot != merkleroot ) { - LogPrint("gatewayscc","GatewaysVerify mismatched merkleroot %s != %s\n",uint256_str(str,proofroot),uint256_str(str2,merkleroot)); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "GatewaysVerify mismatched merkleroot " << proofroot.GetHex() << " != " << merkleroot.GetHex() << std::endl); return(0); } if (std::find(txids.begin(), txids.end(), cointxid) == txids.end()) { - LogPrint("gatewayscc", "GatewaysVerify invalid proof for this cointxid\n"); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "GatewaysVerify invalid proof for this cointxid" << std::endl); return 0; } if ( DecodeHexTx(tx,deposithex) != 0 ) @@ -534,10 +540,10 @@ int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout } if ( txid == cointxid ) { - LogPrint("gatewayscc-1","verified proof for cointxid in merkleroot\n"); + LOGSTREAM("gatewayscc",CCLOG_DEBUG1, stream << "verified proof for cointxid in merkleroot" << std::endl); return(nValue); - } else LogPrint("gatewayscc","(%s) != (%s) or txid %s mismatch.%d or script mismatch\n",refdepositaddr,destaddr,uint256_str(str,txid),txid != cointxid); - } else LogPrint("gatewayscc","claimaddr.(%s) != destpubaddr.(%s)\n",claimaddr,destpubaddr); + } else LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "(" << refdepositaddr << ") != (" << destaddr << ") or txid " << txid.GetHex() << " mismatch." << (txid!=cointxid) << " or script mismatch" << std::endl); + } else LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "claimaddr." << claimaddr << " != destpubaddr." << destpubaddr << std::endl); } return(0); } @@ -571,7 +577,7 @@ int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 { if ( tokenid == reftokenid ) { - LogPrint("gatewayscc","trying to bind an existing tokenid\n"); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "trying to bind an existing tokenid" << std::endl); return(1); } } @@ -869,7 +875,7 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & } retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); if ( retval != 0 ) - LogPrint("gatewayscc","Gateways tx validated\n"); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "Gateways tx validated" << std::endl); else fprintf(stderr,"Gateways tx invalid\n"); return(retval); // } @@ -892,8 +898,12 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP { GetTokensCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); - threshold = total/(maxinputs+1); - LogPrint("gatewayscc-1","check %s for gateway inputs\n",coinaddr); + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; + if ( maxinputs > 0 ) + threshold = total/maxinputs; + else threshold = total; + LOGSTREAM("gatewayscc",CCLOG_DEBUG1, stream << "check " << coinaddr << " for gateway inputs" << std::endl); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; @@ -928,9 +938,9 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP } return(totalinputs); } - else LogPrint("gatewayscc","invalid GatewaysBind\n"); + else LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "invalid GatewaysBind" << std::endl); } - else LogPrint("gatewayscc","can't find GatewaysBind txid\n"); + else LOGSTREAM("gatewayscc",CCLOG_INFO, stream << "can't find GatewaysBind txid" << std::endl); return(0); } @@ -956,18 +966,18 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t prefix2 = p2; wiftype = p3; taddr = p4; - LogPrint("gatewayscc-1","set prefix %d, prefix2 %d, wiftype %d for %s\n",prefix,prefix2,wiftype,coin.c_str()); + LOGSTREAM("gatewayscc",CCLOG_DEBUG1, stream << "set prefix " << prefix << ", prefix2 " << prefix2 << ", wiftype " << wiftype << ", taddr " << taddr << " for " << coin << std::endl); } if ( N == 0 || N > 15 || M > N ) { CCerror = strprintf("illegal M.%d or N.%d",M,N); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( pubkeys.size() != N ) { CCerror = strprintf("M.%d N.%d but pubkeys[%d]",M,N,(int32_t)pubkeys.size()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } for (i=0; iunspendableCCaddr,(double)totalsupply/COIN,(double)fullsupply/COIN); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( CCtoken_balance(myTokenCCaddr,tokenid) != totalsupply ) { CCerror = strprintf("token balance on %s %.8f != %.8f",myTokenCCaddr,(double)CCtoken_balance(myTokenCCaddr,tokenid)/COIN,(double)totalsupply/COIN); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 ) { CCerror = strprintf("cant find oracletxid %s",uint256_str(str,oracletxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' ) { CCerror = strprintf("mismatched oracle name %s != %s",name.c_str(),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( (fstr=(char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 ) { CCerror = strprintf("illegal format (%s) != (%s)",fstr,(char *)"Ihh"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( GatewaysBindExists(cp,gatewayspk,tokenid) != 0 ) { CCerror = strprintf("Gateway bind.%s (%s) already exists",coin.c_str(),uint256_str(str,tokenid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) @@ -1037,7 +1047,7 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t } } CCerror = strprintf("cant find enough inputs"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } @@ -1052,30 +1062,31 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - LogPrint("gatewayscc-1","GatewaysDeposit ht.%d %s %.8f numpks.%d\n",height,refcoin.c_str(),(double)amount/COIN,(int32_t)pubkeys.size()); + LOGSTREAM("gatewayscc",CCLOG_DEBUG1, stream << "GatewaysDeposit ht." << height << " " << refcoin << " " << (double)amount/COIN << " numpks." << (int32_t)pubkeys.size() << std::endl); if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 ) { CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin ) { CCerror = strprintf("invalid coin - bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (komodo_txnotarizedconfirmed(bindtxid)==false) { CCerror = strprintf("gatewaysbind tx not yet confirmed/notarized"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } n = (int32_t)pubkeys.size(); merkleroot = zeroid; for (i=m=0; i 0 ) @@ -1112,7 +1123,7 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysDepositOpRet('D',bindtxid,coin,publishers,txids,height,cointxid,claimvout,deposithex,proof,destpub,amount))); } CCerror = strprintf("cant find enough inputs"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } @@ -1132,49 +1143,49 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || coin != refcoin ) { CCerror = strprintf("invalid coin - bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (komodo_txnotarizedconfirmed(bindtxid)==false) { CCerror = strprintf("gatewaysbind tx not yet confirmed/notarized"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { CCerror = strprintf("cant find deposittxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,tmptxid,coin,publishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D' || coin != refcoin) { CCerror = strprintf("invalid coin - deposittxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (komodo_txnotarizedconfirmed(deposittxid)==false) { CCerror = strprintf("gatewaysdeposit tx not yet confirmed/notarized"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (tmpdestpub!=destpub) { CCerror = strprintf("different destination pubkey from desdeposit tx"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( (depositamount=GatewaysDepositval(tx,mypk)) != amount ) { CCerror = strprintf("invalid Gateways deposittxid %s %.8f != %.8f",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) @@ -1189,7 +1200,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui } } CCerror = strprintf("cant find enough inputs or mismatched total"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } @@ -1211,19 +1222,19 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin if( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || coin != refcoin ) { CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (komodo_txnotarizedconfirmed(bindtxid)==false) { CCerror = strprintf("gatewaysbind tx not yet confirmed/notarized"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); @@ -1241,7 +1252,7 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin && refcoin==coin && tmptokenid==tokenid && tmpbindtxid==bindtxid) { CCerror = strprintf("unable to create withdraw, another withdraw pending"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } @@ -1250,7 +1261,7 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin && refcoin==coin && tmptokenid==tokenid && tmpbindtxid==bindtxid) { CCerror = strprintf("unable to create withdraw, another withdraw pending"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } } @@ -1268,12 +1279,12 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin else { CCerror = strprintf("not enough balance of tokens for withdraw"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } } CCerror = strprintf("cant find enough normal inputs"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } @@ -1294,7 +1305,7 @@ std::string GatewaysPartialSign(uint64_t txfee,uint256 lasttxid,std::string refc || (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) { CCerror = strprintf("can't find last tx %s",uint256_str(str,lasttxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (funcid=='W') @@ -1303,26 +1314,26 @@ std::string GatewaysPartialSign(uint64_t txfee,uint256 lasttxid,std::string refc if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) { CCerror = strprintf("invalid withdraw tx %s",uint256_str(str,lasttxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (komodo_txnotarizedconfirmed(withdrawtxid)==false) { CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (GetTransaction(bindtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())<=0) { CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (DecodeGatewaysBindOpRet(depositaddr,tmptx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin!=coin || tokenid!=tmptokenid) { CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } } @@ -1331,39 +1342,39 @@ std::string GatewaysPartialSign(uint64_t txfee,uint256 lasttxid,std::string refc if (DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) { CCerror = strprintf("cannot decode partialsign tx opret %s",uint256_str(str,lasttxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (GetTransaction(withdrawtxid,tmptx,hashBlock,false)==0 || (numvouts= tmptx.vout.size())<=0) { CCerror = strprintf("can't find withdraw tx %s",uint256_str(str,withdrawtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (DecodeGatewaysWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) { CCerror = strprintf("invalid withdraw tx %s",uint256_str(str,lasttxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (komodo_txnotarizedconfirmed(withdrawtxid)==false) { CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (GetTransaction(bindtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())<=0) { CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (DecodeGatewaysBindOpRet(depositaddr,tmptx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin!=coin || tokenid!=tmptokenid) { CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } } @@ -1374,7 +1385,7 @@ std::string GatewaysPartialSign(uint64_t txfee,uint256 lasttxid,std::string refc return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysPartialOpRet('P',withdrawtxid,refcoin,K+1,mypk,hex))); } CCerror = strprintf("error adding funds for partialsign"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } @@ -1394,7 +1405,7 @@ std::string GatewaysCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string || (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) { CCerror = strprintf("invalid last txid %s",uint256_str(str,lasttxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (funcid=='W') @@ -1403,26 +1414,26 @@ std::string GatewaysCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) { CCerror = strprintf("cannot decode withdraw tx opret %s",uint256_str(str,lasttxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (GetTransaction(bindtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())<=0) { CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (komodo_txnotarizedconfirmed(withdrawtxid)==false) { CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (DecodeGatewaysBindOpRet(depositaddr,tmptx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin!=coin || tokenid!=tmptokenid) { CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } } @@ -1431,38 +1442,38 @@ std::string GatewaysCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string if (DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) { CCerror = strprintf("cannot decode partialsign tx opret %s",uint256_str(str,lasttxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (GetTransaction(withdrawtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())==0) { CCerror = strprintf("invalid withdraw txid %s",uint256_str(str,withdrawtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (DecodeGatewaysWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) { CCerror = strprintf("cannot decode withdraw tx opret %s",uint256_str(str,withdrawtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (komodo_txnotarizedconfirmed(withdrawtxid)==false) { CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (GetTransaction(bindtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())<=0) { CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (DecodeGatewaysBindOpRet(depositaddr,tmptx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin!=coin || tokenid!=tmptokenid) { CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } } @@ -1473,7 +1484,7 @@ std::string GatewaysCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysCompleteSigningOpRet('S',withdrawtxid,refcoin,K+1,hex))); } CCerror = strprintf("error adding funds for completesigning"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } @@ -1491,44 +1502,44 @@ std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string ref if (GetTransaction(completetxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0) { CCerror = strprintf("invalid completesigning txid %s",uint256_str(str,completetxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,hex)!='S' || refcoin!=coin) { CCerror = strprintf("cannot decode completesigning tx opret %s",uint256_str(str,completetxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (komodo_txnotarizedconfirmed(completetxid)==false) { CCerror = strprintf("gatewayscompletesigning tx not yet confirmed/notarized"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (GetTransaction(withdrawtxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())==0) { CCerror = strprintf("invalid withdraw txid %s",uint256_str(str,withdrawtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) { CCerror = strprintf("cannot decode withdraw tx opret %s\n",uint256_str(str,withdrawtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (GetTransaction(bindtxid,tx,hashBlock,false)==0 || (numvouts=tx.vout.size())<=0) { CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } else if (DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin!=coin || tokenid!=tmptokenid) { CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if (AddNormalinputs(mtx,mypk,txfee,3)!=0) @@ -1538,7 +1549,7 @@ std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string ref return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysMarkDoneOpRet('M',withdrawtxid,refcoin,completetxid))); } CCerror = strprintf("error adding funds for markdone"); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } @@ -1558,13 +1569,13 @@ UniValue GatewaysPendingDeposits(uint256 bindtxid,std::string refcoin) if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin) { CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } SetCCunspents(unspentOutputs,coinaddr); @@ -1613,13 +1624,13 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin ) { CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } n = msigpubkeys.size(); @@ -1701,13 +1712,13 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin) { CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } n = msigpubkeys.size(); @@ -1779,13 +1790,13 @@ UniValue GatewaysExternalAddress(uint256 bindtxid,CPubKey pubkey) if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') { CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } GetCustomscriptaddress(addr,CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG,taddr,prefix,prefix2); @@ -1803,19 +1814,19 @@ UniValue GatewaysDumpPrivKey(uint256 bindtxid,CKey key) if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') { CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } priv=EncodeCustomSecret(key,wiftype); result.push_back(Pair("result","success")); - result.push_back(Pair("address",priv.c_str())); + result.push_back(Pair("privkey",priv.c_str())); return(result); } @@ -1832,13 +1843,13 @@ UniValue GatewaysInfo(uint256 bindtxid) if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') { CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LogPrint("gatewayscc","%s\n", CCerror.c_str() ); + LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index aca30208b..9cb0f03bd 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -255,25 +255,25 @@ template int64_t IsHeirFundingVout(struct CCcontract_info* cp, co } // makes coin initial tx opret -CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) +vscript_t EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) { uint8_t evalcode = EVAL_HEIR; - return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName << memo); + return /*CScript() << OP_RETURN <<*/ E_MARSHAL(ss << evalcode << funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName << memo); } // makes coin additional tx opret -CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpendingBegun) +vscript_t EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpendingBegun) { uint8_t evalcode = EVAL_HEIR; fundingtxid = revuint256(fundingtxid); - return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << fundingtxid << hasHeirSpendingBegun); + return /*CScript() << OP_RETURN <<*/ E_MARSHAL(ss << evalcode << funcid << fundingtxid << hasHeirSpendingBegun); } // decode opret vout for Heir contract -uint8_t _DecodeHeirOpRet(std::vector vopret, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) +uint8_t _DecodeHeirOpRet(vscript_t vopret, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { uint8_t evalCodeInOpret = 0; uint8_t heirFuncId = 0; @@ -287,13 +287,13 @@ uint8_t _DecodeHeirOpRet(std::vector vopret, CPubKey& ownerPubkey, CPub uint8_t heirFuncId = 0; hasHeirSpendingBegun = 0; - bool result = E_UNMARSHAL(vopret, { ss >> evalCodeInOpret; ss >> heirFuncId; \ - if (heirFuncId == 'F') { \ - ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; ss >> memo; \ - } \ - else { \ - ss >> fundingTxidInOpret >> hasHeirSpendingBegun; \ - } \ + bool result = E_UNMARSHAL(vopret, { ss >> evalCodeInOpret; ss >> heirFuncId; + if (heirFuncId == 'F') { + ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; ss >> memo; + } + else { + ss >> fundingTxidInOpret >> hasHeirSpendingBegun; + } }); if (!result) { @@ -327,9 +327,11 @@ uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& { uint8_t evalCodeTokens = 0; std::vector voutPubkeysDummy; - std::vector vopretExtra /*, vopretStripped*/; + std::vector> oprets; + vscript_t vopretExtra /*, vopretStripped*/; - if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, vopretExtra) != 0) { + + if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, oprets) != 0 && GetOpretBlob(oprets, OPRETID_HEIRDATA, vopretExtra)) { /* if (vopretExtra.size() > 1) { // restore the second opret: diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 890e2b710..a27dc3340 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -7,8 +7,8 @@ #define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos) // makes coin initial tx opret -CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo); -CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan); +vscript_t EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo); +vscript_t EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan); uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan); //uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false); @@ -29,13 +29,13 @@ public: } static CScript makeCreateOpRet(uint256 dummyid, std::vector dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) { - return EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo); + return CScript() << OP_RETURN << EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo); } static CScript makeAddOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan); + return CScript() << OP_RETURN << EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan); } static CScript makeClaimOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan); + return CScript() << OP_RETURN << EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan); } static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) { return MakeCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey); @@ -71,15 +71,15 @@ public: static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) { return EncodeTokenOpRet(tokenid, voutTokenPubkeys, - EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo)); + std::make_pair(OPRETID_HEIRDATA, EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo))); } static CScript makeAddOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { return EncodeTokenOpRet(tokenid, voutTokenPubkeys, - EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan)); + std::make_pair(OPRETID_HEIRDATA, EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan))); } static CScript makeClaimOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { return EncodeTokenOpRet(tokenid, voutTokenPubkeys, - EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan)); + std::make_pair(OPRETID_HEIRDATA, EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan))); } static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) { diff --git a/src/cc/import.cpp b/src/cc/import.cpp index 25bed49df..bb4248e5a 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -478,5 +478,3 @@ bool Eval::ImportCoin(const std::vector params,const CTransaction &impo } return Valid(); } - - diff --git a/src/cc/makecustom b/src/cc/makecustom new file mode 100755 index 000000000..61b251e6e --- /dev/null +++ b/src/cc/makecustom @@ -0,0 +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 + diff --git a/src/cc/makerogue b/src/cc/makerogue index 51caef6e2..ff16cbb16 100755 --- a/src/cc/makerogue +++ b/src/cc/makerogue @@ -1,15 +1,14 @@ #!/bin/sh cd rogue; +make clean; if [ "$HOST" = "x86_64-w64-mingw32" ]; then echo building rogue.exe... ./configure --host=x86_64-w64-mingw32 - mkdir ncurses && cd ncurses echo $PWD - wget https://invisible-island.net/datafiles/release/mingw32.zip - unzip mingw32.zip && rm mingw32.zip + wget https://github.com/KomodoPlatform/rogue/releases/download/0.3.3b-01/x86_64-w64-mingw32.tar.gz + tar xvfz x86_64-w64-mingw32.tar.gz && rm x86_64-w64-mingw32.tar.gz echo lib archive cleaned - cd .. echo $PWD if make -f Makefile_win "$@"; then echo rogue.exe build SUCCESSFUL diff --git a/src/cc/maketetris b/src/cc/maketetris new file mode 100755 index 000000000..9c2a005a0 --- /dev/null +++ b/src/cc/maketetris @@ -0,0 +1,2 @@ +gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE tetris.cpp -lncurses -o tetris + diff --git a/src/cc/marmara.cpp b/src/cc/marmara.cpp index f43f3a559..60afbc7fd 100644 --- a/src/cc/marmara.cpp +++ b/src/cc/marmara.cpp @@ -167,7 +167,7 @@ int32_t MarmaraGetbatontxid(std::vector &creditloop,uint256 &batontxid, creditloop.push_back(txid); //fprintf(stderr,"%d: %s\n",n,txid.GetHex().c_str()); n++; - if ( (value= CCgettxout(spenttxid,vout,1)) == 10000 ) + if ( (value= CCgettxout(spenttxid,vout,1,1)) == 10000 ) { batontxid = spenttxid; //fprintf(stderr,"got baton %s %.8f\n",batontxid.GetHex().c_str(),(double)value/COIN); @@ -388,7 +388,11 @@ int64_t AddMarmarainputs(CMutableTransaction &mtx,std::vector &pubkeys, uint64_t threshold,nValue,totalinputs = 0; uint256 txid,hashBlock; CTransaction tx; int32_t numvouts,ht,unlockht,vout,i,n = 0; uint8_t funcid; CPubKey pk; std::vector vals; std::vector > unspentOutputs; SetCCunspents(unspentOutputs,coinaddr); - threshold = total/(maxinputs+1); + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; + if ( maxinputs > 0 ) + threshold = total/maxinputs; + else threshold = total; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index c4f476cfb..8fa87bd3d 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -15,203 +15,675 @@ #include "CCPayments.h" -/* - Payments CC is a catchall CC, supported invoices, zpayments, automated funds allocation, including token based revshare +/* + 0) txidopret <- allocation, scriptPubKey, opret + 1) create <- locked_blocks, minrelease, list of txidopret + 2) fund createtxid amount opretflag to global CC address with opret or txidaddr without + + 3) release amount -> vout[i] will be scriptPubKeys[i] and (amount * allocations[i]) / sumallocations[] (only using vins that have been locked for locked_blocks+). + + 4) info txid -> display parameters, funds + 5) list -> all txids + + First step is to create txids with the info needed in their opreturns. this info is the weight, scriptPubKey and opret if needed. To do that txidopret is used: + + ./c is a script that invokes komodo-cli with the correct -ac_name + + ./c paymentstxidopret \"[9,%222102d6f13a8f745921cdb811e32237bb98950af1a5952be7b3d429abd9152f8e388dac%22]\" -> rawhex with txid 95d9fc8d8a3ef63693c7427e59ff5e177ef63b7345d5f6d6497ac262699a8def + + ./c paymentstxidopret \"[1,%2221039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775ac%22]\" -> rawhex txid 00469695a08b975ceaf7258896abbf1455eb0f383e8a98fc650deace4cbf02a1 + + now we have 2 txid with the required info in the opreturn. one of them has a 9 and the other a 1 for a 90%/10% split. + + ./c paymentscreate \"[0,0,%2295d9fc8d8a3ef63693c7427e59ff5e177ef63b7345d5f6d6497ac262699a8def%22,%2200469695a08b975ceaf7258896abbf1455eb0f383e8a98fc650deace4cbf02a1%22]\" -> created txid 318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a that will be the createtxid that the other rpc calls will use. + + lets see if this appears in the list + + ./c paymentslist -> + { + "result": "success", + "createtxids": [ + "318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a" + ] + } + + It appeared! now lets get more info on it: + ./c paymentsinfo \"[%22318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a%22]\" + { + "lockedblocks": 0, + "totalallocations": 10, + "minrelease": 0, + "RWRM36sC8jSctyFZtsu7CyDcHYPdZX7nPZ": 0.00000000, + "REpyKi7avsVduqZ3eimncK4uKqSArLTGGK": 0.00000000, + "totalfunds": 0.00000000, + "result": "success" + } + + There are 2 possible places the funds for this createtxid can be, the first is the special address that is derived from combining the globalCC address with the txidaddr. txidaddr is a non-spendable markeraddress created by converting the txid into a 33 byte pubkey by prefixing 0x02 to the txid. It is a 1of2 address, so it doesnt matter that nobody knows the privkey for this txidaddr. the second address is the global CC address and only utxo to that address with an opreturn containing the createtxid are funds valid for this payments CC createtxid + + next let us add some funds to it. the funds can be to either of the two addresses, controlled by useopret (defaults to 0) + + ./c paymentsfund \"[%22318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a%22,1,0]\" -> txid 28f69b925bb7a21d2a3ba2327e85eb2031b014e976e43f5c2c6fb8a76767b221, which indeed sent funds to RWRM36sC8jSctyFZtsu7CyDcHYPdZX7nPZ without an opreturn and it appears on the payments info. + + ./c paymentsfund \"[%22318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a%22,1,1]\" -> txid cc93330b5c951b724b246b3b138d00519c33f2a600a7c938bc9e51aff6e20e32, which indeed sent funds to REpyKi7avsVduqZ3eimncK4uKqSArLTGGK with an opreturn and it appears on the payments info. + + +./c paymentsrelease \"[%22318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a%22,1.5]\" -> a8d5dbbb8ee94c05e75c4f3c5221091f59dcb86e0e9c4e1e3d2cf69e6fce6b81 + + it used both fund utxos */ // start of consensus code -int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) +CScript EncodePaymentsTxidOpRet(int32_t allocation,std::vector scriptPubKey,std::vector destopret) +{ + CScript opret; uint8_t evalcode = EVAL_PAYMENTS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'T' << allocation << scriptPubKey << destopret); + return(opret); +} + +uint8_t DecodePaymentsTxidOpRet(CScript scriptPubKey,int32_t &allocation,std::vector &destscriptPubKey,std::vector &destopret) +{ + 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 >> allocation; ss >> destscriptPubKey; ss >> destopret) != 0 ) + { + if ( e == EVAL_PAYMENTS && f == 'T' ) + return(f); + } + return(0); +} + +CScript EncodePaymentsFundOpRet(uint256 checktxid) +{ + CScript opret; uint8_t evalcode = EVAL_PAYMENTS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << checktxid); + return(opret); +} + +uint8_t DecodePaymentsFundOpRet(CScript scriptPubKey,uint256 &checktxid) +{ + 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) != 0 ) + { + if ( e == EVAL_PAYMENTS && f == 'F' ) + return(f); + } + return(0); +} + +CScript EncodePaymentsOpRet(int32_t lockedblocks,int32_t minrelease,int32_t totalallocations,std::vector txidoprets) +{ + CScript opret; uint8_t evalcode = EVAL_PAYMENTS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'C' << lockedblocks << minrelease << totalallocations << txidoprets); + return(opret); +} + +uint8_t DecodePaymentsOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int32_t &totalallocations,std::vector &txidoprets) +{ + 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 >> lockedblocks; ss >> minrelease; ss >> totalallocations; ss >> txidoprets) != 0 ) + { + if ( e == EVAL_PAYMENTS && f == 'C' ) + return(f); + } + return(0); +} + +int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr) { char destaddr[64]; if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) + if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && (cmpaddr[0] == 0 || strcmp(destaddr,cmpaddr) == 0) ) return(tx.vout[v].nValue); } return(0); } -bool PaymentsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) -{ - static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) - { - //fprintf(stderr,"vini.%d check mempool\n",i); - if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - //fprintf(stderr,"vini.%d check hash and vout\n",i); - if ( hashBlock == zerohash ) - return eval->Invalid("cant Payments from mempool"); - if ( (assetoshis= IsPaymentsvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) - inputs += assetoshis; - } - } - } - for (i=0; iInvalid("mismatched inputs != outputs + txfee"); - } - else return(true); -} - bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; - return eval->Invalid("no validation yet"); - std::vector > txids; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - preventCCvins = preventCCvouts = -1; - if ( numvouts < 1 ) - return eval->Invalid("no vouts"); - else - { - for (i=0; iInvalid("illegal normal vini"); - } - } - //fprintf(stderr,"check amounts\n"); - if ( PaymentsExactAmounts(cp,eval,tx,1,10000) == false ) - { - fprintf(stderr,"Paymentsget invalid amount\n"); - return false; - } - else - { - txid = tx.GetHash(); - memcpy(hash,&txid,sizeof(hash)); - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); - if ( retval != 0 ) - fprintf(stderr,"Paymentsget validated\n"); - else fprintf(stderr,"Paymentsget invalid\n"); - return(retval); - } - } + // one of two addresses + // change must go to 1of2 txidaddr + // only 'F' or 1of2 txidaddr can be spent + // all vouts must match exactly + return(true); } // end of consensus code // helper functions for rpc calls in rpcwallet.cpp -int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) +int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey txidpk,int64_t total,int32_t maxinputs,uint256 createtxid,int32_t latestheight) { - // add threshold check - char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; + char coinaddr[64]; CPubKey Paymentspk; int64_t nValue,threshold,price,totalinputs = 0; uint256 txid,checktxid,hashBlock; std::vector origpubkey; CTransaction vintx,tx; int32_t iter,vout,ht,n = 0; std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; + if ( maxinputs > 0 ) + threshold = total/maxinputs; + else threshold = total; + Paymentspk = GetUnspendable(cp,0); + for (iter=0; iter<2; iter++) { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - // no need to prevent dup - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + if ( iter == 0 ) + GetCCaddress(cp,coinaddr,Paymentspk); + else GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk); + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { - if ( (nValue= IsPaymentsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) + 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 && GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( total != 0 && maxinputs != 0 ) - mtx.vin.push_back(CTxIn(txid,vout,CScript())); - nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; + if ( latestheight != 0 ) + { + if ( (ht= komodo_blockheight(hashBlock)) == 0 ) + { + fprintf(stderr,"null ht\n"); + continue; + } + else if ( ht > latestheight ) + { + fprintf(stderr,"ht.%d > lastheight.%d\n",ht,latestheight); + continue; + } + } + if ( iter == 0 ) + { + std::vector scriptPubKey,opret; + if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() < 2 || DecodePaymentsFundOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,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)) > PAYMENTS_TXFEE && nValue >= threshold && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) + { + if ( total != 0 && maxinputs != 0 ) + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + nValue = it->second.satoshis; + totalinputs += nValue; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) + break; + } //else fprintf(stderr,"nValue %.8f vs threshold %.8f\n",(double)nValue/COIN,(double)threshold/COIN); } } } return(totalinputs); } -std::string PaymentsGet(uint64_t txfee,int64_t nValue) +UniValue payments_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag) { - CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,Paymentspk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; - cp = CCinit(&C,EVAL_PAYMENTS); - if ( txfee == 0 ) - txfee = 10000; - Paymentspk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - if ( (inputs= AddPaymentsInputs(cp,mtx,Paymentspk,nValue+txfee,60)) > 0 ) + CTransaction tx; + if ( rawtx.size() > 0 ) { - if ( inputs > nValue ) - CCchange = (inputs - nValue - txfee); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,CCchange,Paymentspk)); - mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - fprintf(stderr,"start at %u\n",(uint32_t)time(NULL)); - j = rand() & 0xfffffff; - for (i=0; i<1000000; i++,j++) + result.push_back(Pair("hex",rawtx)); + if ( DecodeHexTx(tx,rawtx) != 0 ) { - tmpmtx = mtx; - rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_PAYMENTS << (uint8_t)'G' << j)); - if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 ) - { - len >>= 1; - decode_hex(buf,len,(char *)rawhex.c_str()); - hash = bits256_doublesha256(0,buf,len); - if ( (hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0 ) - { - fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL)); - return(rawhex); - } - //fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]); - } - } - fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL)); - return(""); - } else fprintf(stderr,"cant find Payments inputs\n"); - return(""); -} - -std::string PaymentsFund(uint64_t txfee,int64_t funds) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,Paymentspk; CScript opret; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_PAYMENTS); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - Paymentspk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,funds,Paymentspk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); - } - return(""); -} - -UniValue PaymentsInfo() -{ - UniValue result(UniValue::VOBJ); char numstr[64]; - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey Paymentspk; struct CCcontract_info *cp,C; int64_t funding; - result.push_back(Pair("result","success")); - result.push_back(Pair("name","Payments")); - cp = CCinit(&C,EVAL_PAYMENTS); - Paymentspk = GetUnspendable(cp,0); - funding = AddPaymentsInputs(cp,mtx,Paymentspk,0,0); - sprintf(numstr,"%.8f",(double)funding/COIN); - result.push_back(Pair("funding",numstr)); + if ( broadcastflag != 0 && myAddtomempool(tx) != 0 ) + RelayTransaction(tx); + result.push_back(Pair("txid",tx.GetHash().ToString())); + result.push_back(Pair("result","success")); + } else result.push_back(Pair("error","decode hex")); + } else result.push_back(Pair("error","couldnt finalize payments CCtx")); return(result); } +cJSON *payments_reparse(int32_t *nump,char *jsonstr) +{ + cJSON *params; char *newstr; int32_t i,j; + *nump = 0; + if ( jsonstr != 0 ) + { + if ( jsonstr[0] == '"' && jsonstr[strlen(jsonstr)-1] == '"' ) + { + jsonstr[strlen(jsonstr)-1] = 0; + jsonstr++; + } + newstr = (char *)malloc(strlen(jsonstr)+1); + for (i=j=0; jsonstr[i]!=0; i++) + { + if ( jsonstr[i] == '%' && jsonstr[i+1] == '2' && jsonstr[i+2] == '2' ) + { + newstr[j++] = '"'; + i += 2; + } + else if ( jsonstr[i] == '\'' ) + newstr[j++] = '"'; + else newstr[j++] = jsonstr[i]; + } + newstr[j] = 0; + params = cJSON_Parse(newstr); + if ( 0 && params != 0 ) + printf("new.(%s) -> %s\n",newstr,jprint(params,0)); + free(newstr); + *nump = cJSON_GetArraySize(params); + } else params = 0; + return(params); +} + +uint256 payments_juint256(cJSON *obj) +{ + uint256 tmp; bits256 t = jbits256(obj,0); + memcpy(&tmp,&t,sizeof(tmp)); + return(revuint256(tmp)); +} + +int32_t payments_parsehexdata(std::vector &hexdata,cJSON *item,int32_t len) +{ + char *hexstr; int32_t val; + if ( (hexstr= jstr(item,0)) != 0 && ((val= is_hexstr(hexstr,0)) == len*2 || (val > 0 && len == 0)) ) + { + val >>= 1; + hexdata.resize(val); + decode_hex(&hexdata[0],val,hexstr); + return(0); + } else return(-1); +} + +UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) +{ + int32_t latestheight,nextheight = komodo_nextheight(); + CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); UniValue result(UniValue::VOBJ); uint256 createtxid,hashBlock; + CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,numoprets=0,lockedblocks,minrelease,totalallocations,checkallocations=0,allocation; int64_t inputsum,amount,CCchange=0; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector txidoprets; std::string rawtx; + cJSON *params = payments_reparse(&n,jsonstr); + mypk = pubkey2pk(Mypubkey()); + Paymentspk = GetUnspendable(cp,0); + if ( params != 0 && n == 2 ) + { + createtxid = payments_juint256(jitem(params,0)); + amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049; + if ( myGetTransaction(createtxid,tx,hashBlock) != 0 ) + { + if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 ) + { + if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","negative parameter")); + return(result); + } + latestheight = (nextheight - lockedblocks - 1); + if ( amount < minrelease ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","amount too smal")); + result.push_back(Pair("amount",ValueFromAmount(amount))); + result.push_back(Pair("minrelease",ValueFromAmount(minrelease))); + return(result); + } + for (i=0; i scriptPubKey,opret; + vout.nValue = 0; + if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) + { + vout.nValue = allocation; + vout.scriptPubKey.resize(scriptPubKey.size()); + memcpy(&vout.scriptPubKey[0],&scriptPubKey[0],scriptPubKey.size()); + checkallocations += allocation; + if ( opret.size() > 0 ) + { + scriptPubKey.resize(opret.size()); + memcpy(&onlyopret[0],&opret[0],opret.size()); + numoprets++; + } + } else break; + mtx.vout.push_back(vout); + } + if ( i != txidoprets.size() ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid txidoprets[i]")); + result.push_back(Pair("txi",(int64_t)i)); + if ( params != 0 ) + free_json(params); + return(result); + } + else if ( checkallocations != totalallocations ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","totalallocations mismatch")); + result.push_back(Pair("checkallocations",(int64_t)checkallocations)); + result.push_back(Pair("totalallocations",(int64_t)totalallocations)); + if ( params != 0 ) + free_json(params); + return(result); + } + else if ( numoprets > 1 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","too many oprets")); + result.push_back(Pair("numoprets",(int64_t)numoprets)); + if ( params != 0 ) + free_json(params); + return(result); + } + for (i=0; i= amount ) + { + if ( (CCchange= (inputsum - amount)) >= PAYMENTS_TXFEE ) + mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,CCchange,Paymentspk,txidpk)); + GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk); + CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,onlyopret); + if ( params != 0 ) + free_json(params); + return(payments_rawtxresult(result,rawtx,0)); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt find enough locked funds")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt decode paymentscreate txid opret")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt find paymentscreate txid")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","parameters error")); + } + if ( params != 0 ) + free_json(params); + return(result); +} + +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; CScript opret; CTransaction tx; char txidaddr[64]; std::string rawtx; int32_t n,useopret = 0,lockedblocks,minrelease,totalallocations; std::vector txidoprets; + cJSON *params = payments_reparse(&n,jsonstr); + mypk = pubkey2pk(Mypubkey()); + Paymentspk = GetUnspendable(cp,0); + if ( params != 0 && n > 1 && n <= 3 ) + { + 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 ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() == 1 || DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid createtxid")); + } + else if ( AddNormalinputs(mtx,mypk,amount+PAYMENTS_TXFEE,60) > 0 ) + { + if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","negative parameter")); + if ( params != 0 ) + free_json(params); + return(result); + } + if ( useopret == 0 ) + { + txidpk = CCtxidaddr(txidaddr,txid); + mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,amount,Paymentspk,txidpk)); + } + else + { + mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk)); + opret = EncodePaymentsFundOpRet(txid); + } + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,opret); + if ( params != 0 ) + free_json(params); + return(payments_rawtxresult(result,rawtx,1)); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt find enough funds")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","parameters error")); + } + if ( params != 0 ) + free_json(params); + return(result); +} + +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 allocation,n,retval0,retval1=0; + cJSON *params = payments_reparse(&n,jsonstr); + mypk = pubkey2pk(Mypubkey()); + if ( params != 0 && n > 1 && n <= 3 ) + { + allocation = juint(jitem(params,0),0); + retval0 = payments_parsehexdata(scriptPubKey,jitem(params,1),0); + if ( n == 3 ) + retval1 = payments_parsehexdata(opret,jitem(params,2),0); + if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE,10) > 0 ) + { + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret)); + if ( params != 0 ) + free_json(params); + return(payments_rawtxresult(result,rawtx,1)); + } + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid params or cant find txfee")); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","parameters error")); + result.push_back(Pair("n",(int64_t)n)); + fprintf(stderr,"(%s) %p\n",jsonstr,params); + } + if ( params != 0 ) + free_json(params); + return(result); +} + +UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); CTransaction tx; CPubKey Paymentspk,mypk; char markeraddr[64]; std::vector txidoprets; uint256 hashBlock; int32_t i,n,numoprets=0,lockedblocks,minrelease,totalallocations=0; std::string rawtx; + cJSON *params = payments_reparse(&n,jsonstr); + if ( params != 0 && n >= 4 ) + { + lockedblocks = juint(jitem(params,0),0); + minrelease = juint(jitem(params,1),0); + if ( lockedblocks < 0 || minrelease < 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","negative parameter")); + if ( params != 0 ) + free_json(params); + return(result); + } + for (i=0; i scriptPubKey,opret; int32_t allocation; + 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; + if ( opret.size() > 0 ) + numoprets++; + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid txidopret")); + result.push_back(Pair("txid",txidoprets[i].GetHex())); + result.push_back(Pair("txi",(int64_t)i)); + if ( params != 0 ) + free_json(params); + return(result); + } + } + if ( numoprets > 1 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","too many opreturns")); + result.push_back(Pair("numoprets",(int64_t)numoprets)); + if ( params != 0 ) + free_json(params); + return(result); + } + mypk = pubkey2pk(Mypubkey()); + Paymentspk = GetUnspendable(cp,0); + if ( AddNormalinputs(mtx,mypk,2*PAYMENTS_TXFEE,60) > 0 ) + { + mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,PAYMENTS_TXFEE,Paymentspk,Paymentspk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsOpRet(lockedblocks,minrelease,totalallocations,txidoprets)); + if ( params != 0 ) + free_json(params); + return(payments_rawtxresult(result,rawtx,1)); + } + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough normal funds")); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","parameters error")); + } + if ( params != 0 ) + free_json(params); + return(result); +} + +UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) +{ + UniValue result(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx,txO; CPubKey Paymentspk,txidpk; int32_t i,j,n,flag=0,allocation,numoprets=0,lockedblocks,minrelease,totalallocations; std::vector txidoprets; int64_t funds,fundsopret; char fundsaddr[64],fundsopretaddr[64],txidaddr[64],*outstr; uint256 createtxid,hashBlock; + cJSON *params = payments_reparse(&n,jsonstr); + if ( params != 0 && n == 1 ) + { + Paymentspk = GetUnspendable(cp,0); + createtxid = payments_juint256(jitem(params,0)); + if ( myGetTransaction(createtxid,tx,hashBlock) != 0 ) + { + if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 ) + { + if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","negative parameter")); + if ( params != 0 ) + free_json(params); + return(result); + } + result.push_back(Pair("lockedblocks",(int64_t)lockedblocks)); + result.push_back(Pair("totalallocations",(int64_t)totalallocations)); + result.push_back(Pair("minrelease",(int64_t)minrelease)); + for (i=0; i scriptPubKey,opret; + obj.push_back(Pair("txidopret",txidoprets[i].GetHex())); + if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) + { + outstr = (char *)malloc(scriptPubKey.size() + opret.size() + 1); + for (j=0; j 1 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","too many opreturns")); + result.push_back(Pair("numoprets",(int64_t)numoprets)); + } + else + { + txidpk = CCtxidaddr(txidaddr,createtxid); + GetCCaddress1of2(cp,fundsaddr,Paymentspk,txidpk); + funds = CCaddress_balance(fundsaddr); + result.push_back(Pair(fundsaddr,ValueFromAmount(funds))); + GetCCaddress(cp,fundsopretaddr,Paymentspk); + fundsopret = CCaddress_balance(fundsopretaddr); + result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret))); + result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret))); + result.push_back(Pair("result","success")); + } + } + } + if ( flag == 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt find valid payments create txid")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","parameters error")); + } + if ( params != 0 ) + free_json(params); + return(result); +} + +UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr) +{ + std::vector > addressIndex; uint256 txid,hashBlock; + UniValue result(UniValue::VOBJ),a(UniValue::VARR); char markeraddr[64],str[65]; CPubKey Paymentspk; CTransaction tx; int32_t lockedblocks,minrelease,totalallocations; std::vector txidoprets; + Paymentspk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,markeraddr,Paymentspk,Paymentspk); + SetCCtxids(addressIndex,markeraddr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + { + txid = it->first.txhash; + if ( it->first.index == 0 && myGetTransaction(txid,tx,hashBlock) != 0 ) + { + if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 'C' ) + { + if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","negative parameter")); + return(result); + } + a.push_back(uint256_str(str,txid)); + } + } + } + result.push_back(Pair("result","success")); + result.push_back(Pair("createtxids",a)); + return(result); +} diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index 07f20f833..c53207562 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -334,7 +334,7 @@ std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingt std::vector voutTokenPubkeysEmpty; //TODO: add token vout pubkeys return(FinalizeCCTx(0,cp,mtx,mypk,txfee, EncodeTokenOpRet(bettoken, voutTokenPubkeysEmpty, - EncodeAssetOpRet('t',/*bettoken,*/zeroid, 0, Mypubkey())))); + std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('t',/*bettoken,*/zeroid, 0, Mypubkey()))))); } else { diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index c201869b0..1351bbaeb 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -333,7 +333,11 @@ int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcont std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); - threshold = total/(maxinputs+1); + if ( maxinputs > CC_MAXVINS ) + maxinputs = CC_MAXVINS; + if ( maxinputs > 0 ) + threshold = total/maxinputs; + else threshold = total; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; diff --git a/src/cc/rogue/Makefile_win b/src/cc/rogue/Makefile_win index 6e558960c..e5a36d9b4 100644 --- a/src/cc/rogue/Makefile_win +++ b/src/cc/rogue/Makefile_win @@ -26,10 +26,10 @@ O=o CC = x86_64-w64-mingw32-gcc #CFLAGS=-O2 -CFLAGS= -g -O2 -I./ncurses/include -I./ncurses/include/ncursesw -I../../../depends/x86_64-w64-mingw32/include +CFLAGS= -g -O2 -I./x86_64-w64-mingw32/include -I./x86_64-w64-mingw32/include/ncursesw #LIBS=-lcurses -LIBS = -L./ncurses/lib -lncursesw -lcurl +LIBS = -L./x86_64-w64-mingw32/lib -lncursesw -lcurl #RM=rm -f RM = rm -f diff --git a/src/cc/rogue/command.c b/src/cc/rogue/command.c index 54d7beb99..568f4b8f8 100644 --- a/src/cc/rogue/command.c +++ b/src/cc/rogue/command.c @@ -25,7 +25,6 @@ command(struct rogue_state *rs) char *fp; THING *mp; static char countch, direction, newcount = FALSE; - if (on(player, ISHASTE)) ntimes++; /* @@ -345,7 +344,7 @@ over: if (wizard) { wizard = FALSE; - turn_see(TRUE); + turn_see(rs,TRUE); msg(rs,"not wizard any more"); } else @@ -354,7 +353,7 @@ over: if (wizard) { noscore = TRUE; - turn_see(FALSE); + turn_see(rs,FALSE); msg(rs,"you are suddenly as smart as Ken Arnold in dungeon #%d", dnum); } else @@ -404,7 +403,7 @@ over: when CTRL('T'): teleport(); when CTRL('E'): msg(rs,"food left: %d", food_left); when CTRL('C'): add_pass(); - when CTRL('X'): turn_see(on(player, SEEMONST)); + when CTRL('X'): turn_see(rs,on(player, SEEMONST)); when CTRL('~'): { THING *item; @@ -456,7 +455,7 @@ over: if (!running) door_stop = FALSE; } - /* +/* * If he ran into something to take, let him pick it up. */ if (take != 0) diff --git a/src/cc/rogue/daemon.c b/src/cc/rogue/daemon.c index 1da06d499..81bdd0a73 100644 --- a/src/cc/rogue/daemon.c +++ b/src/cc/rogue/daemon.c @@ -160,10 +160,43 @@ extinguish(void (*func)(struct rogue_state *rs,int)) * do_fuses: * Decrement counters and start needed fuses */ + +/*char *actionfunc_str(char *str,void *ptr) +{ + if ( ptr == (void *)runners ) + strcpy(str,"runners"); + else if ( ptr == (void *)doctor ) + strcpy(str,"doctor"); + else if ( ptr == (void *)stomach ) + strcpy(str,"stomach"); + else if ( ptr == (void *)nohaste ) + strcpy(str,"nohaste"); + else if ( ptr == (void *)unconfuse ) + strcpy(str,"unconfuse"); + else if ( ptr == (void *)swander ) + strcpy(str,"swander"); + else if ( ptr == (void *)come_down ) + strcpy(str,"come_down"); + else if ( ptr == (void *)unsee ) + strcpy(str,"unsee"); + else if ( ptr == (void *)sight ) + strcpy(str,"sight"); + else if ( ptr == (void *)land ) + strcpy(str,"land"); + else if ( ptr == (void *)rollwand ) + strcpy(str,"rollwand"); + else if ( ptr == (void *)visuals ) + strcpy(str,"visuals"); + else if ( ptr == (void *)turn_see ) + strcpy(str,"turn_see"); + else strcpy(str,"no match"); + return(str); +}*/ + void do_fuses(struct rogue_state *rs,int flag) { - register struct delayed_action *wire; + register struct delayed_action *wire; char str[64]; /* * Step though the list @@ -175,6 +208,8 @@ do_fuses(struct rogue_state *rs,int flag) */ if (flag == wire->d_type && wire->d_time > 0 && --wire->d_time == 0) { + //if ( fp != 0 ) + // fprintf(fp,"t.%d %d %s, ",wire->d_type,wire->d_time,actionfunc_str(str,wire->d_func)); wire->d_type = EMPTY; (*wire->d_func)(rs,wire->d_arg); } diff --git a/src/cc/rogue/daemons.c b/src/cc/rogue/daemons.c index 42e685320..c9c16448d 100644 --- a/src/cc/rogue/daemons.c +++ b/src/cc/rogue/daemons.c @@ -21,6 +21,8 @@ void doctor(struct rogue_state *rs,int arg) { register int lv, ohp; + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"doctor\n"); lv = pstats.s_lvl; ohp = pstats.s_hpt; @@ -52,6 +54,8 @@ doctor(struct rogue_state *rs,int arg) void swander(struct rogue_state *rs,int arg) { + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"swander\n"); start_daemon(rollwand, 0, BEFORE); } @@ -63,6 +67,8 @@ int between = 0; void rollwand(struct rogue_state *rs,int arg) { + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"rollwand\n"); if (++between >= 4) { if (roll(1, 6) == 4) @@ -82,6 +88,8 @@ rollwand(struct rogue_state *rs,int arg) void unconfuse(struct rogue_state *rs,int arg) { + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"unconfuse\n"); player.t_flags &= ~ISHUH; msg(rs,"you feel less %s now", choose_str("trippy", "confused")); } @@ -94,6 +102,8 @@ void unsee(struct rogue_state *rs,int arg) { register THING *th; + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"unsee\n"); for (th = mlist; th != NULL; th = next(th)) if (on(*th, ISINVIS) && see_monst(th)) @@ -108,6 +118,8 @@ unsee(struct rogue_state *rs,int arg) void sight(struct rogue_state *rs,int arg) { + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"sight\n"); if (on(player, ISBLIND)) { extinguish(sight); @@ -126,6 +138,8 @@ sight(struct rogue_state *rs,int arg) void nohaste(struct rogue_state *rs,int arg) { + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"nohaste\n"); player.t_flags &= ~ISHASTE; msg(rs,"you feel yourself slowing down"); } @@ -139,6 +153,8 @@ stomach(struct rogue_state *rs,int arg) { register int oldfood; int orig_hungry = hungry_state; + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"stomach\n"); if (food_left <= 0) { @@ -194,41 +210,43 @@ come_down(struct rogue_state *rs,int arg) { register THING *tp; register bool seemonst; - + + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"come_down\n"); if (!on(player, ISHALU)) - return; - + return; + kill_daemon(visuals); player.t_flags &= ~ISHALU; - + if (on(player, ISBLIND)) - return; - + return; + /* * undo the things */ for (tp = lvl_obj; tp != NULL; tp = next(tp)) - if (cansee(rs,tp->o_pos.y, tp->o_pos.x)) - mvaddch(tp->o_pos.y, tp->o_pos.x, tp->o_type); - + if (cansee(rs,tp->o_pos.y, tp->o_pos.x)) + mvaddch(tp->o_pos.y, tp->o_pos.x, tp->o_type); + /* * undo the monsters */ seemonst = on(player, SEEMONST); for (tp = mlist; tp != NULL; tp = next(tp)) { - move(tp->t_pos.y, tp->t_pos.x); - if (cansee(rs,tp->t_pos.y, tp->t_pos.x)) - if (!on(*tp, ISINVIS) || on(player, CANSEE)) - addch(tp->t_disguise); - else - addch(chat(tp->t_pos.y, tp->t_pos.x)); - else if (seemonst) - { - standout(); - addch(tp->t_type); - standend(); - } + move(tp->t_pos.y, tp->t_pos.x); + if (cansee(rs,tp->t_pos.y, tp->t_pos.x)) + if (!on(*tp, ISINVIS) || on(player, CANSEE)) + addch(tp->t_disguise); + else + addch(chat(tp->t_pos.y, tp->t_pos.x)); + else if (seemonst) + { + standout(); + addch(tp->t_type); + standend(); + } } msg(rs,"Everything looks SO boring now."); } @@ -242,42 +260,44 @@ visuals(struct rogue_state *rs,int arg) { register THING *tp; register bool seemonst; - + if (!after || (running && jump)) - return; + return; + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"visuals\n"); /* * change the things */ for (tp = lvl_obj; tp != NULL; tp = next(tp)) - if (cansee(rs,tp->o_pos.y, tp->o_pos.x)) - mvaddch(tp->o_pos.y, tp->o_pos.x, rnd_thing()); - + if (cansee(rs,tp->o_pos.y, tp->o_pos.x)) + mvaddch(tp->o_pos.y, tp->o_pos.x, rnd_thing()); + /* * change the stairs */ if (!seenstairs && cansee(rs,stairs.y, stairs.x)) - mvaddch(stairs.y, stairs.x, rnd_thing()); - + mvaddch(stairs.y, stairs.x, rnd_thing()); + /* * change the monsters */ seemonst = on(player, SEEMONST); for (tp = mlist; tp != NULL; tp = next(tp)) { - move(tp->t_pos.y, tp->t_pos.x); - if (see_monst(tp)) - { - if (tp->t_type == 'X' && tp->t_disguise != 'X') - addch(rnd_thing()); - else - addch(rnd(26) + 'A'); - } - else if (seemonst) - { - standout(); - addch(rnd(26) + 'A'); - standend(); - } + move(tp->t_pos.y, tp->t_pos.x); + if (see_monst(tp)) + { + if (tp->t_type == 'X' && tp->t_disguise != 'X') + addch(rnd_thing()); + else + addch(rnd(26) + 'A'); + } + else if (seemonst) + { + standout(); + addch(rnd(26) + 'A'); + standend(); + } } } @@ -288,7 +308,54 @@ visuals(struct rogue_state *rs,int arg) void land(struct rogue_state *rs,int arg) { + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"land\n"); player.t_flags &= ~ISLEVIT; msg(rs,choose_str("bummer! You've hit the ground", "you float gently to the ground")); } + +/* + * turn_see: + * Put on or off seeing monsters on this level + */ +bool +turn_see(struct rogue_state *rs,bool turn_off) +{ + THING *mp; + bool can_see, add_new; + if ( rs->logfp != 0 ) + fprintf(rs->logfp,"turn_see\n"); + + add_new = FALSE; + for (mp = mlist; mp != NULL; mp = next(mp)) + { + move(mp->t_pos.y, mp->t_pos.x); + can_see = see_monst(mp); + if (turn_off) + { + if (!can_see) + addch(mp->t_oldch); + } + else + { + if (!can_see) + standout(); + if (!on(player, ISHALU)) + addch(mp->t_type); + else + addch(rnd(26) + 'A'); + if (!can_see) + { + standend(); + add_new ^= 1;//add_new++; + } + } + } + if (turn_off) + player.t_flags &= ~SEEMONST; + else + player.t_flags |= SEEMONST; + return add_new; +} + diff --git a/src/cc/rogue/extern.h b/src/cc/rogue/extern.h index 7fba842f3..c62646b67 100644 --- a/src/cc/rogue/extern.h +++ b/src/cc/rogue/extern.h @@ -107,6 +107,12 @@ #include #include +#ifdef _WIN32 +#ifdef _MSC_VER +#include +#endif +#endif + #undef SIGTSTP #define MAXSTR 1024 /* maximum length of strings */ @@ -142,7 +148,8 @@ void leave(int); void my_exit(int st); void playltchars(void); void quit(int); -int32_t _quit(); +int32_t _quit(); + void resetltchars(void); void set_order(int *order, int numthings); void tstp(int ignored); diff --git a/src/cc/rogue/fight.c b/src/cc/rogue/fight.c index 43474616e..9cb4bf61e 100644 --- a/src/cc/rogue/fight.c +++ b/src/cc/rogue/fight.c @@ -290,27 +290,27 @@ attack(struct rogue_state *rs,THING *mp) } when 'N': { - register THING *obj, *steal; - register int nobj; - - /* - * Nymph's steal a magic item, look through the pack - * and pick out one we like. - */ - steal = NULL; - for (nobj = 0, obj = pack; obj != NULL; obj = next(obj)) - if (obj != cur_armor && obj != cur_weapon - && obj != cur_ring[LEFT] && obj != cur_ring[RIGHT] - && is_magic(obj) && rnd(++nobj) == 0) - steal = obj; - if (steal != NULL) - { - remove_mon(rs,&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE); - mp=NULL; - leave_pack(rs,steal, FALSE, FALSE); - msg(rs,"she stole %s!", inv_name(steal, TRUE)); - discard(steal); - } + THING *obj, *steal; int nobj; + + /* + * Nymph's steal a magic item, look through the pack + * and pick out one we like. + */ + steal = NULL; + for (nobj = 0, obj = pack; obj != NULL; obj = next(obj)) + if (obj != cur_armor && obj != cur_weapon + && obj != cur_ring[LEFT] && obj != cur_ring[RIGHT] + && is_magic(obj) && rnd(++nobj) == 0) + steal = obj; + if (steal != NULL) + { + remove_mon(rs,&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE); + mp=NULL; + leave_pack(rs,steal, FALSE, FALSE); + msg(rs,"she stole %s!", inv_name(steal, TRUE)); + if ( steal->o_count <= 0 ) + discard(steal); + } } otherwise: break; @@ -594,26 +594,24 @@ void remove_mon(struct rogue_state *rs,coord *mp, THING *tp, bool waskill) { register THING *obj, *nexti; - for (obj = tp->t_pack; obj != NULL; obj = nexti) { - nexti = next(obj); - obj->o_pos = tp->t_pos; - detach(tp->t_pack, obj); - if (waskill) - fall(rs,obj, FALSE); - else - discard(obj); + nexti = next(obj); + obj->o_pos = tp->t_pos; + detach(tp->t_pack, obj); + if (waskill) + fall(rs,obj, FALSE); + else discard(obj); } moat(mp->y, mp->x) = NULL; mvaddch(mp->y, mp->x, tp->t_oldch); detach(mlist, tp); if (on(*tp, ISTARGET)) { - kamikaze = FALSE; - to_death = FALSE; - if (fight_flush) - flush_type(); + kamikaze = FALSE; + to_death = FALSE; + if (fight_flush) + flush_type(); } discard(tp); } diff --git a/src/cc/rogue/io.c b/src/cc/rogue/io.c index 994f112e2..ad22407f6 100644 --- a/src/cc/rogue/io.c +++ b/src/cc/rogue/io.c @@ -167,7 +167,7 @@ readchar(struct rogue_state *rs) fp = fopen("log","wb"); if ( fp != 0 ) { - fprintf(fp,"%d: (%c) hp.%d\n",counter,c,pstats.s_hpt); + fprintf(fp,"%d: (%c) hp.%d num.%d gold.%d seed.%llu\n",counter,c,pstats.s_hpt,num_packitems(rs),purse,(long long)seed); fflush(fp); counter++; } diff --git a/src/cc/rogue/list.c b/src/cc/rogue/list.c index 622af60cd..a021c6a8f 100644 --- a/src/cc/rogue/list.c +++ b/src/cc/rogue/list.c @@ -19,80 +19,38 @@ int total = 0; /* total dynamic memory bytes */ #endif -/* - * detach: - * takes an item out of whatever linked list it might be in - */ - -void -_detach(THING **list, THING *item) -{ - if (*list == item) - *list = next(item); - if (prev(item) != NULL) - item->l_prev->l_next = next(item); - if (next(item) != NULL) - item->l_next->l_prev = prev(item); - item->l_next = NULL; - item->l_prev = NULL; -} - -/* - * _attach: - * add an item to the head of a list - */ - -void -_attach(THING **list, THING *item) -{ - if (*list != NULL) - { - item->l_next = *list; - (*list)->l_prev = item; - item->l_prev = NULL; - } - else - { - item->l_next = NULL; - item->l_prev = NULL; - } - *list = item; -} - -/* - * _free_list: - * Throw the whole blamed thing away - */ - -void -_free_list(THING **ptr) -{ - THING *item; - - while (*ptr != NULL) - { - item = *ptr; - *ptr = next(item); - discard(item); - } -} - /* * discard: * Free up an item */ +//#define ENABLE_DEBUG +#define MAX_DEBUGPTRS 100000 + int32_t itemcounter; -THING *thingptrs[100000]; +THING *thingptrs[MAX_DEBUGPTRS]; int32_t numptrs; +int32_t thing_find(THING *item) +{ +#ifdef ENABLE_DEBUG + int32_t i; + for (i=0; il_prev->l_next = next(item); + if (next(item) != NULL) + item->l_next->l_prev = prev(item); + item->l_next = NULL; + item->l_prev = NULL; +} + +/* + * _attach: + * add an item to the head of a list + */ + +void +_attach(THING **list, THING *item) +{ + if (*list != NULL) + { + item->l_next = *list; + (*list)->l_prev = item; + item->l_prev = NULL; + } + else + { + item->l_next = NULL; + item->l_prev = NULL; + } + *list = item; +} + +/* + * _free_list: + * Throw the whole blamed thing away + */ + +void +_free_list(THING **ptr) +{ + THING *item; + while (*ptr != NULL) + { + item = *ptr; + *ptr = next(item); + discard(item); + } +} + /* * new_item * Get a new item with a specified size @@ -139,12 +165,14 @@ new_item(void) #else item = (THING *)calloc(1, sizeof *item); #endif - if ( 0 ) +#ifdef ENABLE_DEBUG + if ( numptrs < MAX_DEBUGPTRS ) { thingptrs[numptrs++] = item; if ( (++itemcounter % 100) == 0 ) fprintf(stderr,"itemcounter.%d\n",itemcounter); } +#endif item->l_next = NULL; item->l_prev = NULL; return item; diff --git a/src/cc/rogue/main.c b/src/cc/rogue/main.c index 2daa1d0c7..f146cfb4d 100644 --- a/src/cc/rogue/main.c +++ b/src/cc/rogue/main.c @@ -38,6 +38,31 @@ union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uin typedef union _bits256 bits256; #endif +#ifdef _WIN32 +#ifdef _MSC_VER +int gettimeofday(struct timeval * tp, struct timezone * tzp) +{ + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t)file_time.dwLowDateTime); + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long)((time - EPOCH) / 10000000L); + tp->tv_usec = (long)(system_time.wMilliseconds * 1000); + return 0; +} +#endif // _MSC_VER +#endif + + + double OS_milliseconds() { struct timeval tv; double millis; @@ -235,6 +260,7 @@ int32_t safecopy(char *dest,char *src,long len) #endif int32_t rogue_replay(uint64_t seed,int32_t sleeptime); +char *rogue_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter); int rogue(int argc, char **argv, char **envp); void *OS_loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep) @@ -391,6 +417,12 @@ char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char * } #endif +#ifdef _WIN32 +#ifdef _MSC_VER +#define sleep(x) Sleep(1000*(x)) +#endif +#endif + /************************************************************************ * * perform the query @@ -708,11 +740,103 @@ char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) #include "rogue.h" -void rogue_progress(struct rogue_state *rs,uint64_t seed,char *keystrokes,int32_t num) +int32_t rogue_sendrawtransaction(char *rawtx) { - char cmd[16384],hexstr[16384],params[32768],*retstr; int32_t i; + char *params,*retstr,*hexstr; cJSON *retjson,*resobj; int32_t retval = -1; + params = (char *)malloc(strlen(rawtx) + 16); + sprintf(params,"[\"%s\"]",rawtx); + if ( (retstr= komodo_issuemethod(USERPASS,"sendrawtransaction",params,ROGUE_PORT)) != 0 ) + { + if ( 0 ) // causes 4th level crash + { + static FILE *fp; + if ( fp == 0 ) + fp = fopen("rogue.sendlog","wb"); + if ( fp != 0 ) + { + fprintf(fp,"%s\n",retstr); + fflush(fp); + } + } + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,"result")) != 0 ) + { + if ( (hexstr= jstr(resobj,0)) != 0 && is_hexstr(hexstr,64) == 64 ) + retval = 0; + } + free_json(retjson); + } + + /* log sendrawtx result in file */ + + /* + FILE *debug_file; + debug_file = fopen("tx_debug.log", "a"); + fprintf(debug_file, "%s\n", retstr); + fflush(debug_file); + fclose(debug_file); + */ + + free(retstr); + } + free(params); + return(retval); +} + +void rogue_progress(struct rogue_state *rs,int32_t waitflag,uint64_t seed,char *keystrokes,int32_t num) +{ + char cmd[16384],hexstr[16384],params[32768],*retstr,*rawtx,*pastkeys,*pastcmp,*keys; int32_t i,len,numpastkeys; cJSON *retjson,*resobj; + //fprintf(stderr,"rogue_progress num.%d\n",num); if ( rs->guiflag != 0 && Gametxidstr[0] != 0 ) { + if ( rs->keystrokeshex != 0 ) + { + if ( rogue_sendrawtransaction(rs->keystrokeshex) == 0 ) + { + if ( waitflag == 0 ) + return; + else if ( 0 ) + { + while ( rogue_sendrawtransaction(rs->keystrokeshex) == 0 ) + { + //fprintf(stderr,"pre-rebroadcast\n"); + sleep(10); + } + } + } + free(rs->keystrokeshex), rs->keystrokeshex = 0; + } + if ( 0 && (pastkeys= rogue_keystrokesload(&numpastkeys,seed,1)) != 0 ) + { + sprintf(params,"[\"extract\",\"17\",\"[%%22%s%%22]\"]",Gametxidstr); + if ( (retstr= komodo_issuemethod(USERPASS,"cclib",params,ROGUE_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,"result")) != 0 && (keys= jstr(resobj,"keystrokes")) != 0 ) + { + len = strlen(keys) / 2; + pastcmp = (char *)malloc(len + 1); + decode_hex(pastcmp,len,keys); + fprintf(stderr,"keystrokes.(%s) vs pastkeys\n",keys); + for (i=0; ikeystrokeshex != 0 ) + free(rs->keystrokeshex); + rs->keystrokeshex = (char *)malloc(strlen(rawtx)+1); + strcpy(rs->keystrokeshex,rawtx); +//fprintf(stderr,"set keystrokestx <- %s\n",rs->keystrokeshex); + } + free_json(retjson); + } free(retstr); } - sleep(1); + if ( 0 && waitflag != 0 && rs->keystrokeshex != 0 ) + { + while ( rogue_sendrawtransaction(rs->keystrokeshex) == 0 ) + { + //fprintf(stderr,"post-rebroadcast\n"); + sleep(3); + } + free(rs->keystrokeshex), rs->keystrokeshex = 0; + } } } } @@ -797,9 +941,46 @@ int32_t rogue_setplayerdata(struct rogue_state *rs,char *gametxidstr) return(retval); } +#ifdef _WIN32 +#ifdef _MSC_VER +__inline int msver(void) { + switch (_MSC_VER) { + case 1500: return 2008; + case 1600: return 2010; + case 1700: return 2012; + case 1800: return 2013; + case 1900: return 2015; + //case 1910: return 2017; + default: return (_MSC_VER / 100); + } +} + +static inline bool is_x64(void) { +#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) + return 1; +#elif defined(__amd64__) || defined(__amd64) || defined(_M_X64) || defined(_M_IA64) + return 1; +#else + return 0; +#endif +} + +#define BUILD_DATE __DATE__ " " __TIME__ +#endif // _WIN32 +#endif // _MSC_VER + int main(int argc, char **argv, char **envp) { uint64_t seed; FILE *fp = 0; int32_t i,j,c; char userpass[8192]; + + #ifdef _WIN32 + #ifdef _MSC_VER + printf("*** rogue for Windows [ Build %s ] ***\n", BUILD_DATE); + const char* arch = is_x64() ? "64-bits" : "32-bits"; + printf(" Built with VC++ %d (%ld) %s\n\n", msver(), _MSC_FULL_VER, arch); + #endif + #endif + for (i=j=0; argv[0][i]!=0&&j max_level) max_level = level; @@ -74,7 +84,7 @@ new_level(struct rogue_state *rs) */ do { - find_floor((struct room *) NULL, &stairs, FALSE, FALSE); + find_floor(rs,(struct room *) NULL, &stairs, FALSE, FALSE); } while (chat(stairs.y, stairs.x) != FLOOR); sp = &flat(stairs.y, stairs.x); *sp &= ~F_REAL; @@ -84,18 +94,18 @@ new_level(struct rogue_state *rs) /* * Place the staircase down. */ - find_floor((struct room *) NULL, &stairs, FALSE, FALSE); + find_floor(rs,(struct room *) NULL, &stairs, FALSE, FALSE); chat(stairs.y, stairs.x) = STAIRS; seenstairs = FALSE; for (tp = mlist; tp != NULL; tp = next(tp)) tp->t_room = roomin(rs,&tp->t_pos); - find_floor((struct room *) NULL, &hero, FALSE, TRUE); + find_floor(rs,(struct room *) NULL, &hero, FALSE, TRUE); enter_room(rs,&hero); mvaddch(hero.y, hero.x, PLAYER); if (on(player, SEEMONST)) - turn_see(FALSE); + turn_see(rs,FALSE); if (on(player, ISHALU)) visuals(rs,0); } @@ -153,7 +163,7 @@ put_things(struct rogue_state *rs) /* * Put it somewhere */ - find_floor((struct room *) NULL, &obj->o_pos, FALSE, FALSE); + find_floor(rs,(struct room *) NULL, &obj->o_pos, FALSE, FALSE); chat(obj->o_pos.y, obj->o_pos.x) = (char) obj->o_type; } /* @@ -173,7 +183,7 @@ put_things(struct rogue_state *rs) /* * Put it somewhere */ - find_floor((struct room *) NULL, &obj->o_pos, FALSE, FALSE); + find_floor(rs,(struct room *) NULL, &obj->o_pos, FALSE, FALSE); chat(obj->o_pos.y, obj->o_pos.x) = AMULET; } } @@ -201,7 +211,7 @@ treas_room(struct rogue_state *rs) num_monst = nm = rnd(spots) + MINTREAS; while (nm--) { - find_floor(rp, &mp, 2 * MAXTRIES, FALSE); + find_floor(rs,rp, &mp, 2 * MAXTRIES, FALSE); //fprintf(stderr,"treas_room\n"); tp = new_thing(rs); tp->o_pos = mp; @@ -222,7 +232,7 @@ treas_room(struct rogue_state *rs) while (nm--) { spots = 0; - if (find_floor(rp, &mp, MAXTRIES, TRUE)) + if (find_floor(rs,rp, &mp, MAXTRIES, TRUE)) { tp = new_item(); new_monster(rs,tp, randmonster(FALSE), &mp); diff --git a/src/cc/rogue/pack.c b/src/cc/rogue/pack.c index 776669b3b..1f2f3faaa 100644 --- a/src/cc/rogue/pack.c +++ b/src/cc/rogue/pack.c @@ -163,6 +163,11 @@ int32_t num_packitems(struct rogue_state *rs) int32_t type = 0,n = 0,total = 0; for (; list != NULL; list = next(list)) { + if ( thing_find(list) < 0 ) + { + fprintf(stderr,"num_packitems cant find %p\n",list); + return(-1); + } if ( list->o_packch != 0 ) { n++; @@ -219,29 +224,29 @@ THING * leave_pack(struct rogue_state *rs,THING *obj, bool newobj, bool all) { THING *nobj; - + inpack--; nobj = obj; if (obj->o_count > 1 && !all) { - last_pick = obj; - obj->o_count--; - if (obj->o_group) - inpack++; - if (newobj) - { - nobj = new_item(); - *nobj = *obj; - next(nobj) = NULL; - prev(nobj) = NULL; - nobj->o_count = 1; - } + last_pick = obj; + obj->o_count--; + if (obj->o_group) + inpack++; + if (newobj) + { + nobj = new_item(); + *nobj = *obj; + next(nobj) = NULL; + prev(nobj) = NULL; + nobj->o_count = 1; + } } else { - last_pick = NULL; - pack_used[obj->o_packch - 'a'] = FALSE; - detach(pack, obj); + last_pick = NULL; + pack_used[obj->o_packch - 'a'] = FALSE; + detach(pack, obj); } return nobj; } @@ -422,6 +427,8 @@ get_item(struct rogue_state *rs,char *purpose, int type) { for (;;) { + if ( rs->replaydone != 0 ) + return(NULL); if (!terse) addmsg(rs,"which object do you want to "); addmsg(rs,purpose); @@ -464,7 +471,9 @@ get_item(struct rogue_state *rs,char *purpose, int type) return NULL; } else + { return obj; + } } } return NULL; diff --git a/src/cc/rogue/passages.c b/src/cc/rogue/passages.c index 5437f4972..606d1a658 100644 --- a/src/cc/rogue/passages.c +++ b/src/cc/rogue/passages.c @@ -27,31 +27,31 @@ do_passages(struct rogue_state *rs) int roomcount; static struct rdes { - bool conn[MAXROOMS]; /* possible to connect to room i? */ - bool isconn[MAXROOMS]; /* connection been made to room i? */ - bool ingraph; /* this room in graph already? */ + bool conn[MAXROOMS]; /* possible to connect to room i? */ + bool isconn[MAXROOMS]; /* connection been made to room i? */ + bool ingraph; /* this room in graph already? */ } rdes[MAXROOMS] = { - { { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, - { { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, - { { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, - { { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, - { { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, - { { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, - { { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, - { { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, - { { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, }; - + /* * reinitialize room graph description */ for (r1 = rdes; r1 <= &rdes[MAXROOMS-1]; r1++) { - for (j = 0; j < MAXROOMS; j++) - r1->isconn[j] = FALSE; - r1->ingraph = FALSE; + for (j = 0; j < MAXROOMS; j++) + r1->isconn[j] = FALSE; + r1->ingraph = FALSE; } - + /* * starting with one room, connect it to a random adjacent room and * then pick a new room to start with. @@ -61,65 +61,65 @@ do_passages(struct rogue_state *rs) r1->ingraph = TRUE; do { - /* - * find a room to connect with - */ - j = 0; - for (i = 0; i < MAXROOMS; i++) - if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0) - r2 = &rdes[i]; - /* - * if no adjacent rooms are outside the graph, pick a new room - * to look from - */ - if (j == 0) - { - do - r1 = &rdes[rnd(MAXROOMS)]; - until (r1->ingraph); - } - /* - * otherwise, connect new room to the graph, and draw a tunnel - * to it - */ - else - { - r2->ingraph = TRUE; - i = (int)(r1 - rdes); - j = (int)(r2 - rdes); - conn(rs,i, j); - r1->isconn[j] = TRUE; - r2->isconn[i] = TRUE; - roomcount++; - } + /* + * find a room to connect with + */ + j = 0; + for (i = 0; i < MAXROOMS; i++) + if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0) + r2 = &rdes[i]; + /* + * if no adjacent rooms are outside the graph, pick a new room + * to look from + */ + if (j == 0) + { + do + r1 = &rdes[rnd(MAXROOMS)]; + until (r1->ingraph); + } + /* + * otherwise, connect new room to the graph, and draw a tunnel + * to it + */ + else + { + r2->ingraph = TRUE; + i = (int)(r1 - rdes); + j = (int)(r2 - rdes); + conn(rs,i, j); + r1->isconn[j] = TRUE; + r2->isconn[i] = TRUE; + roomcount++; + } } while (roomcount < MAXROOMS); - + /* * attempt to add passages to the graph a random number of times so * that there isn't always just one unique passage through it. */ for (roomcount = rnd(5); roomcount > 0; roomcount--) { - r1 = &rdes[rnd(MAXROOMS)]; /* a random room to look from */ - /* - * find an adjacent room not already connected - */ - j = 0; - for (i = 0; i < MAXROOMS; i++) - if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0) - r2 = &rdes[i]; - /* - * if there is one, connect it and look for the next added - * passage - */ - if (j != 0) - { - i = (int)(r1 - rdes); - j = (int)(r2 - rdes); - conn(rs,i, j); - r1->isconn[j] = TRUE; - r2->isconn[i] = TRUE; - } + r1 = &rdes[rnd(MAXROOMS)]; /* a random room to look from */ + /* + * find an adjacent room not already connected + */ + j = 0; + for (i = 0; i < MAXROOMS; i++) + if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0) + r2 = &rdes[i]; + /* + * if there is one, connect it and look for the next added + * passage + */ + if (j != 0) + { + i = (int)(r1 - rdes); + j = (int)(r2 - rdes); + conn(rs,i, j); + r1->isconn[j] = TRUE; + r2->isconn[i] = TRUE; + } } passnum(); } @@ -138,22 +138,22 @@ conn(struct rogue_state *rs,int r1, int r2) int rm; char direc; static coord del, curr, turn_delta, spos, epos; - + if (r1 < r2) { - rm = r1; - if (r1 + 1 == r2) - direc = 'r'; - else - direc = 'd'; + rm = r1; + if (r1 + 1 == r2) + direc = 'r'; + else + direc = 'd'; } else { - rm = r2; - if (r2 + 1 == r1) - direc = 'r'; - else - direc = 'd'; + rm = r2; + if (r2 + 1 == r1) + direc = 'r'; + else + direc = 'd'; } rpf = &rooms[rm]; /* @@ -162,75 +162,75 @@ conn(struct rogue_state *rs,int r1, int r2) */ if (direc == 'd') { - rmt = rm + 3; /* room # of dest */ - rpt = &rooms[rmt]; /* room pointer of dest */ - del.x = 0; /* direction of move */ - del.y = 1; - spos.x = rpf->r_pos.x; /* start of move */ - spos.y = rpf->r_pos.y; - epos.x = rpt->r_pos.x; /* end of move */ - epos.y = rpt->r_pos.y; - if (!(rpf->r_flags & ISGONE)) /* if not gone pick door pos */ - do - { - spos.x = rpf->r_pos.x + rnd(rpf->r_max.x - 2) + 1; - spos.y = rpf->r_pos.y + rpf->r_max.y - 1; - } while ((rpf->r_flags&ISMAZE) && !(flat(spos.y, spos.x)&F_PASS)); - if (!(rpt->r_flags & ISGONE)) - do - { - epos.x = rpt->r_pos.x + rnd(rpt->r_max.x - 2) + 1; - } while ((rpt->r_flags&ISMAZE) && !(flat(epos.y, epos.x)&F_PASS)); - distance = abs(spos.y - epos.y) - 1; /* distance to move */ - turn_delta.y = 0; /* direction to turn */ - turn_delta.x = (spos.x < epos.x ? 1 : -1); - turn_distance = abs(spos.x - epos.x); /* how far to turn */ + rmt = rm + 3; /* room # of dest */ + rpt = &rooms[rmt]; /* room pointer of dest */ + del.x = 0; /* direction of move */ + del.y = 1; + spos.x = rpf->r_pos.x; /* start of move */ + spos.y = rpf->r_pos.y; + epos.x = rpt->r_pos.x; /* end of move */ + epos.y = rpt->r_pos.y; + if (!(rpf->r_flags & ISGONE)) /* if not gone pick door pos */ + do + { + spos.x = rpf->r_pos.x + rnd(rpf->r_max.x - 2) + 1; + spos.y = rpf->r_pos.y + rpf->r_max.y - 1; + } while ((rpf->r_flags&ISMAZE) && !(flat(spos.y, spos.x)&F_PASS)); + if (!(rpt->r_flags & ISGONE)) + do + { + epos.x = rpt->r_pos.x + rnd(rpt->r_max.x - 2) + 1; + } while ((rpt->r_flags&ISMAZE) && !(flat(epos.y, epos.x)&F_PASS)); + distance = abs(spos.y - epos.y) - 1; /* distance to move */ + turn_delta.y = 0; /* direction to turn */ + turn_delta.x = (spos.x < epos.x ? 1 : -1); + turn_distance = abs(spos.x - epos.x); /* how far to turn */ } else if (direc == 'r') /* setup for moving right */ { - rmt = rm + 1; - rpt = &rooms[rmt]; - del.x = 1; - del.y = 0; - spos.x = rpf->r_pos.x; - spos.y = rpf->r_pos.y; - epos.x = rpt->r_pos.x; - epos.y = rpt->r_pos.y; - if (!(rpf->r_flags & ISGONE)) - do - { - spos.x = rpf->r_pos.x + rpf->r_max.x - 1; - spos.y = rpf->r_pos.y + rnd(rpf->r_max.y - 2) + 1; - } while ((rpf->r_flags&ISMAZE) && !(flat(spos.y, spos.x)&F_PASS)); - if (!(rpt->r_flags & ISGONE)) - do - { - epos.y = rpt->r_pos.y + rnd(rpt->r_max.y - 2) + 1; - } while ((rpt->r_flags&ISMAZE) && !(flat(epos.y, epos.x)&F_PASS)); - distance = abs(spos.x - epos.x) - 1; - turn_delta.y = (spos.y < epos.y ? 1 : -1); - turn_delta.x = 0; - turn_distance = abs(spos.y - epos.y); + rmt = rm + 1; + rpt = &rooms[rmt]; + del.x = 1; + del.y = 0; + spos.x = rpf->r_pos.x; + spos.y = rpf->r_pos.y; + epos.x = rpt->r_pos.x; + epos.y = rpt->r_pos.y; + if (!(rpf->r_flags & ISGONE)) + do + { + spos.x = rpf->r_pos.x + rpf->r_max.x - 1; + spos.y = rpf->r_pos.y + rnd(rpf->r_max.y - 2) + 1; + } while ((rpf->r_flags&ISMAZE) && !(flat(spos.y, spos.x)&F_PASS)); + if (!(rpt->r_flags & ISGONE)) + do + { + epos.y = rpt->r_pos.y + rnd(rpt->r_max.y - 2) + 1; + } while ((rpt->r_flags&ISMAZE) && !(flat(epos.y, epos.x)&F_PASS)); + distance = abs(spos.x - epos.x) - 1; + turn_delta.y = (spos.y < epos.y ? 1 : -1); + turn_delta.x = 0; + turn_distance = abs(spos.y - epos.y); } #ifdef MASTER else - debug("error in connection tables"); + debug("error in connection tables"); #endif - + turn_spot = rnd(distance - 1) + 1; /* where turn starts */ - + /* * Draw in the doors on either side of the passage or just put #'s * if the rooms are gone. */ if (!(rpf->r_flags & ISGONE)) - door(rpf, &spos); + door(rpf, &spos); else - putpass(&spos); + putpass(&spos); if (!(rpt->r_flags & ISGONE)) - door(rpt, &epos); + door(rpt, &epos); else - putpass(&epos); + putpass(&epos); /* * Get ready to move... */ @@ -238,31 +238,31 @@ conn(struct rogue_state *rs,int r1, int r2) curr.y = spos.y; while (distance > 0) { - /* - * Move to new position - */ - curr.x += del.x; - curr.y += del.y; - /* - * Check if we are at the turn place, if so do the turn - */ - if (distance == turn_spot) - while (turn_distance--) - { - putpass(&curr); - curr.x += turn_delta.x; - curr.y += turn_delta.y; - } - /* - * Continue digging along - */ - putpass(&curr); - distance--; + /* + * Move to new position + */ + curr.x += del.x; + curr.y += del.y; + /* + * Check if we are at the turn place, if so do the turn + */ + if (distance == turn_spot) + while (turn_distance--) + { + putpass(&curr); + curr.x += turn_delta.x; + curr.y += turn_delta.y; + } + /* + * Continue digging along + */ + putpass(&curr); + distance--; } curr.x += del.x; curr.y += del.y; if (!ce(curr, epos)) - msg(rs,"warning, connectivity problem on this level"); + msg(rs,"warning, connectivity problem on this level"); } /* @@ -274,13 +274,13 @@ void putpass(coord *cp) { PLACE *pp; - + pp = INDEX(cp->y, cp->x); pp->p_flags |= F_PASS; if (rnd(10) + 1 < level && rnd(40) == 0) - pp->p_flags &= ~F_REAL; + pp->p_flags &= ~F_REAL; else - pp->p_ch = PASSAGE; + pp->p_ch = PASSAGE; } /* @@ -293,23 +293,23 @@ void door(struct room *rm, coord *cp) { PLACE *pp; - + rm->r_exit[rm->r_nexits++] = *cp; - + if (rm->r_flags & ISMAZE) - return; - + return; + pp = INDEX(cp->y, cp->x); if (rnd(10) + 1 < level && rnd(5) == 0) { - if (cp->y == rm->r_pos.y || cp->y == rm->r_pos.y + rm->r_max.y - 1) - pp->p_ch = '-'; - else - pp->p_ch = '|'; - pp->p_flags &= ~F_REAL; + if (cp->y == rm->r_pos.y || cp->y == rm->r_pos.y + rm->r_max.y - 1) + pp->p_ch = '-'; + else + pp->p_ch = '|'; + pp->p_flags &= ~F_REAL; } else - pp->p_ch = DOOR; + pp->p_ch = DOOR; } #ifdef MASTER @@ -324,31 +324,31 @@ add_pass() PLACE *pp; int y, x; char ch; - + for (y = 1; y < NUMLINES - 1; y++) - for (x = 0; x < NUMCOLS; x++) - { - pp = INDEX(y, x); - if ((pp->p_flags & F_PASS) || pp->p_ch == DOOR || - (!(pp->p_flags&F_REAL) && (pp->p_ch == '|' || pp->p_ch == '-'))) - { - ch = pp->p_ch; - if (pp->p_flags & F_PASS) - ch = PASSAGE; - pp->p_flags |= F_SEEN; - move(y, x); - if (pp->p_monst != NULL) - pp->p_monst->t_oldch = pp->p_ch; - else if (pp->p_flags & F_REAL) - addch(ch); - else - { - standout(); - addch((pp->p_flags & F_PASS) ? PASSAGE : DOOR); - standend(); - } - } - } + for (x = 0; x < NUMCOLS; x++) + { + pp = INDEX(y, x); + if ((pp->p_flags & F_PASS) || pp->p_ch == DOOR || + (!(pp->p_flags&F_REAL) && (pp->p_ch == '|' || pp->p_ch == '-'))) + { + ch = pp->p_ch; + if (pp->p_flags & F_PASS) + ch = PASSAGE; + pp->p_flags |= F_SEEN; + move(y, x); + if (pp->p_monst != NULL) + pp->p_monst->t_oldch = pp->p_ch; + else if (pp->p_flags & F_REAL) + addch(ch); + else + { + standout(); + addch((pp->p_flags & F_PASS) ? PASSAGE : DOOR); + standend(); + } + } + } } #endif @@ -365,17 +365,17 @@ passnum() { struct room *rp; int i; - + pnum = 0; newpnum = FALSE; for (rp = passages; rp < &passages[MAXPASS]; rp++) - rp->r_nexits = 0; + rp->r_nexits = 0; for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) - for (i = 0; i < rp->r_nexits; i++) - { - newpnum ^= 1;//newpnum++; - numpass(rp->r_exit[i].y, rp->r_exit[i].x); - } + for (i = 0; i < rp->r_nexits; i++) + { + newpnum ^= 1;//newpnum++; + numpass(rp->r_exit[i].y, rp->r_exit[i].x); + } } /* @@ -389,30 +389,30 @@ numpass(int y, int x) char *fp; struct room *rp; char ch; - + if (x >= NUMCOLS || x < 0 || y >= NUMLINES || y <= 0) - return; + return; fp = &flat(y, x); if (*fp & F_PNUM) - return; + return; if (newpnum) { - pnum++; - newpnum = FALSE; + pnum++; + newpnum = FALSE; } /* * check to see if it is a door or secret door, i.e., a new exit, * or a numerable type of place */ if ((ch = chat(y, x)) == DOOR || - (!(*fp & F_REAL) && (ch == '|' || ch == '-'))) + (!(*fp & F_REAL) && (ch == '|' || ch == '-'))) { - rp = &passages[pnum]; - rp->r_exit[rp->r_nexits].y = y; - rp->r_exit[rp->r_nexits++].x = x; + rp = &passages[pnum]; + rp->r_exit[rp->r_nexits].y = y; + rp->r_exit[rp->r_nexits++].x = x; } else if (!(*fp & F_PASS)) - return; + return; *fp |= pnum; /* * recurse on the surrounding places diff --git a/src/cc/rogue/potions.c b/src/cc/rogue/potions.c index 00865b5dd..2425b051f 100644 --- a/src/cc/rogue/potions.c +++ b/src/cc/rogue/potions.c @@ -78,7 +78,6 @@ quaff(struct rogue_state *rs) } if (obj == cur_weapon) cur_weapon = NULL; - /* * Calculate the effect it has on the poor guy. */ @@ -91,7 +90,7 @@ quaff(struct rogue_state *rs) do_pot(rs,P_CONFUSE, !trip); when P_POISON: pot_info[P_POISON].oi_know = TRUE; - if (ISWEARING(R_SUSTSTR)) + if (ISWEARING(R_SUSTSTR)) msg(rs,"you feel momentarily sick"); else { @@ -112,7 +111,7 @@ quaff(struct rogue_state *rs) when P_MFIND: player.t_flags |= SEEMONST; fuse((void(*)(struct rogue_state *rs,int))turn_see, TRUE, HUHDURATION, AFTER); - if (!turn_see(FALSE)) + if (!turn_see(rs,FALSE)) msg(rs,"you have a %s feeling for a moment, then it passes", choose_str("normal", "strange")); when P_TFIND: @@ -158,7 +157,7 @@ quaff(struct rogue_state *rs) if (!trip) { if (on(player, SEEMONST)) - turn_see(FALSE); + turn_see(rs,FALSE); start_daemon(visuals, 0, BEFORE); seenstairs = seen_stairs(); } @@ -220,7 +219,7 @@ quaff(struct rogue_state *rs) call_it(rs,&pot_info[obj->o_which]); if (discardit) - discard(obj); + discard(obj); return; } @@ -263,47 +262,6 @@ invis_on() mvaddch(mp->t_pos.y, mp->t_pos.x, mp->t_disguise); } -/* - * turn_see: - * Put on or off seeing monsters on this level - */ -bool -turn_see(bool turn_off) -{ - THING *mp; - bool can_see, add_new; - - add_new = FALSE; - for (mp = mlist; mp != NULL; mp = next(mp)) - { - move(mp->t_pos.y, mp->t_pos.x); - can_see = see_monst(mp); - if (turn_off) - { - if (!can_see) - addch(mp->t_oldch); - } - else - { - if (!can_see) - standout(); - if (!on(player, ISHALU)) - addch(mp->t_type); - else - addch(rnd(26) + 'A'); - if (!can_see) - { - standend(); - add_new ^= 1;//add_new++; - } - } - } - if (turn_off) - player.t_flags &= ~SEEMONST; - else - player.t_flags |= SEEMONST; - return add_new; -} /* * seen_stairs: @@ -358,18 +316,18 @@ do_pot(struct rogue_state *rs,int type, bool knowit) { PACT *pp; int t; - + pp = &p_actions[type]; if (!pot_info[type].oi_know) - pot_info[type].oi_know = knowit; + pot_info[type].oi_know = knowit; t = spread(pp->pa_time); if (!on(player, pp->pa_flags)) { - player.t_flags |= pp->pa_flags; - fuse(pp->pa_daemon, 0, t, AFTER); - look(rs,FALSE); + player.t_flags |= pp->pa_flags; + fuse(pp->pa_daemon, 0, t, AFTER); + look(rs,FALSE); } else - lengthen(pp->pa_daemon, t); + lengthen(pp->pa_daemon, t); msg(rs,choose_str(pp->pa_high, pp->pa_straight)); } diff --git a/src/cc/rogue/rings.c b/src/cc/rogue/rings.c index 747da302a..f9ce50795 100644 --- a/src/cc/rogue/rings.c +++ b/src/cc/rogue/rings.c @@ -23,65 +23,65 @@ ring_on(struct rogue_state *rs) { THING *obj; int ring; - + obj = get_item(rs,"put on", RING); /* * Make certain that it is somethings that we want to wear */ if (obj == NULL) - return; + return; if (obj->o_type != RING) { - if (!terse) - msg(rs,"it would be difficult to wrap that around a finger"); - else - msg(rs,"not a ring"); - return; + if (!terse) + msg(rs,"it would be difficult to wrap that around a finger"); + else + msg(rs,"not a ring"); + return; } - + /* * find out which hand to put it on */ if (is_current(rs,obj)) - return; - + return; + if (cur_ring[LEFT] == NULL && cur_ring[RIGHT] == NULL) { - if ((ring = gethand(rs)) < 0) - return; + if ((ring = gethand(rs)) < 0) + return; } else if (cur_ring[LEFT] == NULL) - ring = LEFT; + ring = LEFT; else if (cur_ring[RIGHT] == NULL) - ring = RIGHT; + ring = RIGHT; else { - if (!terse) - msg(rs,"you already have a ring on each hand"); - else - msg(rs,"wearing two"); - return; + if (!terse) + msg(rs,"you already have a ring on each hand"); + else + msg(rs,"wearing two"); + return; } cur_ring[ring] = obj; - + /* * Calculate the effect it has on the poor guy. */ switch (obj->o_which) { - case R_ADDSTR: - chg_str(obj->o_arm); - break; - case R_SEEINVIS: - invis_on(); - break; - case R_AGGR: - aggravate(rs); - break; + case R_ADDSTR: + chg_str(obj->o_arm); + break; + case R_SEEINVIS: + invis_on(); + break; + case R_AGGR: + aggravate(rs); + break; } - + if (!terse) - addmsg(rs,"you are now wearing "); + addmsg(rs,"you are now wearing "); msg(rs,"%s (%c)", inv_name(obj, TRUE), obj->o_packch); } @@ -95,31 +95,31 @@ ring_off(struct rogue_state *rs) { int ring; THING *obj; - + if (cur_ring[LEFT] == NULL && cur_ring[RIGHT] == NULL) { - if (terse) - msg(rs,"no rings"); - else - msg(rs,"you aren't wearing any rings"); - return; + if (terse) + msg(rs,"no rings"); + else + msg(rs,"you aren't wearing any rings"); + return; } else if (cur_ring[LEFT] == NULL) - ring = RIGHT; + ring = RIGHT; else if (cur_ring[RIGHT] == NULL) - ring = LEFT; + ring = LEFT; else - if ((ring = gethand(rs)) < 0) - return; + if ((ring = gethand(rs)) < 0) + return; mpos = 0; obj = cur_ring[ring]; if (obj == NULL) { - msg(rs,"not wearing such a ring"); - return; + msg(rs,"not wearing such a ring"); + return; } if (dropcheck(rs,obj)) - msg(rs,"was wearing %s(%c)", inv_name(obj, TRUE), obj->o_packch); + msg(rs,"was wearing %s(%c)", inv_name(obj, TRUE), obj->o_packch); } /* @@ -130,24 +130,26 @@ int gethand(struct rogue_state *rs) { int c; - + for (;;) { - if (terse) - msg(rs,"left or right ring? "); - else - msg(rs,"left hand or right hand? "); - if ((c = readchar(rs)) == ESCAPE) - return -1; - mpos = 0; - if (c == 'l' || c == 'L') - return LEFT; - else if (c == 'r' || c == 'R') - return RIGHT; - if (terse) - msg(rs,"L or R"); - else - msg(rs,"please type L or R"); + if ( rs->replaydone != 0 ) + return(-1); + if (terse) + msg(rs,"left or right ring? "); + else + msg(rs,"left hand or right hand? "); + if ((c = readchar(rs)) == ESCAPE) + return -1; + mpos = 0; + if (c == 'l' || c == 'L') + return LEFT; + else if (c == 'r' || c == 'R') + return RIGHT; + if (terse) + msg(rs,"L or R"); + else + msg(rs,"please type L or R"); } } @@ -161,21 +163,21 @@ ring_eat(int hand) THING *ring; int eat; static int uses[] = { - 1, /* R_PROTECT */ 1, /* R_ADDSTR */ - 1, /* R_SUSTSTR */ -3, /* R_SEARCH */ - -5, /* R_SEEINVIS */ 0, /* R_NOP */ - 0, /* R_AGGR */ -3, /* R_ADDHIT */ - -3, /* R_ADDDAM */ 2, /* R_REGEN */ - -2, /* R_DIGEST */ 0, /* R_TELEPORT */ - 1, /* R_STEALTH */ 1 /* R_SUSTARM */ + 1, /* R_PROTECT */ 1, /* R_ADDSTR */ + 1, /* R_SUSTSTR */ -3, /* R_SEARCH */ + -5, /* R_SEEINVIS */ 0, /* R_NOP */ + 0, /* R_AGGR */ -3, /* R_ADDHIT */ + -3, /* R_ADDDAM */ 2, /* R_REGEN */ + -2, /* R_DIGEST */ 0, /* R_TELEPORT */ + 1, /* R_STEALTH */ 1 /* R_SUSTARM */ }; - + if ((ring = cur_ring[hand]) == NULL) - return 0; + return 0; if ((eat = uses[ring->o_which]) < 0) - eat = (rnd(-eat) == 0); + eat = (rnd(-eat) == 0); if (ring->o_which == R_DIGEST) - eat = -eat; + eat = -eat; return eat; } @@ -187,18 +189,18 @@ char * ring_num(THING *obj) { static char buf[10]; - + if (!(obj->o_flags & ISKNOW)) - return ""; + return ""; switch (obj->o_which) { - case R_PROTECT: - case R_ADDSTR: - case R_ADDDAM: - case R_ADDHIT: - sprintf(buf, " [%s]", num(obj->o_arm, 0, RING)); - otherwise: - return ""; + case R_PROTECT: + case R_ADDSTR: + case R_ADDDAM: + case R_ADDHIT: + sprintf(buf, " [%s]", num(obj->o_arm, 0, RING)); + otherwise: + return ""; } return buf; } diff --git a/src/cc/rogue/rip.c b/src/cc/rogue/rip.c index 1866f0b48..123b1aaa8 100644 --- a/src/cc/rogue/rip.c +++ b/src/cc/rogue/rip.c @@ -238,7 +238,7 @@ death(struct rogue_state *rs,char monst) //struct tm *localtime(const time_t *); if ( rs->guiflag == 0 ) { - fprintf(stderr,"death during replay by (%c)\n",monst); //sleep(3); + //fprintf(stderr,"death during replay by (%c)\n",monst); //sleep(3); rs->replaydone = (uint32_t)time(NULL); return; } diff --git a/src/cc/rogue/rogue.c b/src/cc/rogue/rogue.c index 53f6da353..7a8e38c15 100644 --- a/src/cc/rogue/rogue.c +++ b/src/cc/rogue/rogue.c @@ -13,6 +13,7 @@ #include //#include //#include + #include "rogue.h" #ifdef STANDALONE #include "../komodo/src/komodo_cJSON.h" @@ -118,20 +119,20 @@ int32_t roguefname(char *fname,uint64_t seed,int32_t counter) return(0); } -#ifdef test -int32_t flushkeystrokes(struct rogue_state *rs) +int32_t flushkeystrokes_local(struct rogue_state *rs,int32_t waitflag) { +#ifndef BUILD_ROGUE char fname[1024]; FILE *fp; int32_t i,retflag = -1; + rs->counter++; roguefname(fname,rs->seed,rs->counter); if ( (fp= fopen(fname,"wb")) != 0 ) { if ( fwrite(rs->buffered,1,rs->num,fp) == rs->num ) { - rs->counter++; rs->num = 0; retflag = 0; fclose(fp); - if ( (fp= fopen("savefile","wb")) != 0 ) + /*if ( (fp= fopen("savefile","wb")) != 0 ) { save_file(rs,fp,0); if ( 0 && (fp= fopen("savefile","rb")) != 0 ) @@ -140,22 +141,24 @@ int32_t flushkeystrokes(struct rogue_state *rs) fprintf(stderr,"%02x",fgetc(fp)); fprintf(stderr," first part rnd.%d\n",rnd(1000)); fclose(fp); - } - roguefname(fname,rs->seed,rs->counter); + }*/ + roguefname(fname,rs->seed,rs->counter+1); if ( (fp= fopen(fname,"wb")) != 0 ) // truncate next file fclose(fp); //fprintf(stderr,"savefile <- %s retflag.%d\n",fname,retflag); - } + //} } else fprintf(stderr,"error writing (%s)\n",fname); } else fprintf(stderr,"error creating (%s)\n",fname); return(retflag); -} #else + return(0); +#endif +} #ifdef BUILD_ROGUE // stubs for inside daemon -void rogue_progress(struct rogue_state *rs,uint64_t seed,char *keystrokes,int32_t num) +void rogue_progress(struct rogue_state *rs,int32_t waitflag,uint64_t seed,char *keystrokes,int32_t num) { } @@ -165,14 +168,19 @@ int32_t rogue_setplayerdata(struct rogue_state *rs,char *gametxidstr) } #endif -int32_t flushkeystrokes(struct rogue_state *rs) +int32_t flushkeystrokes(struct rogue_state *rs,int32_t waitflag) { if ( rs->num > 0 ) { - rogue_progress(rs,rs->seed,rs->buffered,rs->num); + // need to get existing keystrokes including mempool + // create keystrokes that are not saved + //rs->keytxid = rogue_progress(rs,waitflag,rs->seed,&rs->buffered[rs->lastnum],rs->num - rs->lastnum); + //rs->lastnum = rs->num; + rogue_progress(rs,waitflag,rs->seed,rs->buffered,rs->num); + flushkeystrokes_local(rs,waitflag); memset(rs->buffered,0,sizeof(rs->buffered)); - rs->counter++; - rs->num = 0; + //rs->num = 0; + //rs->counter++; } return(0); } @@ -180,7 +188,7 @@ int32_t flushkeystrokes(struct rogue_state *rs) void rogue_bailout(struct rogue_state *rs) { char cmd[512]; - flushkeystrokes(rs); + flushkeystrokes(rs,1); //sleep(5); return; /*fprintf(stderr,"bailing out\n"); @@ -189,6 +197,12 @@ void rogue_bailout(struct rogue_state *rs) fprintf(stderr,"error issuing (%s)\n",cmd);*/ } +#ifdef _WIN32 +#ifdef _MSC_VER +#define sleep(x) Sleep(1000*(x)) +#endif +#endif + int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct rogue_player *player,int32_t sleepmillis) { struct rogue_state *rs; FILE *fp; int32_t i,n; @@ -208,6 +222,14 @@ int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu globalR = *rs; uint32_t starttime = (uint32_t)time(NULL); rogueiterate(rs); + + /* + // keypress after replay + printf("[Press return to continue]"); + fflush(stdout); + if (fgets(prbuf, 10, stdin) != 0); + */ + if ( 0 ) { fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL) - starttime); @@ -229,7 +251,7 @@ int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu if ( (fp= fopen("checkfile","wb")) != 0 ) { save_file(rs,fp,0); - fprintf(stderr,"gold.%d hp.%d strength.%d/%d level.%d exp.%d dungeon.%d data[%d]\n",rs->P.gold,rs->P.hitpoints,rs->P.strength&0xffff,rs->P.strength>>16,rs->P.level,rs->P.experience,rs->P.dungeonlevel,rs->playersize); + //fprintf(stderr,"gold.%d hp.%d strength.%d/%d level.%d exp.%d dungeon.%d data[%d]\n",rs->P.gold,rs->P.hitpoints,rs->P.strength&0xffff,rs->P.strength>>16,rs->P.level,rs->P.experience,rs->P.dungeonlevel,rs->playersize); if ( newdata != 0 && rs->playersize > 0 ) memcpy(newdata,rs->playerdata,rs->playersize); } @@ -237,7 +259,6 @@ int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu free(rs); return(n); } -#endif long get_filesize(FILE *fp) { @@ -248,11 +269,10 @@ long get_filesize(FILE *fp) return(fsize); } -int32_t rogue_replay(uint64_t seed,int32_t sleeptime) +char *rogue_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter) { - FILE *fp; char fname[1024]; char *keystrokes = 0; long num=0,fsize; int32_t i,counter = 0; struct rogue_state *rs; struct rogue_player P,*player = 0; - if ( seed == 0 ) - seed = 777; + char fname[1024],*keystrokes = 0; FILE *fp; long fsize; int32_t num = 0; + *numkeysp = 0; while ( 1 ) { roguefname(fname,seed,counter); @@ -262,26 +282,37 @@ int32_t rogue_replay(uint64_t seed,int32_t sleeptime) if ( (fsize= get_filesize(fp)) <= 0 ) { fclose(fp); - printf("fsize.%ld\n",fsize); + //printf("fsize.%ld\n",fsize); break; } if ( (keystrokes= (char *)realloc(keystrokes,num+fsize)) == 0 ) { fprintf(stderr,"error reallocating keystrokes\n"); fclose(fp); - return(-1); + return(0); } if ( fread(&keystrokes[num],1,fsize,fp) != fsize ) { fprintf(stderr,"error reading keystrokes from (%s)\n",fname); fclose(fp); - return(-1); + free(keystrokes); + return(0); } fclose(fp); num += fsize; counter++; - fprintf(stderr,"loaded %ld from (%s) total %ld\n",fsize,fname,num); + //fprintf(stderr,"loaded %ld from (%s) total %d\n",fsize,fname,num); } + *numkeysp = num; + return(keystrokes); +} + +int32_t rogue_replay(uint64_t seed,int32_t sleeptime) +{ + FILE *fp; char fname[1024]; char *keystrokes = 0; long fsize; int32_t i,num=0,counter = 0; struct rogue_state *rs; struct rogue_player P,*player = 0; + if ( seed == 0 ) + seed = 777; + keystrokes = rogue_keystrokesload(&num,seed,counter); if ( num > 0 ) { sprintf(fname,"rogue.%llu.player",(long long)seed); @@ -295,7 +326,6 @@ int32_t rogue_replay(uint64_t seed,int32_t sleeptime) fclose(fp); } rogue_replay2(0,seed,keystrokes,num,player,sleeptime); - mvaddstr(LINES - 2, 0, (char *)"replay completed"); endwin(); my_exit(0); @@ -313,8 +343,17 @@ int rogue(int argc, char **argv, char **envp) rs->sleeptime = 1; // non-zero to allow refresh() if ( argc == 3 && strlen(argv[2]) == 64 ) { - rs->seed = atol(argv[1]); + #ifdef _WIN32 + #ifdef _MSC_VER + rs->seed = _strtoui64(argv[1], NULL, 10); + #else + rs->seed = atol(argv[1]); // windows, but not MSVC + #endif // _MSC_VER + #else + rs->seed = atol(argv[1]); // non-windows + #endif // _WIN32 strcpy(Gametxidstr,argv[2]); + fprintf(stderr,"setplayerdata\n"); if ( rogue_setplayerdata(rs,Gametxidstr) < 0 ) { fprintf(stderr,"invalid gametxid, or already started\n"); @@ -410,7 +449,7 @@ int rogue(int argc, char **argv, char **envp) #endif printf("Hello %s, just a moment while I dig the dungeon... seed.%llu", whoami,(long long)rs->seed); fflush(stdout); - + fprintf(stderr,"rogueiterate\n"); rogueiterate(rs); return(0); } @@ -510,6 +549,18 @@ tstp(int ignored) #endif*/ } + +#ifdef _WIN32 +#ifdef _MSC_VER +void usleep(int32_t micros) +{ + if (micros < 1000) + Sleep(1); + else Sleep(micros / 1000); +} +#endif +#endif + /* * playit: * The main loop of the program. Loop until the game is over, @@ -560,15 +611,15 @@ playit(struct rogue_state *rs) } else { - if ( rs->needflush != 0 && rs->num > 1000 ) + if ( rs->needflush != 0 ) { - if ( flushkeystrokes(rs) == 0 ) + if ( flushkeystrokes(rs,0) == 0 ) rs->needflush = 0; } } } if ( rs->guiflag != 0 ) - flushkeystrokes(rs); + flushkeystrokes(rs,1); endit(0); } @@ -593,13 +644,13 @@ int32_t _quit() if ( rs->sleeptime != 0 ) refresh(); score(rs,purse, 1, 0); - flushkeystrokes(rs); + flushkeystrokes(rs,1); my_exit(0); } else { //score(rs,purse, 1, 0); - fprintf(stderr,"done! (%c)\n",c); + //fprintf(stderr,"done! (%c)\n",c); } return(1); } diff --git a/src/cc/rogue/rogue.h b/src/cc/rogue/rogue.h index b64af8f1a..5540da2da 100644 --- a/src/cc/rogue/rogue.h +++ b/src/cc/rogue/rogue.h @@ -362,11 +362,12 @@ typedef union _bits256 bits256; struct rogue_state { uint64_t seed; - char *keystrokes; + char *keystrokes,*keystrokeshex; uint32_t needflush,replaydone; - int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring; + int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum; + FILE *logfp; struct rogue_player P; - char buffered[8192]; + char buffered[10000]; uint8_t playerdata[10000]; }; extern struct rogue_state globalR; @@ -374,12 +375,12 @@ extern struct rogue_state globalR; int rogue(int argc, char **argv, char **envp); void rogueiterate(struct rogue_state *rs); int32_t roguefname(char *fname,uint64_t seed,int32_t counter); -int32_t flushkeystrokes(struct rogue_state *rs); +int32_t flushkeystrokes(struct rogue_state *rs,int32_t waitflag); int32_t rogue_restorepack(struct rogue_state *rs); void restore_player(struct rogue_state *rs); int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct rogue_player *player,int32_t sleepmillis); void rogue_bailout(struct rogue_state *rs); -void rogue_progress(struct rogue_state *rs,uint64_t seed,char *keystrokes,int32_t num); +void rogue_progress(struct rogue_state *rs,int32_t waitflag,uint64_t seed,char *keystrokes,int32_t num); int32_t rogue_setplayerdata(struct rogue_state *rs,char *gametxidstr); #define ROGUE_MAXTOTAL (pstats.s_str*2) @@ -612,7 +613,7 @@ void current(struct rogue_state *rs,THING *cur, char *how, char *where); void d_level(struct rogue_state *rs); void death(struct rogue_state *rs,char monst); char death_monst(void); -void dig(int y, int x); +void dig(struct rogue_state *rs,int y, int x); void discard(THING *item); void discovered(struct rogue_state *rs); int dist(int y1, int x1, int y2, int x2); @@ -620,7 +621,7 @@ int dist_cp(coord *c1, coord *c2); int do_chase(struct rogue_state *rs,THING *th); void do_daemons(struct rogue_state *rs,int flag); void do_fuses(struct rogue_state *rs,int flag); -void do_maze(struct room *rp); +void do_maze(struct rogue_state *rs,struct room *rp); void do_motion(struct rogue_state *rs,THING *obj, int ydelta, int xdelta); void do_move(struct rogue_state *rs,int dy, int dx); void do_passages(struct rogue_state *rs); @@ -632,7 +633,7 @@ void doadd(struct rogue_state *rs,char *fmt, va_list args); void door(struct room *rm, coord *cp); void door_open(struct rogue_state *rs,struct room *rp); void drain(struct rogue_state *rs); -void draw_room(struct room *rp); +void draw_room(struct rogue_state *rs,struct room *rp); void drop(struct rogue_state *rs); void eat(struct rogue_state *rs); size_t encread(char *start, size_t size, FILE *inf); @@ -761,7 +762,7 @@ bool chase(THING *tp, coord *ee); bool diag_ok(coord *sp, coord *ep); bool dropcheck(struct rogue_state *rs,THING *obj); bool fallpos(coord *pos, coord *newpos); -bool find_floor(struct room *rp, coord *cp, int limit, bool monst); +bool find_floor(struct rogue_state *rs,struct room *rp, coord *cp, int limit, bool monst); bool is_magic(THING *obj); bool is_symlink(char *sp); bool levit_check(struct rogue_state *rs); @@ -770,7 +771,7 @@ bool roll_em(THING *thatt, THING *thdef, THING *weap, bool hurl); bool see_monst(THING *mp); bool seen_stairs(void); bool turn_ok(int y, int x); -bool turn_see(bool turn_off); +bool turn_see(struct rogue_state *rs,bool turn_off); bool is_current(struct rogue_state *rs,THING *obj); int passwd(void); @@ -824,6 +825,7 @@ void doctor(struct rogue_state *rs,int); void playit(struct rogue_state *rs); struct room *roomin(struct rogue_state *rs,coord *cp); +int32_t thing_find(THING *ptr); #define MAXDAEMONS 20 diff --git a/src/cc/rogue/rogue54.sln b/src/cc/rogue/rogue54.sln index da1c58f07..751959465 100644 --- a/src/cc/rogue/rogue54.sln +++ b/src/cc/rogue/rogue54.sln @@ -1,17 +1,25 @@ -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual C++ Express 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rogue54", "rogue54.vcproj", "{9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rogue54", "rogue54.vcxproj", "{9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Debug|Win32.ActiveCfg = Debug|Win32 {9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Debug|Win32.Build.0 = Debug|Win32 + {9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Debug|x64.ActiveCfg = Debug|x64 + {9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Debug|x64.Build.0 = Debug|x64 {9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Release|Win32.ActiveCfg = Release|Win32 {9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Release|Win32.Build.0 = Release|Win32 + {9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Release|x64.ActiveCfg = Release|x64 + {9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/cc/rogue/rogue54.vcxproj b/src/cc/rogue/rogue54.vcxproj new file mode 100644 index 000000000..344598dd8 --- /dev/null +++ b/src/cc/rogue/rogue54.vcxproj @@ -0,0 +1,257 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6} + Win32Proj + 8.1 + + + + Application + v140 + MultiByte + + + Application + v140 + MultiByte + false + + + Application + v140 + MultiByte + + + Application + v140 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.25431.1 + + + Debug\ + Debug\ + true + + + true + + + Release\ + Release\ + false + + + false + + + + Disabled + Default + ../pdcurses;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;ALLSCORES;MASTER;SCOREFILE="rogue54.scr";LOCKFILE="rogue54.lck";%(PreprocessorDefinitions) + true + false + + EnableFastChecks + MultiThreaded + true + true + false + true + + + Level4 + EditAndContinue + CompileAsC + + + Ws2_32.lib;pdcurses.lib;advapi32.lib;shfolder.lib;user32.lib;%(AdditionalDependencies) + $(OutDir)rogue54.exe + ..\pdcurses;%(AdditionalLibraryDirectories) + false + true + $(OutDir)rogue54.pdb + Console + MachineX86 + + + + + Disabled + Default + $(ProjectDir)x86_64-w64-msvc\deps\install\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;PDC_DLL_BUILD;PDC_WIDE;PDCDEBUG;_CRT_SECURE_NO_DEPRECATE;ALLSCORES;SCOREFILE="rogue54.scr";LOCKFILE="rogue54.lck";%(PreprocessorDefinitions) + true + false + + + EnableFastChecks + MultiThreaded + true + true + false + true + + + + + Level4 + ProgramDatabase + CompileAsC + + + Ws2_32.lib;wincon\pdcurses.lib;libcurl_imp.lib;advapi32.lib;shfolder.lib;user32.lib;%(AdditionalDependencies) + $(OutDir)rogue54.exe + $(ProjectDir)x86_64-w64-msvc\deps\install\lib;$(ProjectDir)x86_64-w64-msvc\deps\install\Release\lib;%(AdditionalLibraryDirectories) + false + true + $(OutDir)rogue54.pdb + Console + + + + + MaxSpeed + OnlyExplicitInline + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + true + NotUsing + Level3 + ProgramDatabase + $(ProjectDir)\x86_64-w64-msvc\include\ncursesw;$(ProjectDir)\x86_64-w64-msvc\include;%(AdditionalIncludeDirectories) + + + $(OutDir)rogue54.exe + true + Windows + true + true + MachineX86 + %(AdditionalLibraryDirectories) + %(AdditionalDependencies) + + + + + MaxSpeed + OnlyExplicitInline + true + WIN32;_WINDOWS;NDEBUG;PDC_DLL_BUILD;PDC_WIDE;PDCDEBUG;_CRT_SECURE_NO_DEPRECATE;ALLSCORES;SCOREFILE="rogue54.scr";LOCKFILE="rogue54.lck";%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + ProgramDatabase + $(ProjectDir)x86_64-w64-msvc\deps\install\include;%(AdditionalIncludeDirectories) + stdafx.h + CompileAsC + + + + + $(OutDir)rogue54.exe + true + Console + true + true + $(ProjectDir)x86_64-w64-msvc\deps\install\lib;$(ProjectDir)x86_64-w64-msvc\deps\install\Release\lib;%(AdditionalLibraryDirectories) + Ws2_32.lib;wincon\pdcurses.lib;libcurl_imp.lib;advapi32.lib;shfolder.lib;user32.lib;%(AdditionalDependencies) + %(IgnoreSpecificDefaultLibraries) + false + %(ForceSymbolReferences) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/cc/rogue/rogue_build_msvc.cmd b/src/cc/rogue/rogue_build_msvc.cmd new file mode 100644 index 000000000..77e7cd852 --- /dev/null +++ b/src/cc/rogue/rogue_build_msvc.cmd @@ -0,0 +1,64 @@ +@echo off +echo Rogue Build Script by Decker (c) 2019 + +@REM Check for Visual Studio +call set "VSPATH=" +if defined VS140COMNTOOLS ( if not defined VSPATH ( + call set "VSPATH=%%VS140COMNTOOLS%%" +) ) + +@REM check if we already have the tools in the environment +if exist "%VCINSTALLDIR%" ( + goto compile +) + +if not defined VSPATH ( + echo You need Microsoft Visual Studio 15 installed + pause + exit +) + +@REM set up the environment +if exist "%VSPATH%..\..\vc\vcvarsall.bat" ( + call "%%VSPATH%%..\..\vc\vcvarsall.bat" amd64 + goto compile +) + +echo Unable to set up the environment +pause +exit + +:compile + +mkdir x86_64-w64-msvc\deps +mkdir x86_64-w64-msvc\deps\install + +pushd x86_64-w64-msvc\deps + +:compile_pdcurses +rem git clone https://github.com/wmcbrine/PDCurses PDCurses.org +git clone https://github.com/Bill-Gray/PDCurses + +set PREFIX_DIR=%CD%\install + +pushd PDCurses +mkdir build64 & pushd build64 +rem cmake -G"Visual Studio 14 2015 Win64" -DPDC_WIDE=ON -DCMAKE_INSTALL_PREFIX=%PREFIX_DIR% -DCMAKE_BUILD_TYPE=Debug -DPDCDEBUG=ON .. +cmake -G"Visual Studio 14 2015 Win64" -DPDC_WIDE=ON -DCMAKE_INSTALL_PREFIX=%PREFIX_DIR% -DCMAKE_BUILD_TYPE=Release .. +popd +rem cmake --build build64 --config Debug --target install +cmake --build build64 --config Release --target install +popd + +:compile_curl + +git clone https://github.com/curl/curl +pushd curl + +mkdir build64 & pushd build64 +cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=%PREFIX_DIR% -DCMAKE_USE_WINSSL:BOOL=ON .. +cmake --build . --config Release --target libcurl +cmake --build . --config Release --target install +popd +popd + diff --git a/src/cc/rogue/rooms.c b/src/cc/rogue/rooms.c index 41041d627..67ca701d9 100644 --- a/src/cc/rogue/rooms.c +++ b/src/cc/rogue/rooms.c @@ -112,7 +112,7 @@ do_rooms(struct rogue_state *rs) rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x); rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y); } until (rp->r_pos.y != 0); - draw_room(rp); + draw_room(rs,rp); /* * Put the gold in */ @@ -122,7 +122,7 @@ do_rooms(struct rogue_state *rs) gold = new_item(); gold->o_goldval = rp->r_goldval = GOLDCALC; - find_floor(rp, &rp->r_gold, FALSE, FALSE); + find_floor(rs,rp, &rp->r_gold, FALSE, FALSE); gold->o_pos = rp->r_gold; chat(rp->r_gold.y, rp->r_gold.x) = GOLD; gold->o_flags = ISMANY; @@ -136,7 +136,7 @@ do_rooms(struct rogue_state *rs) if (rnd(100) < (rp->r_goldval > 0 ? 80 : 25)) { tp = new_item(); - find_floor(rp, &mp, FALSE, TRUE); + find_floor(rs,rp, &mp, FALSE, TRUE); new_monster(rs,tp, randmonster(FALSE), &mp); give_pack(rs,tp); } @@ -150,12 +150,12 @@ do_rooms(struct rogue_state *rs) */ void -draw_room(struct room *rp) +draw_room(struct rogue_state *rs,struct room *rp) { int y, x; if (rp->r_flags & ISMAZE) - do_maze(rp); + do_maze(rs,rp); else { vert(rp, rp->r_pos.x); /* Draw left side */ @@ -211,7 +211,7 @@ static SPOT maze[NUMLINES/3+1][NUMCOLS/3+1]; void -do_maze(struct room *rp) +do_maze(struct rogue_state *rs,struct room *rp) { SPOT *sp; int starty, startx; @@ -232,7 +232,7 @@ do_maze(struct room *rp) pos.y = starty + Starty; pos.x = startx + Startx; putpass(&pos); - dig(starty, startx); + dig(rs,starty, startx); } /* @@ -241,7 +241,7 @@ do_maze(struct room *rp) */ void -dig(int y, int x) +dig(struct rogue_state *rs,int y, int x) { coord *cp; int cnt, newy, newx, nexty = 0, nextx = 0; @@ -252,6 +252,8 @@ dig(int y, int x) for (;;) { + if ( rs->replaydone != 0 ) + return; cnt = 0; for (cp = del; cp <= &del[3]; cp++) { @@ -291,7 +293,7 @@ dig(int y, int x) pos.y = nexty + Starty; pos.x = nextx + Startx; putpass(&pos); - dig(nexty, nextx); + dig(rs,nexty, nextx); } } @@ -332,7 +334,7 @@ rnd_pos(struct room *rp, coord *cp) * pick a new room each time around the loop. */ bool -find_floor(struct room *rp, coord *cp, int limit, bool monst) +find_floor(struct rogue_state *rs,struct room *rp, coord *cp, int limit, bool monst) { PLACE *pp; int cnt; @@ -346,6 +348,8 @@ find_floor(struct room *rp, coord *cp, int limit, bool monst) cnt = limit; for (;;) { + if ( rs->replaydone != 0 ) + return(FALSE); if (limit && cnt-- == 0) return FALSE; if (pickroom) diff --git a/src/cc/rogue/scrolls.c b/src/cc/rogue/scrolls.c index 5554a5701..8ed6d2648 100644 --- a/src/cc/rogue/scrolls.c +++ b/src/cc/rogue/scrolls.c @@ -313,7 +313,7 @@ def: call_it(rs,&scr_info[obj->o_which]); if (discardit) - discard(obj); + discard(obj); } /* diff --git a/src/cc/rogue/state.c b/src/cc/rogue/state.c index b0176a042..9963bbc9e 100644 --- a/src/cc/rogue/state.c +++ b/src/cc/rogue/state.c @@ -1429,6 +1429,11 @@ rs_write_object(struct rogue_state *rs,FILE *savef, THING *o) struct rogue_packitem *item; if (write_error) return(WRITESTAT); + if ( thing_find(o) < 0 ) + { + fprintf(stderr,"cant find thing.%p (%s) in list\n",o,inv_name(o,FALSE)); //sleep(3); + return(0); + } if ( o->_o._o_packch != 0 ) { item = &rs->P.roguepack[rs->P.packsize]; diff --git a/src/cc/rogue/sticks.c b/src/cc/rogue/sticks.c index f048f9423..cd559daef 100644 --- a/src/cc/rogue/sticks.c +++ b/src/cc/rogue/sticks.c @@ -158,7 +158,7 @@ do_zap(struct rogue_state *rs) { do { - find_floor(NULL, &new_pos, FALSE, TRUE); + find_floor(rs,NULL, &new_pos, FALSE, TRUE); } while (ce(new_pos, hero)); } else diff --git a/src/cc/rogue/weapons.c b/src/cc/rogue/weapons.c index e5a5eacf6..0a8b6016c 100644 --- a/src/cc/rogue/weapons.c +++ b/src/cc/rogue/weapons.c @@ -81,6 +81,8 @@ do_motion(struct rogue_state *rs,THING *obj, int ydelta, int xdelta) obj->o_pos = hero; for (;;) { + if ( rs->replaydone != 0 ) + return; /* * Erase the old one */ @@ -127,28 +129,28 @@ fall(struct rogue_state *rs,THING *obj, bool pr) if (fallpos(&obj->o_pos, &fpos)) { - pp = INDEX(fpos.y, fpos.x); - pp->p_ch = (char) obj->o_type; - obj->o_pos = fpos; - if (cansee(rs,fpos.y, fpos.x)) - { - if (pp->p_monst != NULL) - pp->p_monst->t_oldch = (char) obj->o_type; - else - mvaddch(fpos.y, fpos.x, obj->o_type); - } - attach(lvl_obj, obj); - return; + pp = INDEX(fpos.y, fpos.x); + pp->p_ch = (char) obj->o_type; + obj->o_pos = fpos; + if (cansee(rs,fpos.y, fpos.x)) + { + if (pp->p_monst != NULL) + pp->p_monst->t_oldch = (char) obj->o_type; + else + mvaddch(fpos.y, fpos.x, obj->o_type); + } + attach(lvl_obj, obj); + return; } if (pr) { - if (has_hit) - { - endmsg(rs); - has_hit = FALSE; - } - msg(rs,"the %s vanishes as it hits the ground", - weap_info[obj->o_which].oi_name); + if (has_hit) + { + endmsg(rs); + has_hit = FALSE; + } + msg(rs,"the %s vanishes as it hits the ground", + weap_info[obj->o_which].oi_name); } discard(obj); } diff --git a/src/cc/rogue/wizard.c b/src/cc/rogue/wizard.c index ee16b2d9b..35ce9fb54 100644 --- a/src/cc/rogue/wizard.c +++ b/src/cc/rogue/wizard.c @@ -35,19 +35,21 @@ whatis(struct rogue_state *rs,bool insist, int type) for (;;) { - obj = get_item(rs,"identify", type); - if (insist) - { - if (n_objs == 0) - return; - else if (obj == NULL) - msg(rs,"you must identify something"); - else if (type && obj->o_type != type && - !(type == R_OR_S && (obj->o_type == RING || obj->o_type == STICK)) ) - msg(rs,"you must identify a %s", type_name(type)); - else - break; - } + if ( rs->replaydone != 0 ) + return; + obj = get_item(rs,"identify", type); + if (insist) + { + if (n_objs == 0) + return; + else if (obj == NULL) + msg(rs,"you must identify something"); + else if (type && obj->o_type != type && + !(type == R_OR_S && (obj->o_type == RING || obj->o_type == STICK)) ) + msg(rs,"you must identify a %s", type_name(type)); + else + break; + } else break; } @@ -202,7 +204,7 @@ teleport(struct rogue_state *rs) static coord c; mvaddch(hero.y, hero.x, floor_at()); - find_floor((struct room *) NULL, &c, FALSE, TRUE); + find_floor(rs,(struct room *) NULL, &c, FALSE, TRUE); if (roomin(rs,&c) != proom) { leave_room(rs,&hero); diff --git a/src/cc/rogue/x86_64-w64-msvc/deps/install/include/acs_defs.h b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/acs_defs.h new file mode 100644 index 000000000..c8c02a737 --- /dev/null +++ b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/acs_defs.h @@ -0,0 +1,265 @@ +/* Many of the following #defines are completely unused for the +nonce. For each character, its code point in code page 437, +Unicode, and page 8859-1 are given. The first is used for +non-wide builds in Win32 console, DOS, SDL, and OS/2. +Unicode is used for all wide builds, and for the non-wide +build of WinGUI. Code page 8859-1 is used for non-wide X11. + + All of these characters exist in CP437 and Unicode. Some +don't exist in 8859-1, in which case the last column is 'TBD'. +Only 32 are used in ncurses. So caution is advised. */ + +#ifdef USE_ISO8859_CHARSET + #define CHOOSE( A, B, C) (C) + #define TBD '!' +#else + #define CHOOSE( A, B, C) (USE_UNICODE_ACS_CHARS ? B : A) +#endif + +/* Codes found from https://en.wikipedia.org/wiki/Code_page_437 */ + +#define SMILE CHOOSE( 0x01, 0x263a, 'O') +#define REV_SMILE CHOOSE( 0x02, 0x263b, 'O') +#define HEART CHOOSE( 0x03, 0x2665, 'H') +#define DIAMOND CHOOSE( 0x04, 0x2666, 0x01) +#define CLUB CHOOSE( 0x05, 0x2663, 'C') +#define SPADE CHOOSE( 0x06, 0x2660, 'S') +#define MEDIUM_BULLET CHOOSE( 0x07, 0x2022, 0xb7) +#define REV_BULLET CHOOSE( 0x08, 0x2508, 0xb7) +#define WHITE_BULLET CHOOSE( 0x09, 0x25cb, 7) +#define REV_WHITE_BULLET CHOOSE( 0x0a, 0x25D9, 7) +#define MALE_SYM CHOOSE( 0x0b, 0x2642, 'm') +#define FEMALE_SYM CHOOSE( 0x0c, 0x2640, 'f') +#define QTR_NOTE CHOOSE( 0x0d, 0x266a, 0xbc) +#define EIGHTH_NOTE CHOOSE( 0x0e, 0x266b, 0xbd) +#define SPLAT CHOOSE( 0x0f, 0xa4 , 0xa4) +#define RIGHT_TRIANGLE CHOOSE( 0x10, 0x25b6, '>') +#define LEFT_TRIANGLE CHOOSE( 0x11, 0x25c0, '<') +#define UP_DOWN_ARROW CHOOSE( 0x12, 0x2195, 0x19) +#define DBL_BANG CHOOSE( 0x13, 0x203c, '!') +#define PILCROW CHOOSE( 0x14, 0xb6 , 0xb6) +#define SECTION_SIGN CHOOSE( 0x15, 0xa7 , 0xa7) +#define LOW_QTR_BLOCK CHOOSE( 0x16, 0x25b2, '_') +#define UP_DOWN_ARROW_UNDERSCORED CHOOSE( 0x17, 0x21ab, 0x19) +#define UP_ARROW CHOOSE( 0x18, 0x2191, '^') +#define DOWN_ARROW CHOOSE( 0x19, 0x2193, 'v') +#define RIGHT_ARROW CHOOSE( 0x1a, 0x2192, '>') +#define LEFT_ARROW CHOOSE( 0x1b, 0x2190, '<') +#define RIGHT_ANGLE CHOOSE( 0x1c, 0x221f, 0xe) +#define LEFT_RIGHT_ARROW CHOOSE( 0x1d, 0x2194, '-') +#define UP_TRIANGLE CHOOSE( 0x1e, 0x25b2, '^') +#define DOWN_TRIANGLE CHOOSE( 0x1f, 0x25bc, 'v') + +#define UPPERCASE_C_CEDILLA CHOOSE( 0x80, 0xc7 , 0xc7) +#define LOWERCASE_U_UMLAUT CHOOSE( 0x81, 0xfc , 0xfc) +#define LOWERCASE_E_ACUTE CHOOSE( 0x82, 0xe9 , 0xe9) +#define LOWERCASE_A_CIRCUMFLEX CHOOSE( 0x83, 0xe2 , 0xe2) +#define LOWERCASE_A_UMLAUT CHOOSE( 0x84, 0xe4 , 0xe4) +#define LOWERCASE_A_GRAVE CHOOSE( 0x85, 0xe0 , 0xea) +#define LOWERCASE_A_RING CHOOSE( 0x86, 0xe5 , 0xe5) +#define LOWERCASE_C_CEDILLA CHOOSE( 0x87, 0xe7 , 0xe7) +#define LOWERCASE_E_CIRCUMFLEX CHOOSE( 0x88, 0xea , 0xea) +#define LOWERCASE_E_UMLAUT CHOOSE( 0x89, 0xeb , 0xeb) +#define LOWERCASE_E_GRAVE CHOOSE( 0x8a, 0xe8 , 0xe8) +#define LOWERCASE_I_UMLAUT CHOOSE( 0x8b, 0xef , 0xef) +#define LOWERCASE_I_CIRCUMFLEX CHOOSE( 0x8c, 0xee , 0xee) +#define LOWERCASE_I_GRAVE CHOOSE( 0x8d, 0xec , 0xce) +#define UPPERCASE_A_UMLAUT CHOOSE( 0x8e, 0xc4 , 0xc4) +#define UPPERCASE_A_RING CHOOSE( 0x8f, 0xc5 , 0xc5) + +#define UPPERCASE_E_ACUTE CHOOSE( 0x90, 0xc9 , 0xc9) +#define LOWERCASE_AE_LIGATURE CHOOSE( 0x91, 0xe6 , 0xe6) +#define UPPERCASE_AE_LIGATURE CHOOSE( 0x92, 0xc6 , 0xc6) +#define LOWERCASE_O_CIRCUMFLEX CHOOSE( 0x93, 0xf4 , 0xf4) +#define LOWERCASE_O_UMLAUT CHOOSE( 0x94, 0xf6 , 0xf6) +#define LOWERCASE_O_GRAVE CHOOSE( 0x95, 0xf2 , 0xf2) +#define LOWERCASE_U_CIRCUMFLEX CHOOSE( 0x96, 0xfb , 0xfb) +#define LOWERCASE_U_GRAVE CHOOSE( 0x97, 0xf9 , 0xf9) +#define LOWERCASE_Y_UMLAUT CHOOSE( 0x98, 0xff , 0xff) +#define UPPERCASE_O_UMLAUT CHOOSE( 0x99, 0xd6 , 0xd6) +#define UPPERCASE_U_UMLAUT CHOOSE( 0x9a, 0xdc , 0xdc) +#define CENT_SIGN CHOOSE( 0x9b, 0xa2 , 0xa2) +#define STERLING_SIGN CHOOSE( 0x9c, 0xa3 , 30) +#define YEN_SIGN CHOOSE( 0x9d, 0xa5 , 0xa5) +#define PESETA_SIGN CHOOSE( 0x9e, 0x20a7, TBD) +#define F_WITH_HOOK CHOOSE( 0x9f, 0x0192, TBD) + +#define LOWERCASE_A_ACUTE CHOOSE( 0xa0, 0xe1 , 0xe1) +#define LOWERCASE_I_ACUTE CHOOSE( 0xa1, 0xed , 0xed) +#define LOWERCASE_O_ACUTE CHOOSE( 0xa2, 0xf3 , 0xf3) +#define LOWERCASE_U_ACUTE CHOOSE( 0xa3, 0xfa , 0xfa) +#define LOWERCASE_N_TILDE CHOOSE( 0xa4, 0xf1 , 0xf1) +#define UPPERCASE_N_TILDE CHOOSE( 0xa5, 0xd1 , 0xd1) +#define A_ORDINAL CHOOSE( 0xa6, 0xaa , 0xaa) +#define O_ORDINAL CHOOSE( 0xa7, 0xba , 0xba) +#define INVERTED_QUESTION_MARK CHOOSE( 0xa8, 0xbf , 0xbf) +#define REVERSED_NOT_SIGN CHOOSE( 0xa9, 0x2310, TBD) +#define NOT_SIGN CHOOSE( 0xaa, 0xac , 0xac) +#define VULGAR_HALF CHOOSE( 0xab, 0xbd , 0xbd) +#define VULGAR_QUARTER CHOOSE( 0xac, 0xbc , 0xbc) +#define INVERTED_EXCLAMATION_MARK CHOOSE( 0xad, 0xa1 , 0xa1) +#define LEFT_ANGLE_QUOTE_MARK CHOOSE( 0xae, 0xab , 0xab) +#define RIGHT_ANGLE_QUOTE_MARK CHOOSE( 0xaf, 0xbb , 0xbb) + +#define LIGHT_SHADE CHOOSE( 0xb0, 0x2591, '#' ) +#define MEDIUM_SHADE CHOOSE( 0xb1, 0x2592, 2) +#define DARK_SHADE CHOOSE( 0xb2, 0x2593, TBD) +#define BOX_VLINE CHOOSE( 0xb3, 0x2502, 25) +#define BOX_RTEE CHOOSE( 0xb4, 0x2524, 22) +#define BOX_SD_RTEE CHOOSE( 0xb5, 0x2561, 22) +#define BOX_DS_RTEE CHOOSE( 0xb6, 0x2562, 22) +#define BOX_DS_URCORNER CHOOSE( 0xb7, 0x2556, 12) +#define BOX_SD_URCORNER CHOOSE( 0xb8, 0x2555, 12) +#define BOX_D_RTEE CHOOSE( 0xb9, 0x2563, 22) +#define BOX_D_VLINE CHOOSE( 0xba, 0x2551, 25) +#define BOX_D_URCORNER CHOOSE( 0xbb, 0x2557, 12) +#define BOX_D_LRCORNER CHOOSE( 0xbc, 0x255D, 11) +#define BOX_DS_LRCORNER CHOOSE( 0xbd, 0x255c, 11) +#define BOX_SD_LRCORNER CHOOSE( 0xbe, 0x255b, 11) +#define BOX_URCORNER CHOOSE( 0xbf, 0x2510, 12) + +#define BOX_LLCORNER CHOOSE( 0xc0, 0x2514, 14) +#define BOX_BTEE CHOOSE( 0xc1, 0x2534, 23) +#define BOX_TTEE CHOOSE( 0xc2, 0x252c, 24) +#define BOX_LTEE CHOOSE( 0xc3, 0x251c, 21) +#define BOX_HLINE CHOOSE( 0xc4, 0x2500, 18) +#define BOX_PLUS CHOOSE( 0xc5, 0x253c, 15) +#define BOX_SD_LTEE CHOOSE( 0xc6, 0x255e, 21) +#define BOX_DS_LTEE CHOOSE( 0xc7, 0x255f, 21) +#define BOX_D_LLCORNER CHOOSE( 0xc8, 0x255A, 14) +#define BOX_D_ULCORNER CHOOSE( 0xc9, 0x2554, 13) +#define BOX_D_BTEE CHOOSE( 0xca, 0x2569, 23) +#define BOX_D_TTEE CHOOSE( 0xcb, 0x2566, 24) +#define BOX_D_LTEE CHOOSE( 0xcc, 0x2560, 21) +#define BOX_D_HLINE CHOOSE( 0xcd, 0x2550, 18) +#define BOX_D_PLUS CHOOSE( 0xce, 0x256C, 15) +#define BOX_SD_BTEE CHOOSE( 0xcf, 0x2567, 23) + +#define BOX_DS_BTEE CHOOSE( 0xd0, 0x2568, 23) +#define BOX_SD_TTEE CHOOSE( 0xd1, 0x2564, 24) +#define BOX_DS_TTEE CHOOSE( 0xd2, 0x2565, 24) +#define BOX_DS_LLCORNER CHOOSE( 0xd3, 0x2559, 14) +#define BOX_SD_LLCORNER CHOOSE( 0xd4, 0x2558, 14) +#define BOX_SD_ULCORNER CHOOSE( 0xd5, 0x2552, 13) +#define BOX_DS_ULCORNER CHOOSE( 0xd6, 0x2553, 13) +#define BOX_DS_PLUS CHOOSE( 0xd7, 0x256b, 15) +#define BOX_SD_PLUS CHOOSE( 0xd8, 0x256a, 15) +#define BOX_LRCORNER CHOOSE( 0xd9, 0x2518, 11) +#define BOX_ULCORNER CHOOSE( 0xda, 0x250c, 13) +#define FULL_BLOCK CHOOSE( 0xdb, 0x2588, 0) +#define LOWER_HALF_BLOCK CHOOSE( 0xdc, 0x2584, TBD) +#define LEFT_HALF_BLOCK CHOOSE( 0xdd, 0x258c, TBD) +#define RIGHT_HALF_BLOCK CHOOSE( 0xde, 0x2590, TBD) +#define UPPER_HALF_BLOCK CHOOSE( 0xdf, 0x2580, TBD) + +#define ALPHA CHOOSE( 0xe0, 0x03b1, TBD) +#define BETA CHOOSE( 0xe1, 0x00df, TBD) +#define GAMMA CHOOSE( 0xe2, 0x0393, TBD) +#define PI CHOOSE( 0xe3, 0x03c0, 28) +#define UPPERCASE_SIGMA CHOOSE( 0xe4, 0x03a3, TBD) +#define LOWERCASE_SIGMA CHOOSE( 0xe5, 0x03c3, TBD) +#define MU CHOOSE( 0xe6, 0x00b5, 0xb5) +#define TAU CHOOSE( 0xe7, 0x03c4, TBD) +#define UPPERCASE_PHI CHOOSE( 0xe8, 0x03a6, TBD) +#define THETA CHOOSE( 0xe9, 0x0398, TBD) +#define OMEGA CHOOSE( 0xea, 0x03a9, TBD) +#define DELTA CHOOSE( 0xeb, 0x03b4, TBD) +#define INFINITY_SIGN CHOOSE( 0xec, 0x221e, TBD) +#define LOWERCASE_PHI CHOOSE( 0xed, 0x03c6, TBD) +#define EPSILON CHOOSE( 0xee, 0x03b5, TBD) +#define INTERSECTION CHOOSE( 0xef, 0x2229, TBD) + +#define TRIPLE_BAR CHOOSE( 0xf0, 0x2261, TBD) +#define PLUS_OR_MINUS CHOOSE( 0xf1, 0x00b1, 8) +#define GREATER_THAN_OR_EQUAL_TO CHOOSE( 0xf2, 0x2265, 27) +#define LESSER_THAN_OR_EQUAL_TO CHOOSE( 0xf3, 0x2264, 26) +#define UPPER_HALF_INTEGRAL_SIGN CHOOSE( 0xf4, 0x2320, TBD) +#define LOWER_HALF_INTEGRAL_SIGN CHOOSE( 0xf5, 0x2321, TBD) +#define DIVISION_SIGN CHOOSE( 0xf6, 0x00f7, 0xf7) +#define APPROXIMATELY_EQUALS_SIGN CHOOSE( 0xf7, 0x2248, TBD) +#define DEGREE_SIGN CHOOSE( 0xf8, 0x00b0, 0xb0) +#define LARGE_BULLET CHOOSE( 0xf9, 0x2219, 7) +#define SMALL_BULLET CHOOSE( 0xfa, 0x00b7, 0xb7) +#define SQUARE_ROOT CHOOSE( 0xfb, 0x221a, TBD) +#define SUPERSCRIPT_N CHOOSE( 0xfc, 0x207f, TBD) +#define SUPERSCRIPT_2 CHOOSE( 0xfd, 0x00b2, 0xb2) +#define CENTERED_SQUARE CHOOSE( 0xfe, 0x25a0, TBD) +#define NON_BREAKING_SPACE CHOOSE( 0xff, 0x00a0, TBD) + + + + /* It says at http://unicode.org/charts/PDF/U2300.pdf */ + /* that '...the scan line numbers here refer to old, */ + /* low-resolution technology for terminals, with only */ + /* nine scan lines per fixed-size character glyph. */ + /* Even-numbered scan lines are unified with box */ + /* drawing graphics." */ + /* The utility of these is questionable; they'd */ + /* work Just Fine in wingdi (_if_ the appropriate */ + /* glyphs are available), but not elsewhere. */ +#define HORIZ_SCAN_LINE_1 CHOOSE( 0x2d, 0x23ba, 16) +#define HORIZ_SCAN_LINE_3 CHOOSE( 0x2d, 0x23bb, 17) +#define HORIZ_SCAN_LINE_7 CHOOSE( 0x2d, 0x23bc, 19) +#define HORIZ_SCAN_LINE_9 CHOOSE( '_', 0x23bd, 20) + + /* Code page 437 lacks a 'for real' not-equals, so for that, */ + /* we use the double-horizontal single-vertical box drawing : */ +#define NOT_EQUALS_SIGN CHOOSE( 0xd8, 0x2260, 29) + +# define A(x) ((chtype)x | A_ALTCHARSET) + +chtype acs_map[128] = +{ + A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), + A(9), A(10), + CLUB, HEART, SPADE, SMILE, REV_SMILE, /* 11 12 13 14 15 */ + MEDIUM_BULLET, WHITE_BULLET, PILCROW, SECTION_SIGN, /* 16 17 18 19 */ + A_ORDINAL, O_ORDINAL, LOWERCASE_PHI, /* 20 21 22 */ + INVERTED_EXCLAMATION_MARK, INVERTED_QUESTION_MARK, /* 23 24 */ + REVERSED_NOT_SIGN, NOT_SIGN, /* 25 26 */ + UPPER_HALF_INTEGRAL_SIGN, LOWER_HALF_INTEGRAL_SIGN, /* 27 28 */ + SUPERSCRIPT_N, CENTERED_SQUARE, F_WITH_HOOK, /* 29 30 31 */ + + RIGHT_ARROW, LEFT_ARROW, UP_ARROW, DOWN_ARROW, /* 32 !"# */ + + PI, NOT_EQUALS_SIGN, VULGAR_HALF, VULGAR_QUARTER, /* $%&' */ + '(', + LEFT_ANGLE_QUOTE_MARK, RIGHT_ANGLE_QUOTE_MARK, /* )* */ + DARK_SHADE, SUPERSCRIPT_2, INFINITY_SIGN, /* +,- */ + ALPHA, BETA, GAMMA, UPPERCASE_SIGMA, LOWERCASE_SIGMA, /* ./012 */ + '3', + MU, TAU, UPPERCASE_PHI, THETA, OMEGA, DELTA, EPSILON, /* 456789: */ + + BOX_SD_LRCORNER, BOX_SD_URCORNER, BOX_SD_ULCORNER, /* ;<= */ + BOX_SD_LLCORNER, BOX_SD_PLUS, /* >? */ + BOX_SD_LTEE, BOX_SD_RTEE, BOX_SD_BTEE, BOX_SD_TTEE, /* @ABC */ + + BOX_D_LRCORNER, BOX_D_URCORNER, BOX_D_ULCORNER, /* DEF */ + BOX_D_LLCORNER, BOX_D_PLUS, /* GH */ + BOX_D_LTEE, BOX_D_RTEE, BOX_D_BTEE, BOX_D_TTEE, /* IJKL */ + + BOX_DS_LRCORNER, BOX_DS_URCORNER, BOX_DS_ULCORNER, /* MNO */ + BOX_DS_LLCORNER, BOX_DS_PLUS, /* PQ */ + BOX_DS_LTEE, BOX_DS_RTEE, BOX_DS_BTEE, BOX_DS_TTEE, /* RSTU */ + + BOX_LRCORNER, BOX_URCORNER, BOX_ULCORNER, /* VWX */ + BOX_LLCORNER, BOX_PLUS, /* YZ */ + BOX_LTEE, BOX_RTEE, BOX_BTEE, BOX_TTEE, /* [\]^ */ + + BOX_HLINE, BOX_VLINE, BOX_D_HLINE, BOX_D_VLINE, /* _`ab */ + + DIVISION_SIGN, APPROXIMATELY_EQUALS_SIGN, /* cd */ + INTERSECTION, TRIPLE_BAR, /* ef */ + SMALL_BULLET, LARGE_BULLET, SQUARE_ROOT, /* ghi */ + DIAMOND, MEDIUM_SHADE, /* jk */ + HORIZ_SCAN_LINE_1, HORIZ_SCAN_LINE_3, /* lm */ + HORIZ_SCAN_LINE_7, HORIZ_SCAN_LINE_9, /* no */ + UPPER_HALF_BLOCK, LOWER_HALF_BLOCK, /* pq */ + LEFT_HALF_BLOCK, RIGHT_HALF_BLOCK, FULL_BLOCK, /* rst */ + LESSER_THAN_OR_EQUAL_TO, GREATER_THAN_OR_EQUAL_TO, /* uv */ + DEGREE_SIGN, PLUS_OR_MINUS, LIGHT_SHADE, SPLAT, /* wxyz */ + CENT_SIGN, YEN_SIGN, PESETA_SIGN, STERLING_SIGN, /* {|}~ */ + A(127) +}; + +# undef A diff --git a/src/cc/rogue/x86_64-w64-msvc/deps/install/include/curses.h b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/curses.h new file mode 100644 index 000000000..9ee3f08a6 --- /dev/null +++ b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/curses.h @@ -0,0 +1,1846 @@ +/* Public Domain Curses */ + +/*----------------------------------------------------------------------* + * PDCurses * + *----------------------------------------------------------------------*/ + +#ifndef __PDCURSES__ +#define __PDCURSES__ 1 + +/*man-start************************************************************** + +PDCurses definitions list: (Only define those needed) + + XCURSES True if compiling for X11. + PDC_RGB True if you want to use RGB color definitions + (Red = 1, Green = 2, Blue = 4) instead of BGR. + PDC_WIDE True if building wide-character support. + PDC_DLL_BUILD True if building a Windows DLL. + PDC_NCMOUSE Use the ncurses mouse API instead + of PDCurses' traditional mouse API. + +PDCurses portable platform definitions list: + + PDC_BUILD Defines API build version. + PDCURSES Enables access to PDCurses-only routines. + XOPEN Always true. + SYSVcurses True if you are compiling for SYSV portability. + BSDcurses True if you are compiling for BSD portability. + +**man-end****************************************************************/ + +#define PDCURSES 1 /* PDCurses-only routines */ +#define XOPEN 1 /* X/Open Curses routines */ +#define SYSVcurses 1 /* System V Curses routines */ +#define BSDcurses 1 /* BSD Curses routines */ +#if defined( CHTYPE_32) + #define CHTYPE_LONG 1 /* chtypes will be 32 bits */ +#elif !defined( CHTYPE_16) + #define CHTYPE_LONG 2 /* chtypes will be (default) 64 bits */ +#endif + +/*----------------------------------------------------------------------*/ + +#ifdef NO_STDINT_H + #define uint64_t unsigned long long + #define uint32_t unsigned long + #define uint16_t unsigned short +#else + #include +#endif +#include +#include +#include /* Required by X/Open usage below */ + +#ifdef PDC_WIDE +# include +#endif + +#if defined(__STDC_VERSION__) && __STDC_VERSION >= 199901L && \ + !defined(__bool_true_false_are_defined) +# include +#endif + +#ifdef __cplusplus +extern "C" +{ +# define bool _bool +#endif + +/*---------------------------------------------------------------------- + * + * Constants and Types + * + */ + +#undef FALSE +#undef TRUE + +#ifdef __bool_true_false_are_defined + +# define FALSE false +# define TRUE true + +#else + +typedef unsigned char bool; + +# define FALSE 0 +# define TRUE 1 + +#endif + +#undef ERR +#define ERR (-1) + +#undef OK +#define OK 0 + +#ifdef CHTYPE_LONG + #if(CHTYPE_LONG >= 2) /* "non-standard" 64-bit chtypes */ + typedef uint64_t chtype; + #else /* "Standard" CHTYPE_LONG case, 32-bit: */ + typedef uint32_t chtype; + # endif +#else +typedef uint16_t chtype; /* 8-bit attr + 8-bit char */ +#endif + +#ifdef PDC_WIDE +typedef chtype cchar_t; +#endif + +typedef chtype attr_t; + +/* Version constants, available as of version 4.0 : */ +/* Don't forget to update 'version.mif' if MAJOR/MINOR changes! */ + +#define PDC_VER_MAJOR 4 +#define PDC_VER_MINOR 0 +#define PDC_VER_CHANGE 4 +#define PDC_VER_YEAR 2019 +#define PDC_VER_MONTH 1 +#define PDC_VER_DAY 20 + +#define PDC_BUILD (PDC_VER_MAJOR*1000 + PDC_VER_MINOR *100 + PDC_VER_CHANGE) + +/* When using PDCurses as a DLL (Windows) or shared library (BSD or *nix), +it's possible to switch the DLL or shared library. One may therefore want +to inquire of the DLL/shared library the port, version numbers, and +chtype_size used, and make sure they're what one was expecting. The +'PDC_version' structure lets you do just that. */ + +enum PDC_port +{ + PDC_PORT_X11 = 0, + PDC_PORT_WIN32 = 1, + PDC_PORT_WINGUI = 2, + PDC_PORT_DOS = 3, + PDC_PORT_OS2 = 4, + PDC_PORT_SDL1 = 5, + PDC_PORT_SDL2 = 6, + PDC_PORT_VT = 7 +}; + +/* Detailed PDC version information */ +#define PDC_HAS_VERSION_INFO 1 +typedef struct +{ + const enum PDC_port port; + const int ver_major; + const int ver_minor; + const int ver_change; + const size_t chtype_size; + const bool is_wide; + const bool is_forced_utf8; +} PDC_version_info; + +/*---------------------------------------------------------------------- + * + * Mouse Interface -- SYSVR4, with extensions + * + */ + +/* Most flavors of PDCurses support three buttons. WinGUI supports */ +/* these plus two "extended" buttons. But we'll set this macro to */ +/* six, allowing future versions to support up to nine total buttons. */ +/* (The button states are broken up into two arrays to allow for the */ +/* possibility of backward compatibility to DLLs compiled with only */ +/* three mouse buttons.) */ + +#define PDC_MAX_MOUSE_BUTTONS 9 +#define PDC_N_EXTENDED_MOUSE_BUTTONS 6 + +typedef struct +{ + int x; /* absolute column, 0 based, measured in characters */ + int y; /* absolute row, 0 based, measured in characters */ + short button[3]; /* state of three "normal" buttons */ + int changes; /* flags indicating what has changed with the mouse */ + short xbutton[PDC_N_EXTENDED_MOUSE_BUTTONS]; /* state of ext buttons */ +} MOUSE_STATUS; + +#define BUTTON_RELEASED 0x0000 +#define BUTTON_PRESSED 0x0001 +#define BUTTON_CLICKED 0x0002 +#define BUTTON_DOUBLE_CLICKED 0x0003 +#define BUTTON_TRIPLE_CLICKED 0x0004 +#define BUTTON_MOVED 0x0005 /* PDCurses */ +#define WHEEL_SCROLLED 0x0006 /* PDCurses */ +#define BUTTON_ACTION_MASK 0x0007 /* PDCurses */ + +#define PDC_BUTTON_SHIFT 0x0008 /* PDCurses */ +#define PDC_BUTTON_CONTROL 0x0010 /* PDCurses */ +#define PDC_BUTTON_ALT 0x0020 /* PDCurses */ +#define BUTTON_MODIFIER_MASK 0x0038 /* PDCurses */ + +#define MOUSE_X_POS (Mouse_status.x) +#define MOUSE_Y_POS (Mouse_status.y) + +/* + * Bits associated with the .changes field: + * 3 2 1 0 + * 210987654321098765432109876543210 + * 1 <- button 1 has changed 0 + * 10 <- button 2 has changed 1 + * 100 <- button 3 has changed 2 + * 1000 <- mouse has moved 3 + * 10000 <- mouse position report 4 + * 100000 <- mouse wheel up 5 + * 1000000 <- mouse wheel down 6 + * 10000000 <- mouse wheel left 7 + * 100000000 <- mouse wheel right 8 + * 1000000000 <- button 4 has changed 9 + * (NOTE: buttons 6 to 10000000000 <- button 5 has changed 10 + * 9 aren't implemented 100000000000 <- button 6 has changed 11 + * in any flavor of 1000000000000 <- button 7 has changed 12 + * PDCurses yet!) 10000000000000 <- button 8 has changed 13 + * 100000000000000 <- button 9 has changed 14 + */ + +#define PDC_MOUSE_MOVED 0x0008 +#define PDC_MOUSE_POSITION 0x0010 +#define PDC_MOUSE_WHEEL_UP 0x0020 +#define PDC_MOUSE_WHEEL_DOWN 0x0040 +#define PDC_MOUSE_WHEEL_LEFT 0x0080 +#define PDC_MOUSE_WHEEL_RIGHT 0x0100 + +#define A_BUTTON_CHANGED (Mouse_status.changes & 7) +#define MOUSE_MOVED (Mouse_status.changes & PDC_MOUSE_MOVED) +#define MOUSE_POS_REPORT (Mouse_status.changes & PDC_MOUSE_POSITION) +#define BUTTON_CHANGED(x) (Mouse_status.changes & (1 << ((x) - ((x)<4 ? 1 : -5)))) +#define BUTTON_STATUS(x) (Mouse_status.button[(x) - 1]) +#define MOUSE_WHEEL_UP (Mouse_status.changes & PDC_MOUSE_WHEEL_UP) +#define MOUSE_WHEEL_DOWN (Mouse_status.changes & PDC_MOUSE_WHEEL_DOWN) +#define MOUSE_WHEEL_LEFT (Mouse_status.changes & PDC_MOUSE_WHEEL_LEFT) +#define MOUSE_WHEEL_RIGHT (Mouse_status.changes & PDC_MOUSE_WHEEL_RIGHT) + +/* mouse bit-masks */ + +#define BUTTON1_RELEASED 0x00000001L +#define BUTTON1_PRESSED 0x00000002L +#define BUTTON1_CLICKED 0x00000004L +#define BUTTON1_DOUBLE_CLICKED 0x00000008L +#define BUTTON1_TRIPLE_CLICKED 0x00000010L +#define BUTTON1_MOVED 0x00000010L /* PDCurses */ + +#define BUTTON2_RELEASED 0x00000020L +#define BUTTON2_PRESSED 0x00000040L +#define BUTTON2_CLICKED 0x00000080L +#define BUTTON2_DOUBLE_CLICKED 0x00000100L +#define BUTTON2_TRIPLE_CLICKED 0x00000200L +#define BUTTON2_MOVED 0x00000200L /* PDCurses */ + +#define BUTTON3_RELEASED 0x00000400L +#define BUTTON3_PRESSED 0x00000800L +#define BUTTON3_CLICKED 0x00001000L +#define BUTTON3_DOUBLE_CLICKED 0x00002000L +#define BUTTON3_TRIPLE_CLICKED 0x00004000L +#define BUTTON3_MOVED 0x00004000L /* PDCurses */ + +/* For the ncurses-compatible functions only, BUTTON4_PRESSED and + BUTTON5_PRESSED are returned for mouse scroll wheel up and down; + otherwise PDCurses doesn't support buttons 4 and 5... except + as described above for WinGUI, and perhaps to be extended to + other PDCurses flavors */ + +#define BUTTON4_RELEASED 0x00008000L +#define BUTTON4_PRESSED 0x00010000L +#define BUTTON4_CLICKED 0x00020000L +#define BUTTON4_DOUBLE_CLICKED 0x00040000L +#define BUTTON4_TRIPLE_CLICKED 0x00080000L + +#define BUTTON5_RELEASED 0x00100000L +#define BUTTON5_PRESSED 0x00200000L +#define BUTTON5_CLICKED 0x00400000L +#define BUTTON5_DOUBLE_CLICKED 0x00800000L +#define BUTTON5_TRIPLE_CLICKED 0x01000000L + +#define MOUSE_WHEEL_SCROLL 0x02000000L /* PDCurses */ +#define BUTTON_MODIFIER_SHIFT 0x04000000L /* PDCurses */ +#define BUTTON_MODIFIER_CONTROL 0x08000000L /* PDCurses */ +#define BUTTON_MODIFIER_ALT 0x10000000L /* PDCurses */ + +#define ALL_MOUSE_EVENTS 0x1fffffffL +#define REPORT_MOUSE_POSITION 0x20000000L + +/* ncurses mouse interface */ + +typedef unsigned long mmask_t; + +typedef struct +{ + short id; /* unused, always 0 */ + int x, y, z; /* x, y same as MOUSE_STATUS; z unused */ + mmask_t bstate; /* equivalent to changes + button[], but + in the same format as used for mousemask() */ +} MEVENT; + +#if defined(PDC_NCMOUSE) && !defined(NCURSES_MOUSE_VERSION) +# define NCURSES_MOUSE_VERSION 2 +#endif + +#ifdef NCURSES_MOUSE_VERSION +# define BUTTON_SHIFT BUTTON_MODIFIER_SHIFT +# define BUTTON_CONTROL BUTTON_MODIFIER_CONTROL +# define BUTTON_CTRL BUTTON_MODIFIER_CONTROL +# define BUTTON_ALT BUTTON_MODIFIER_ALT +#else +# define BUTTON_SHIFT PDC_BUTTON_SHIFT +# define BUTTON_CONTROL PDC_BUTTON_CONTROL +# define BUTTON_ALT PDC_BUTTON_ALT +#endif + +/*---------------------------------------------------------------------- + * + * Window and Screen Structures + * + */ + +typedef struct _win /* definition of a window */ +{ + int _cury; /* current pseudo-cursor */ + int _curx; + int _maxy; /* max window coordinates */ + int _maxx; + int _begy; /* origin on screen */ + int _begx; + int _flags; /* window properties */ + chtype _attrs; /* standard attributes and colors */ + chtype _bkgd; /* background, normally blank */ + bool _clear; /* causes clear at next refresh */ + bool _leaveit; /* leaves cursor where it is */ + bool _scroll; /* allows window scrolling */ + bool _nodelay; /* input character wait flag */ + bool _immed; /* immediate update flag */ + bool _sync; /* synchronise window ancestors */ + bool _use_keypad; /* flags keypad key mode active */ + chtype **_y; /* pointer to line pointer array */ + int *_firstch; /* first changed character in line */ + int *_lastch; /* last changed character in line */ + int _tmarg; /* top of scrolling region */ + int _bmarg; /* bottom of scrolling region */ + int _delayms; /* milliseconds of delay for getch() */ + int _parx, _pary; /* coords relative to parent (0,0) */ + struct _win *_parent; /* subwin's pointer to parent win */ +} WINDOW; + +/* Avoid using the SCREEN struct directly -- use the corresponding + functions if possible. This struct may eventually be made private. */ + +typedef struct +{ + bool alive; /* if initscr() called, and not endwin() */ + bool autocr; /* if cr -> lf */ + bool cbreak; /* if terminal unbuffered */ + bool echo; /* if terminal echo */ + bool raw_inp; /* raw input mode (v. cooked input) */ + bool raw_out; /* raw output mode (7 v. 8 bits) */ + bool audible; /* FALSE if the bell is visual */ + bool mono; /* TRUE if current screen is mono */ + bool resized; /* TRUE if TERM has been resized */ + bool orig_attr; /* TRUE if we have the original colors */ + short orig_fore; /* original screen foreground color */ + short orig_back; /* original screen foreground color */ + int cursrow; /* position of physical cursor */ + int curscol; /* position of physical cursor */ + int visibility; /* visibility of cursor */ + int orig_cursor; /* original cursor size */ + int lines; /* new value for LINES */ + int cols; /* new value for COLS */ + unsigned long _trap_mbe; /* trap these mouse button events */ + unsigned long _map_mbe_to_key; /* map mouse buttons to slk */ + int mouse_wait; /* time to wait (in ms) for a + button release after a press, in + order to count it as a click */ + int slklines; /* lines in use by slk_init() */ + WINDOW *slk_winptr; /* window for slk */ + int linesrippedoff; /* lines ripped off via ripoffline() */ + int linesrippedoffontop; /* lines ripped off on + top via ripoffline() */ + int delaytenths; /* 1/10ths second to wait block + getch() for */ + bool _preserve; /* TRUE if screen background + to be preserved */ + int _restore; /* specifies if screen background + to be restored, and how */ + bool save_key_modifiers; /* TRUE if each key modifiers saved + with each key press */ + bool return_key_modifiers; /* TRUE if modifier keys are + returned as "real" keys */ + bool key_code; /* TRUE if last key is a special key; + used internally by get_wch() */ +#ifdef XCURSES + int XcurscrSize; /* size of Xcurscr shared memory block */ + bool sb_on; + int sb_viewport_y; + int sb_viewport_x; + int sb_total_y; + int sb_total_x; + int sb_cur_y; + int sb_cur_x; + int exit_key; +#endif + short line_color; /* color of line attributes - default -1 */ +} SCREEN; + +/*---------------------------------------------------------------------- + * + * External Variables + * + */ + +#ifdef PDC_DLL_BUILD +# ifdef CURSES_LIBRARY +# define PDCEX __declspec(dllexport) extern +# else +# define PDCEX __declspec(dllimport) +# endif +#else +# define PDCEX extern +#endif + +PDCEX int LINES; /* terminal height */ +PDCEX int COLS; /* terminal width */ +PDCEX WINDOW *stdscr; /* the default screen window */ +PDCEX WINDOW *curscr; /* the current screen image */ +PDCEX SCREEN *SP; /* curses variables */ +PDCEX MOUSE_STATUS Mouse_status; +PDCEX int COLORS; +PDCEX int COLOR_PAIRS; +PDCEX int TABSIZE; +PDCEX chtype acs_map[]; /* alternate character set map */ +PDCEX char ttytype[]; /* terminal name/description */ +PDCEX PDC_version_info PDC_version; + +/*man-start************************************************************** + +Text Attributes +=============== + +Originally, PDCurses used a short (16 bits) for its chtype. To include +color, a number of things had to be sacrificed from the strict Unix and +System V support. The main problem was fitting all character attributes +and color into an unsigned char (all 8 bits!). + +Today, PDCurses by default uses a long (32 bits) for its chtype, as in +System V. The short chtype is still available, by undefining CHTYPE_LONG +and rebuilding the library. + +The following is the structure of a win->_attrs chtype: + +short form: + + +-----------------------------------------------+ + |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| + +-----------------------------------------------+ + color number | attrs | character eg 'a' + +The available non-color attributes are bold, reverse and blink. Others +have no effect. The high order char is an index into an array of +physical colors (defined in color.c) -- 32 foreground/background color +pairs (5 bits) plus 3 bits for other attributes. + +long form: + + +--------------------------------------------------------------------+ + |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|..| 2| 1| 0| + +--------------------------------------------------------------------+ + color number | modifiers | character eg 'a' + +The available non-color attributes are bold, underline, invisible, +right-line, left-line, protect, reverse and blink. 256 color pairs (8 +bits), 8 bits for other attributes, and 16 bits for character data. + + Note that there is now a "super-long" 64-bit form, available by +defining CHTYPE_LONG to be 2: + +------------------------------------------------------------------------------- +|63|62|61|60|59|..|34|33|32|31|30|29|28|..|22|21|20|19|18|17|16|..| 3| 2| 1| 0| +------------------------------------------------------------------------------- + color number | modifiers | character eg 'a' + + + We take five more bits for the character (thus allowing Unicode values +past 64K; UTF-16 can go up to 0x10ffff, requiring 21 bits total), and +four more bits for attributes. Three are currently used as A_OVERLINE, A_DIM, +and A_STRIKEOUT; one more is reserved for future use. 31 bits are then used +for color. These are usually just treated as the usual palette +indices, and range from 0 to 255. However, if bit 63 is +set, the remaining 30 bits are interpreted as foreground RGB (first +fifteen bits, five bits for each of the three channels) and background RGB +(same scheme using the remaining 15 bits.) + +**man-end****************************************************************/ + +/*** Video attribute macros ***/ + +#define A_NORMAL (chtype)0 + +#ifdef CHTYPE_LONG + +# if(CHTYPE_LONG >= 2) /* 64-bit chtypes */ + # define PDC_CHARTEXT_BITS 21 + # define A_CHARTEXT (chtype)( ((chtype)0x1 << PDC_CHARTEXT_BITS) - 1) + # define A_ALTCHARSET ((chtype)0x001 << PDC_CHARTEXT_BITS) + # define A_RIGHTLINE ((chtype)0x002 << PDC_CHARTEXT_BITS) + # define A_LEFTLINE ((chtype)0x004 << PDC_CHARTEXT_BITS) + # define A_INVIS ((chtype)0x008 << PDC_CHARTEXT_BITS) + # define A_UNDERLINE ((chtype)0x010 << PDC_CHARTEXT_BITS) + # define A_REVERSE ((chtype)0x020 << PDC_CHARTEXT_BITS) + # define A_BLINK ((chtype)0x040 << PDC_CHARTEXT_BITS) + # define A_BOLD ((chtype)0x080 << PDC_CHARTEXT_BITS) + # define A_OVERLINE ((chtype)0x100 << PDC_CHARTEXT_BITS) + # define A_STRIKEOUT ((chtype)0x200 << PDC_CHARTEXT_BITS) + # define A_DIM ((chtype)0x400 << PDC_CHARTEXT_BITS) +#if 0 + /* May come up with a use for this bit */ + /* someday; reserved for the future: */ + # define A_FUTURE_2 ((chtype)0x800 << PDC_CHARTEXT_BITS) +#endif + # define PDC_COLOR_SHIFT (PDC_CHARTEXT_BITS + 12) + # define A_COLOR ((chtype)0x7fffffff << PDC_COLOR_SHIFT) + # define A_RGB_COLOR ((chtype)0x40000000 << PDC_COLOR_SHIFT) + # define A_ATTRIBUTES (((chtype)0xfff << PDC_CHARTEXT_BITS) | A_COLOR) + # define A_RGB( rfore, gfore, bfore, rback, gback, bback) \ + (( (((chtype)(bfore) << 25) \ + | ((chtype)(gfore) << 20) \ + | ((chtype)(rfore) << 15) \ + | ((chtype)(bback) << 10) \ + | ((chtype)(gback) << 5) \ + | ((chtype)(rback) )) << PDC_COLOR_SHIFT) | A_RGB_COLOR) +# else /* plain ol' 32-bit chtypes */ + # define A_ALTCHARSET (chtype)0x00010000 + # define A_RIGHTLINE (chtype)0x00020000 + # define A_LEFTLINE (chtype)0x00040000 + # define A_INVIS (chtype)0x00080000 + # define A_UNDERLINE (chtype)0x00100000 + # define A_REVERSE (chtype)0x00200000 + # define A_BLINK (chtype)0x00400000 + # define A_BOLD (chtype)0x00800000 + # define A_COLOR (chtype)0xff000000 + # define A_RGB_COLOR A_NORMAL +#ifdef PDC_WIDE + # define A_CHARTEXT (chtype)0x0000ffff + # define A_ATTRIBUTES (chtype)0xffff0000 + # define A_DIM A_NORMAL + # define A_OVERLINE A_NORMAL + # define A_STRIKEOUT A_NORMAL +#else /* with 8-bit chars, we have bits for these attribs : */ + # define A_CHARTEXT (chtype)0x000000ff + # define A_ATTRIBUTES (chtype)0xffffe000 + # define A_DIM (chtype)0x00008000 + # define A_OVERLINE (chtype)0x00004000 + # define A_STRIKEOUT (chtype)0x00002000 +#endif + # define PDC_COLOR_SHIFT 24 +#endif + + +# define A_ITALIC A_INVIS +# define A_PROTECT (A_UNDERLINE | A_LEFTLINE | A_RIGHTLINE) + +#else /* 16-bit chtypes */ +# define A_BOLD (chtype)0x0100 /* X/Open */ +# define A_REVERSE (chtype)0x0200 /* X/Open */ +# define A_BLINK (chtype)0x0400 /* X/Open */ + +# define A_ATTRIBUTES (chtype)0xff00 /* X/Open */ +# define A_CHARTEXT (chtype)0x00ff /* X/Open */ +# define A_COLOR (chtype)0xf800 /* System V */ + +# define A_ALTCHARSET A_NORMAL /* X/Open */ +# define A_PROTECT A_NORMAL /* X/Open */ +# define A_UNDERLINE A_NORMAL /* X/Open */ +# define A_OVERLINE A_NORMAL /* X/Open */ +# define A_STRIKEOUT A_NORMAL /* X/Open */ + +# define A_LEFTLINE A_NORMAL +# define A_RIGHTLINE A_NORMAL +# define A_ITALIC A_NORMAL +# define A_INVIS A_NORMAL +# define A_RGB_COLOR A_NORMAL +# define A_DIM A_NORMAL + +# define PDC_COLOR_SHIFT 11 +#endif + +#define A_STANDOUT (A_REVERSE | A_BOLD) /* X/Open */ + +#define CHR_MSK A_CHARTEXT /* Obsolete */ +#define ATR_MSK A_ATTRIBUTES /* Obsolete */ +#define ATR_NRM A_NORMAL /* Obsolete */ + +/* For use with attr_t -- X/Open says, "these shall be distinct", so + this is a non-conforming implementation. */ + +#define WA_NORMAL A_NORMAL + +#define WA_ALTCHARSET A_ALTCHARSET +#define WA_BLINK A_BLINK +#define WA_BOLD A_BOLD +#define WA_DIM A_DIM +#define WA_INVIS A_INVIS +#define WA_LEFT A_LEFTLINE +#define WA_PROTECT A_PROTECT +#define WA_REVERSE A_REVERSE +#define WA_RIGHT A_RIGHTLINE +#define WA_STANDOUT A_STANDOUT +#define WA_UNDERLINE A_UNDERLINE + +#define WA_HORIZONTAL A_NORMAL +#define WA_LOW A_NORMAL +#define WA_TOP A_NORMAL +#define WA_VERTICAL A_NORMAL + +#define WA_ATTRIBUTES A_ATTRIBUTES + +/*** Alternate character set macros ***/ + +/* 'w' = 32-bit chtype; acs_map[] index | A_ALTCHARSET + 'n' = 16-bit chtype; it gets the fallback set because no bit is + available for A_ALTCHARSET */ + +#ifdef CHTYPE_LONG +# define PDC_ACS(w, n) ((chtype)w | A_ALTCHARSET) +#else +# define PDC_ACS(w, n) ((chtype)n) +#endif + +/* VT100-compatible symbols -- box chars */ + +#define ACS_LRCORNER PDC_ACS('V', '+') +#define ACS_URCORNER PDC_ACS('W', '+') +#define ACS_ULCORNER PDC_ACS('X', '+') +#define ACS_LLCORNER PDC_ACS('Y', '+') +#define ACS_PLUS PDC_ACS('Z', '+') +#define ACS_LTEE PDC_ACS('[', '+') +#define ACS_RTEE PDC_ACS('\\', '+') +#define ACS_BTEE PDC_ACS(']', '+') +#define ACS_TTEE PDC_ACS('^', '+') +#define ACS_HLINE PDC_ACS('_', '-') +#define ACS_VLINE PDC_ACS('`', '|') + +/* PDCurses-only ACS chars. Don't use if ncurses compatibility matters. +Some won't work in non-wide X11 builds (see 'acs_defs.h' for details). */ + +#define ACS_CENT PDC_ACS('{', 'c') +#define ACS_YEN PDC_ACS('|', 'y') +#define ACS_PESETA PDC_ACS('}', 'p') +#define ACS_HALF PDC_ACS('&', '/') +#define ACS_QUARTER PDC_ACS('\'', '/') +#define ACS_LEFT_ANG_QU PDC_ACS(')', '<') +#define ACS_RIGHT_ANG_QU PDC_ACS('*', '>') +#define ACS_D_HLINE PDC_ACS('a', '-') +#define ACS_D_VLINE PDC_ACS('b', '|') +#define ACS_CLUB PDC_ACS( 11, 'C') +#define ACS_HEART PDC_ACS( 12, 'H') +#define ACS_SPADE PDC_ACS( 13, 'S') +#define ACS_SMILE PDC_ACS( 14, 'O') +#define ACS_REV_SMILE PDC_ACS( 15, 'O') +#define ACS_MED_BULLET PDC_ACS( 16, '.') +#define ACS_WHITE_BULLET PDC_ACS( 17, 'O') +#define ACS_PILCROW PDC_ACS( 18, 'O') +#define ACS_SECTION PDC_ACS( 19, 'O') + +#define ACS_SUP2 PDC_ACS(',', '2') +#define ACS_ALPHA PDC_ACS('.', 'a') +#define ACS_BETA PDC_ACS('/', 'b') +#define ACS_GAMMA PDC_ACS('0', 'y') +#define ACS_UP_SIGMA PDC_ACS('1', 'S') +#define ACS_LO_SIGMA PDC_ACS('2', 's') +#define ACS_MU PDC_ACS('4', 'u') +#define ACS_TAU PDC_ACS('5', 't') +#define ACS_UP_PHI PDC_ACS('6', 'F') +#define ACS_THETA PDC_ACS('7', 't') +#define ACS_OMEGA PDC_ACS('8', 'w') +#define ACS_DELTA PDC_ACS('9', 'd') +#define ACS_INFINITY PDC_ACS('-', 'i') +#define ACS_LO_PHI PDC_ACS( 22, 'f') +#define ACS_EPSILON PDC_ACS(':', 'e') +#define ACS_INTERSECT PDC_ACS('e', 'u') +#define ACS_TRIPLE_BAR PDC_ACS('f', '=') +#define ACS_DIVISION PDC_ACS('c', '/') +#define ACS_APPROX_EQ PDC_ACS('d', '~') +#define ACS_SM_BULLET PDC_ACS('g', '.') +#define ACS_SQUARE_ROOT PDC_ACS('i', '!') +#define ACS_UBLOCK PDC_ACS('p', '^') +#define ACS_BBLOCK PDC_ACS('q', '_') +#define ACS_LBLOCK PDC_ACS('r', '<') +#define ACS_RBLOCK PDC_ACS('s', '>') + +#define ACS_A_ORDINAL PDC_ACS(20, 'a') +#define ACS_O_ORDINAL PDC_ACS(21, 'o') +#define ACS_INV_QUERY PDC_ACS(24, '?') +#define ACS_REV_NOT PDC_ACS(25, '!') +#define ACS_NOT PDC_ACS(26, '!') +#define ACS_INV_BANG PDC_ACS(23, '!') +#define ACS_UP_INTEGRAL PDC_ACS(27, '|') +#define ACS_LO_INTEGRAL PDC_ACS(28, '|') +#define ACS_SUP_N PDC_ACS(29, 'n') +#define ACS_CENTER_SQU PDC_ACS(30, 'x') +#define ACS_F_WITH_HOOK PDC_ACS(31, 'f') + +#define ACS_SD_LRCORNER PDC_ACS(';', '+') +#define ACS_SD_URCORNER PDC_ACS('<', '+') +#define ACS_SD_ULCORNER PDC_ACS('=', '+') +#define ACS_SD_LLCORNER PDC_ACS('>', '+') +#define ACS_SD_PLUS PDC_ACS('?', '+') +#define ACS_SD_LTEE PDC_ACS('@', '+') +#define ACS_SD_RTEE PDC_ACS('A', '+') +#define ACS_SD_BTEE PDC_ACS('B', '+') +#define ACS_SD_TTEE PDC_ACS('C', '+') + +#define ACS_D_LRCORNER PDC_ACS('D', '+') +#define ACS_D_URCORNER PDC_ACS('E', '+') +#define ACS_D_ULCORNER PDC_ACS('F', '+') +#define ACS_D_LLCORNER PDC_ACS('G', '+') +#define ACS_D_PLUS PDC_ACS('H', '+') +#define ACS_D_LTEE PDC_ACS('I', '+') +#define ACS_D_RTEE PDC_ACS('J', '+') +#define ACS_D_BTEE PDC_ACS('K', '+') +#define ACS_D_TTEE PDC_ACS('L', '+') + +#define ACS_DS_LRCORNER PDC_ACS('M', '+') +#define ACS_DS_URCORNER PDC_ACS('N', '+') +#define ACS_DS_ULCORNER PDC_ACS('O', '+') +#define ACS_DS_LLCORNER PDC_ACS('P', '+') +#define ACS_DS_PLUS PDC_ACS('Q', '+') +#define ACS_DS_LTEE PDC_ACS('R', '+') +#define ACS_DS_RTEE PDC_ACS('S', '+') +#define ACS_DS_BTEE PDC_ACS('T', '+') +#define ACS_DS_TTEE PDC_ACS('U', '+') + +/* VT100-compatible symbols -- other */ + +#define ACS_S1 PDC_ACS('l', '-') +#define ACS_S9 PDC_ACS('o', '_') +#define ACS_DIAMOND PDC_ACS('j', '+') +#define ACS_CKBOARD PDC_ACS('k', ':') +#define ACS_DEGREE PDC_ACS('w', '\'') +#define ACS_PLMINUS PDC_ACS('x', '#') +#define ACS_BULLET PDC_ACS('h', 'o') + +/* Teletype 5410v1 symbols -- these are defined in SysV curses, but + are not well-supported by most terminals. Stick to VT100 characters + for optimum portability. */ + +#define ACS_LARROW PDC_ACS('!', '<') +#define ACS_RARROW PDC_ACS(' ', '>') +#define ACS_DARROW PDC_ACS('#', 'v') +#define ACS_UARROW PDC_ACS('"', '^') +#define ACS_BOARD PDC_ACS('+', '#') +#define ACS_LTBOARD PDC_ACS('y', '#') +#define ACS_LANTERN PDC_ACS('z', '*') +#define ACS_BLOCK PDC_ACS('t', '#') + +/* That goes double for these -- undocumented SysV symbols. Don't use + them. */ + +#define ACS_S3 PDC_ACS('m', '-') +#define ACS_S7 PDC_ACS('n', '-') +#define ACS_LEQUAL PDC_ACS('u', '<') +#define ACS_GEQUAL PDC_ACS('v', '>') +#define ACS_PI PDC_ACS('$', 'n') +#define ACS_NEQUAL PDC_ACS('%', '+') +#define ACS_STERLING PDC_ACS('~', 'L') + +/* Box char aliases */ + +#define ACS_BSSB ACS_ULCORNER +#define ACS_SSBB ACS_LLCORNER +#define ACS_BBSS ACS_URCORNER +#define ACS_SBBS ACS_LRCORNER +#define ACS_SBSS ACS_RTEE +#define ACS_SSSB ACS_LTEE +#define ACS_SSBS ACS_BTEE +#define ACS_BSSS ACS_TTEE +#define ACS_BSBS ACS_HLINE +#define ACS_SBSB ACS_VLINE +#define ACS_SSSS ACS_PLUS + +/* cchar_t aliases */ + +#ifdef PDC_WIDE +# define WACS_LRCORNER (&(acs_map['V'])) +# define WACS_URCORNER (&(acs_map['W'])) +# define WACS_ULCORNER (&(acs_map['X'])) +# define WACS_LLCORNER (&(acs_map['Y'])) +# define WACS_PLUS (&(acs_map['Z'])) +# define WACS_LTEE (&(acs_map['['])) +# define WACS_RTEE (&(acs_map['\\'])) +# define WACS_BTEE (&(acs_map[']'])) +# define WACS_TTEE (&(acs_map['^'])) +# define WACS_HLINE (&(acs_map['_'])) +# define WACS_VLINE (&(acs_map['`'])) + +# define WACS_CENT (&(acs_map['{'])) +# define WACS_YEN (&(acs_map['|'])) +# define WACS_PESETA (&(acs_map['}'])) +# define WACS_HALF (&(acs_map['&'])) +# define WACS_QUARTER (&(acs_map['\''])) +# define WACS_LEFT_ANG_QU (&(acs_map[')'])) +# define WACS_RIGHT_ANG_QU (&(acs_map['*'])) +# define WACS_D_HLINE (&(acs_map['a'])) +# define WACS_D_VLINE (&(acs_map['b'])) +# define WACS_CLUB (&(acs_map[ 11])) +# define WACS_HEART (&(acs_map[ 12])) +# define WACS_SPADE (&(acs_map[ 13])) +# define WACS_SMILE (&(acs_map[ 14])) +# define WACS_REV_SMILE (&(acs_map[ 15])) +# define WACS_MED_BULLET (&(acs_map[ 16])) +# define WACS_WHITE_BULLET (&(acs_map[ 17])) +# define WACS_PILCROW (&(acs_map[ 18])) +# define WACS_SECTION (&(acs_map[ 19])) + +# define WACS_SUP2 (&(acs_map[','])) +# define WACS_ALPHA (&(acs_map['.'])) +# define WACS_BETA (&(acs_map['/'])) +# define WACS_GAMMA (&(acs_map['0'])) +# define WACS_UP_SIGMA (&(acs_map['1'])) +# define WACS_LO_SIGMA (&(acs_map['2'])) +# define WACS_MU (&(acs_map['4'])) +# define WACS_TAU (&(acs_map['5'])) +# define WACS_UP_PHI (&(acs_map['6'])) +# define WACS_THETA (&(acs_map['7'])) +# define WACS_OMEGA (&(acs_map['8'])) +# define WACS_DELTA (&(acs_map['9'])) +# define WACS_INFINITY (&(acs_map['-'])) +# define WACS_LO_PHI (&(acs_map[ 22])) +# define WACS_EPSILON (&(acs_map[':'])) +# define WACS_INTERSECT (&(acs_map['e'])) +# define WACS_TRIPLE_BAR (&(acs_map['f'])) +# define WACS_DIVISION (&(acs_map['c'])) +# define WACS_APPROX_EQ (&(acs_map['d'])) +# define WACS_SM_BULLET (&(acs_map['g'])) +# define WACS_SQUARE_ROOT (&(acs_map['i'])) +# define WACS_UBLOCK (&(acs_map['p'])) +# define WACS_BBLOCK (&(acs_map['q'])) +# define WACS_LBLOCK (&(acs_map['r'])) +# define WACS_RBLOCK (&(acs_map['s'])) + +# define WACS_A_ORDINAL (&(acs_map[20])) +# define WACS_O_ORDINAL (&(acs_map[21])) +# define WACS_INV_QUERY (&(acs_map[24])) +# define WACS_REV_NOT (&(acs_map[25])) +# define WACS_NOT (&(acs_map[26])) +# define WACS_INV_BANG (&(acs_map[23])) +# define WACS_UP_INTEGRAL (&(acs_map[27])) +# define WACS_LO_INTEGRAL (&(acs_map[28])) +# define WACS_SUP_N (&(acs_map[29])) +# define WACS_CENTER_SQU (&(acs_map[30])) +# define WACS_F_WITH_HOOK (&(acs_map[31])) + +# define WACS_SD_LRCORNER (&(acs_map[';'])) +# define WACS_SD_URCORNER (&(acs_map['<'])) +# define WACS_SD_ULCORNER (&(acs_map['='])) +# define WACS_SD_LLCORNER (&(acs_map['>'])) +# define WACS_SD_PLUS (&(acs_map['?'])) +# define WACS_SD_LTEE (&(acs_map['@'])) +# define WACS_SD_RTEE (&(acs_map['A'])) +# define WACS_SD_BTEE (&(acs_map['B'])) +# define WACS_SD_TTEE (&(acs_map['C'])) + +# define WACS_D_LRCORNER (&(acs_map['D'])) +# define WACS_D_URCORNER (&(acs_map['E'])) +# define WACS_D_ULCORNER (&(acs_map['F'])) +# define WACS_D_LLCORNER (&(acs_map['G'])) +# define WACS_D_PLUS (&(acs_map['H'])) +# define WACS_D_LTEE (&(acs_map['I'])) +# define WACS_D_RTEE (&(acs_map['J'])) +# define WACS_D_BTEE (&(acs_map['K'])) +# define WACS_D_TTEE (&(acs_map['L'])) + +# define WACS_DS_LRCORNER (&(acs_map['M'])) +# define WACS_DS_URCORNER (&(acs_map['N'])) +# define WACS_DS_ULCORNER (&(acs_map['O'])) +# define WACS_DS_LLCORNER (&(acs_map['P'])) +# define WACS_DS_PLUS (&(acs_map['Q'])) +# define WACS_DS_LTEE (&(acs_map['R'])) +# define WACS_DS_RTEE (&(acs_map['S'])) +# define WACS_DS_BTEE (&(acs_map['T'])) +# define WACS_DS_TTEE (&(acs_map['U'])) + +# define WACS_S1 (&(acs_map['l'])) +# define WACS_S9 (&(acs_map['o'])) +# define WACS_DIAMOND (&(acs_map['j'])) +# define WACS_CKBOARD (&(acs_map['k'])) +# define WACS_DEGREE (&(acs_map['w'])) +# define WACS_PLMINUS (&(acs_map['x'])) +# define WACS_BULLET (&(acs_map['h'])) + + +# define WACS_LARROW (&(acs_map['!'])) +# define WACS_RARROW (&(acs_map[' '])) +# define WACS_DARROW (&(acs_map['#'])) +# define WACS_UARROW (&(acs_map['"'])) +# define WACS_BOARD (&(acs_map['+'])) +# define WACS_LTBOARD (&(acs_map['y'])) +# define WACS_LANTERN (&(acs_map['z'])) +# define WACS_BLOCK (&(acs_map['t'])) + +# define WACS_S3 (&(acs_map['m'])) +# define WACS_S7 (&(acs_map['n'])) +# define WACS_LEQUAL (&(acs_map['u'])) +# define WACS_GEQUAL (&(acs_map['v'])) +# define WACS_PI (&(acs_map['$'])) +# define WACS_NEQUAL (&(acs_map['%'])) +# define WACS_STERLING (&(acs_map['~'])) + +# define WACS_BSSB WACS_ULCORNER +# define WACS_SSBB WACS_LLCORNER +# define WACS_BBSS WACS_URCORNER +# define WACS_SBBS WACS_LRCORNER +# define WACS_SBSS WACS_RTEE +# define WACS_SSSB WACS_LTEE +# define WACS_SSBS WACS_BTEE +# define WACS_BSSS WACS_TTEE +# define WACS_BSBS WACS_HLINE +# define WACS_SBSB WACS_VLINE +# define WACS_SSSS WACS_PLUS +#endif + +/*** Color macros ***/ + +#define COLOR_BLACK 0 + +#ifdef PDC_RGB /* RGB */ +# define COLOR_RED 1 +# define COLOR_GREEN 2 +# define COLOR_BLUE 4 +#else /* BGR */ +# define COLOR_BLUE 1 +# define COLOR_GREEN 2 +# define COLOR_RED 4 +#endif + +#define COLOR_CYAN (COLOR_BLUE | COLOR_GREEN) +#define COLOR_MAGENTA (COLOR_RED | COLOR_BLUE) +#define COLOR_YELLOW (COLOR_RED | COLOR_GREEN) + +#define COLOR_WHITE 7 + +/*---------------------------------------------------------------------- + * + * Function and Keypad Key Definitions + * Many are just for compatibility + * + */ + +#ifdef PDC_WIDE + #define KEY_OFFSET 0xec00 +#else + #define KEY_OFFSET 0x100 +#endif + +#define KEY_CODE_YES (KEY_OFFSET + 0x00) /* If get_wch() gives a key code */ + +#define KEY_BREAK (KEY_OFFSET + 0x01) /* Not on PC KBD */ +#define KEY_DOWN (KEY_OFFSET + 0x02) /* Down arrow key */ +#define KEY_UP (KEY_OFFSET + 0x03) /* Up arrow key */ +#define KEY_LEFT (KEY_OFFSET + 0x04) /* Left arrow key */ +#define KEY_RIGHT (KEY_OFFSET + 0x05) /* Right arrow key */ +#define KEY_HOME (KEY_OFFSET + 0x06) /* home key */ +#define KEY_BACKSPACE (KEY_OFFSET + 0x07) /* not on pc */ +#define KEY_F0 (KEY_OFFSET + 0x08) /* function keys; 64 reserved */ + +#define KEY_DL (KEY_OFFSET + 0x48) /* delete line */ +#define KEY_IL (KEY_OFFSET + 0x49) /* insert line */ +#define KEY_DC (KEY_OFFSET + 0x4a) /* delete character */ +#define KEY_IC (KEY_OFFSET + 0x4b) /* insert char or enter ins mode */ +#define KEY_EIC (KEY_OFFSET + 0x4c) /* exit insert char mode */ +#define KEY_CLEAR (KEY_OFFSET + 0x4d) /* clear screen */ +#define KEY_EOS (KEY_OFFSET + 0x4e) /* clear to end of screen */ +#define KEY_EOL (KEY_OFFSET + 0x4f) /* clear to end of line */ +#define KEY_SF (KEY_OFFSET + 0x50) /* scroll 1 line forward */ +#define KEY_SR (KEY_OFFSET + 0x51) /* scroll 1 line back (reverse) */ +#define KEY_NPAGE (KEY_OFFSET + 0x52) /* next page */ +#define KEY_PPAGE (KEY_OFFSET + 0x53) /* previous page */ +#define KEY_STAB (KEY_OFFSET + 0x54) /* set tab */ +#define KEY_CTAB (KEY_OFFSET + 0x55) /* clear tab */ +#define KEY_CATAB (KEY_OFFSET + 0x56) /* clear all tabs */ +#define KEY_ENTER (KEY_OFFSET + 0x57) /* enter or send (unreliable) */ +#define KEY_SRESET (KEY_OFFSET + 0x58) /* soft/reset (partial/unreliable) */ +#define KEY_RESET (KEY_OFFSET + 0x59) /* reset/hard reset (unreliable) */ +#define KEY_PRINT (KEY_OFFSET + 0x5a) /* print/copy */ +#define KEY_LL (KEY_OFFSET + 0x5b) /* home down/bottom (lower left) */ +#define KEY_ABORT (KEY_OFFSET + 0x5c) /* abort/terminate key (any) */ +#define KEY_SHELP (KEY_OFFSET + 0x5d) /* short help */ +#define KEY_LHELP (KEY_OFFSET + 0x5e) /* long help */ +#define KEY_BTAB (KEY_OFFSET + 0x5f) /* Back tab key */ +#define KEY_BEG (KEY_OFFSET + 0x60) /* beg(inning) key */ +#define KEY_CANCEL (KEY_OFFSET + 0x61) /* cancel key */ +#define KEY_CLOSE (KEY_OFFSET + 0x62) /* close key */ +#define KEY_COMMAND (KEY_OFFSET + 0x63) /* cmd (command) key */ +#define KEY_COPY (KEY_OFFSET + 0x64) /* copy key */ +#define KEY_CREATE (KEY_OFFSET + 0x65) /* create key */ +#define KEY_END (KEY_OFFSET + 0x66) /* end key */ +#define KEY_EXIT (KEY_OFFSET + 0x67) /* exit key */ +#define KEY_FIND (KEY_OFFSET + 0x68) /* find key */ +#define KEY_HELP (KEY_OFFSET + 0x69) /* help key */ +#define KEY_MARK (KEY_OFFSET + 0x6a) /* mark key */ +#define KEY_MESSAGE (KEY_OFFSET + 0x6b) /* message key */ +#define KEY_MOVE (KEY_OFFSET + 0x6c) /* move key */ +#define KEY_NEXT (KEY_OFFSET + 0x6d) /* next object key */ +#define KEY_OPEN (KEY_OFFSET + 0x6e) /* open key */ +#define KEY_OPTIONS (KEY_OFFSET + 0x6f) /* options key */ +#define KEY_PREVIOUS (KEY_OFFSET + 0x70) /* previous object key */ +#define KEY_REDO (KEY_OFFSET + 0x71) /* redo key */ +#define KEY_REFERENCE (KEY_OFFSET + 0x72) /* ref(erence) key */ +#define KEY_REFRESH (KEY_OFFSET + 0x73) /* refresh key */ +#define KEY_REPLACE (KEY_OFFSET + 0x74) /* replace key */ +#define KEY_RESTART (KEY_OFFSET + 0x75) /* restart key */ +#define KEY_RESUME (KEY_OFFSET + 0x76) /* resume key */ +#define KEY_SAVE (KEY_OFFSET + 0x77) /* save key */ +#define KEY_SBEG (KEY_OFFSET + 0x78) /* shifted beginning key */ +#define KEY_SCANCEL (KEY_OFFSET + 0x79) /* shifted cancel key */ +#define KEY_SCOMMAND (KEY_OFFSET + 0x7a) /* shifted command key */ +#define KEY_SCOPY (KEY_OFFSET + 0x7b) /* shifted copy key */ +#define KEY_SCREATE (KEY_OFFSET + 0x7c) /* shifted create key */ +#define KEY_SDC (KEY_OFFSET + 0x7d) /* shifted delete char key */ +#define KEY_SDL (KEY_OFFSET + 0x7e) /* shifted delete line key */ +#define KEY_SELECT (KEY_OFFSET + 0x7f) /* select key */ +#define KEY_SEND (KEY_OFFSET + 0x80) /* shifted end key */ +#define KEY_SEOL (KEY_OFFSET + 0x81) /* shifted clear line key */ +#define KEY_SEXIT (KEY_OFFSET + 0x82) /* shifted exit key */ +#define KEY_SFIND (KEY_OFFSET + 0x83) /* shifted find key */ +#define KEY_SHOME (KEY_OFFSET + 0x84) /* shifted home key */ +#define KEY_SIC (KEY_OFFSET + 0x85) /* shifted input key */ + +#define KEY_SLEFT (KEY_OFFSET + 0x87) /* shifted left arrow key */ +#define KEY_SMESSAGE (KEY_OFFSET + 0x88) /* shifted message key */ +#define KEY_SMOVE (KEY_OFFSET + 0x89) /* shifted move key */ +#define KEY_SNEXT (KEY_OFFSET + 0x8a) /* shifted next key */ +#define KEY_SOPTIONS (KEY_OFFSET + 0x8b) /* shifted options key */ +#define KEY_SPREVIOUS (KEY_OFFSET + 0x8c) /* shifted prev key */ +#define KEY_SPRINT (KEY_OFFSET + 0x8d) /* shifted print key */ +#define KEY_SREDO (KEY_OFFSET + 0x8e) /* shifted redo key */ +#define KEY_SREPLACE (KEY_OFFSET + 0x8f) /* shifted replace key */ +#define KEY_SRIGHT (KEY_OFFSET + 0x90) /* shifted right arrow */ +#define KEY_SRSUME (KEY_OFFSET + 0x91) /* shifted resume key */ +#define KEY_SSAVE (KEY_OFFSET + 0x92) /* shifted save key */ +#define KEY_SSUSPEND (KEY_OFFSET + 0x93) /* shifted suspend key */ +#define KEY_SUNDO (KEY_OFFSET + 0x94) /* shifted undo key */ +#define KEY_SUSPEND (KEY_OFFSET + 0x95) /* suspend key */ +#define KEY_UNDO (KEY_OFFSET + 0x96) /* undo key */ + +/* PDCurses-specific key definitions -- PC only */ + +#define ALT_0 (KEY_OFFSET + 0x97) +#define ALT_1 (KEY_OFFSET + 0x98) +#define ALT_2 (KEY_OFFSET + 0x99) +#define ALT_3 (KEY_OFFSET + 0x9a) +#define ALT_4 (KEY_OFFSET + 0x9b) +#define ALT_5 (KEY_OFFSET + 0x9c) +#define ALT_6 (KEY_OFFSET + 0x9d) +#define ALT_7 (KEY_OFFSET + 0x9e) +#define ALT_8 (KEY_OFFSET + 0x9f) +#define ALT_9 (KEY_OFFSET + 0xa0) +#define ALT_A (KEY_OFFSET + 0xa1) +#define ALT_B (KEY_OFFSET + 0xa2) +#define ALT_C (KEY_OFFSET + 0xa3) +#define ALT_D (KEY_OFFSET + 0xa4) +#define ALT_E (KEY_OFFSET + 0xa5) +#define ALT_F (KEY_OFFSET + 0xa6) +#define ALT_G (KEY_OFFSET + 0xa7) +#define ALT_H (KEY_OFFSET + 0xa8) +#define ALT_I (KEY_OFFSET + 0xa9) +#define ALT_J (KEY_OFFSET + 0xaa) +#define ALT_K (KEY_OFFSET + 0xab) +#define ALT_L (KEY_OFFSET + 0xac) +#define ALT_M (KEY_OFFSET + 0xad) +#define ALT_N (KEY_OFFSET + 0xae) +#define ALT_O (KEY_OFFSET + 0xaf) +#define ALT_P (KEY_OFFSET + 0xb0) +#define ALT_Q (KEY_OFFSET + 0xb1) +#define ALT_R (KEY_OFFSET + 0xb2) +#define ALT_S (KEY_OFFSET + 0xb3) +#define ALT_T (KEY_OFFSET + 0xb4) +#define ALT_U (KEY_OFFSET + 0xb5) +#define ALT_V (KEY_OFFSET + 0xb6) +#define ALT_W (KEY_OFFSET + 0xb7) +#define ALT_X (KEY_OFFSET + 0xb8) +#define ALT_Y (KEY_OFFSET + 0xb9) +#define ALT_Z (KEY_OFFSET + 0xba) + +#define CTL_LEFT (KEY_OFFSET + 0xbb) /* Control-Left-Arrow */ +#define CTL_RIGHT (KEY_OFFSET + 0xbc) +#define CTL_PGUP (KEY_OFFSET + 0xbd) +#define CTL_PGDN (KEY_OFFSET + 0xbe) +#define CTL_HOME (KEY_OFFSET + 0xbf) +#define CTL_END (KEY_OFFSET + 0xc0) + +#define KEY_A1 (KEY_OFFSET + 0xc1) /* upper left on Virtual keypad */ +#define KEY_A2 (KEY_OFFSET + 0xc2) /* upper middle on Virt. keypad */ +#define KEY_A3 (KEY_OFFSET + 0xc3) /* upper right on Vir. keypad */ +#define KEY_B1 (KEY_OFFSET + 0xc4) /* middle left on Virt. keypad */ +#define KEY_B2 (KEY_OFFSET + 0xc5) /* center on Virt. keypad */ +#define KEY_B3 (KEY_OFFSET + 0xc6) /* middle right on Vir. keypad */ +#define KEY_C1 (KEY_OFFSET + 0xc7) /* lower left on Virt. keypad */ +#define KEY_C2 (KEY_OFFSET + 0xc8) /* lower middle on Virt. keypad */ +#define KEY_C3 (KEY_OFFSET + 0xc9) /* lower right on Vir. keypad */ + +#define PADSLASH (KEY_OFFSET + 0xca) /* slash on keypad */ +#define PADENTER (KEY_OFFSET + 0xcb) /* enter on keypad */ +#define CTL_PADENTER (KEY_OFFSET + 0xcc) /* ctl-enter on keypad */ +#define ALT_PADENTER (KEY_OFFSET + 0xcd) /* alt-enter on keypad */ +#define PADSTOP (KEY_OFFSET + 0xce) /* stop on keypad */ +#define PADSTAR (KEY_OFFSET + 0xcf) /* star on keypad */ +#define PADMINUS (KEY_OFFSET + 0xd0) /* minus on keypad */ +#define PADPLUS (KEY_OFFSET + 0xd1) /* plus on keypad */ +#define CTL_PADSTOP (KEY_OFFSET + 0xd2) /* ctl-stop on keypad */ +#define CTL_PADCENTER (KEY_OFFSET + 0xd3) /* ctl-enter on keypad */ +#define CTL_PADPLUS (KEY_OFFSET + 0xd4) /* ctl-plus on keypad */ +#define CTL_PADMINUS (KEY_OFFSET + 0xd5) /* ctl-minus on keypad */ +#define CTL_PADSLASH (KEY_OFFSET + 0xd6) /* ctl-slash on keypad */ +#define CTL_PADSTAR (KEY_OFFSET + 0xd7) /* ctl-star on keypad */ +#define ALT_PADPLUS (KEY_OFFSET + 0xd8) /* alt-plus on keypad */ +#define ALT_PADMINUS (KEY_OFFSET + 0xd9) /* alt-minus on keypad */ +#define ALT_PADSLASH (KEY_OFFSET + 0xda) /* alt-slash on keypad */ +#define ALT_PADSTAR (KEY_OFFSET + 0xdb) /* alt-star on keypad */ +#define ALT_PADSTOP (KEY_OFFSET + 0xdc) /* alt-stop on keypad */ +#define CTL_INS (KEY_OFFSET + 0xdd) /* ctl-insert */ +#define ALT_DEL (KEY_OFFSET + 0xde) /* alt-delete */ +#define ALT_INS (KEY_OFFSET + 0xdf) /* alt-insert */ +#define CTL_UP (KEY_OFFSET + 0xe0) /* ctl-up arrow */ +#define CTL_DOWN (KEY_OFFSET + 0xe1) /* ctl-down arrow */ +#define CTL_TAB (KEY_OFFSET + 0xe2) /* ctl-tab */ +#define ALT_TAB (KEY_OFFSET + 0xe3) +#define ALT_MINUS (KEY_OFFSET + 0xe4) +#define ALT_EQUAL (KEY_OFFSET + 0xe5) +#define ALT_HOME (KEY_OFFSET + 0xe6) +#define ALT_PGUP (KEY_OFFSET + 0xe7) +#define ALT_PGDN (KEY_OFFSET + 0xe8) +#define ALT_END (KEY_OFFSET + 0xe9) +#define ALT_UP (KEY_OFFSET + 0xea) /* alt-up arrow */ +#define ALT_DOWN (KEY_OFFSET + 0xeb) /* alt-down arrow */ +#define ALT_RIGHT (KEY_OFFSET + 0xec) /* alt-right arrow */ +#define ALT_LEFT (KEY_OFFSET + 0xed) /* alt-left arrow */ +#define ALT_ENTER (KEY_OFFSET + 0xee) /* alt-enter */ +#define ALT_ESC (KEY_OFFSET + 0xef) /* alt-escape */ +#define ALT_BQUOTE (KEY_OFFSET + 0xf0) /* alt-back quote */ +#define ALT_LBRACKET (KEY_OFFSET + 0xf1) /* alt-left bracket */ +#define ALT_RBRACKET (KEY_OFFSET + 0xf2) /* alt-right bracket */ +#define ALT_SEMICOLON (KEY_OFFSET + 0xf3) /* alt-semi-colon */ +#define ALT_FQUOTE (KEY_OFFSET + 0xf4) /* alt-forward quote */ +#define ALT_COMMA (KEY_OFFSET + 0xf5) /* alt-comma */ +#define ALT_STOP (KEY_OFFSET + 0xf6) /* alt-stop */ +#define ALT_FSLASH (KEY_OFFSET + 0xf7) /* alt-forward slash */ +#define ALT_BKSP (KEY_OFFSET + 0xf8) /* alt-backspace */ +#define CTL_BKSP (KEY_OFFSET + 0xf9) /* ctl-backspace */ +#define PAD0 (KEY_OFFSET + 0xfa) /* keypad 0 */ + +#define CTL_PAD0 (KEY_OFFSET + 0xfb) /* ctl-keypad 0 */ +#define CTL_PAD1 (KEY_OFFSET + 0xfc) +#define CTL_PAD2 (KEY_OFFSET + 0xfd) +#define CTL_PAD3 (KEY_OFFSET + 0xfe) +#define CTL_PAD4 (KEY_OFFSET + 0xff) +#define CTL_PAD5 (KEY_OFFSET + 0x100) +#define CTL_PAD6 (KEY_OFFSET + 0x101) +#define CTL_PAD7 (KEY_OFFSET + 0x102) +#define CTL_PAD8 (KEY_OFFSET + 0x103) +#define CTL_PAD9 (KEY_OFFSET + 0x104) + +#define ALT_PAD0 (KEY_OFFSET + 0x105) /* alt-keypad 0 */ +#define ALT_PAD1 (KEY_OFFSET + 0x106) +#define ALT_PAD2 (KEY_OFFSET + 0x107) +#define ALT_PAD3 (KEY_OFFSET + 0x108) +#define ALT_PAD4 (KEY_OFFSET + 0x109) +#define ALT_PAD5 (KEY_OFFSET + 0x10a) +#define ALT_PAD6 (KEY_OFFSET + 0x10b) +#define ALT_PAD7 (KEY_OFFSET + 0x10c) +#define ALT_PAD8 (KEY_OFFSET + 0x10d) +#define ALT_PAD9 (KEY_OFFSET + 0x10e) + +#define CTL_DEL (KEY_OFFSET + 0x10f) /* clt-delete */ +#define ALT_BSLASH (KEY_OFFSET + 0x110) /* alt-back slash */ +#define CTL_ENTER (KEY_OFFSET + 0x111) /* ctl-enter */ + +#define SHF_PADENTER (KEY_OFFSET + 0x112) /* shift-enter on keypad */ +#define SHF_PADSLASH (KEY_OFFSET + 0x113) /* shift-slash on keypad */ +#define SHF_PADSTAR (KEY_OFFSET + 0x114) /* shift-star on keypad */ +#define SHF_PADPLUS (KEY_OFFSET + 0x115) /* shift-plus on keypad */ +#define SHF_PADMINUS (KEY_OFFSET + 0x116) /* shift-minus on keypad */ +#define SHF_UP (KEY_OFFSET + 0x117) /* shift-up on keypad */ +#define SHF_DOWN (KEY_OFFSET + 0x118) /* shift-down on keypad */ +#define SHF_IC (KEY_OFFSET + 0x119) /* shift-insert on keypad */ +#define SHF_DC (KEY_OFFSET + 0x11a) /* shift-delete on keypad */ + +#define KEY_MOUSE (KEY_OFFSET + 0x11b) /* "mouse" key */ +#define KEY_SHIFT_L (KEY_OFFSET + 0x11c) /* Left-shift */ +#define KEY_SHIFT_R (KEY_OFFSET + 0x11d) /* Right-shift */ +#define KEY_CONTROL_L (KEY_OFFSET + 0x11e) /* Left-control */ +#define KEY_CONTROL_R (KEY_OFFSET + 0x11f) /* Right-control */ +#define KEY_ALT_L (KEY_OFFSET + 0x120) /* Left-alt */ +#define KEY_ALT_R (KEY_OFFSET + 0x121) /* Right-alt */ +#define KEY_RESIZE (KEY_OFFSET + 0x122) /* Window resize */ +#define KEY_SUP (KEY_OFFSET + 0x123) /* Shifted up arrow */ +#define KEY_SDOWN (KEY_OFFSET + 0x124) /* Shifted down arrow */ + + /* The following were added 2011 Sep 14, and are */ + /* not returned by most flavors of PDCurses: */ + +#define CTL_SEMICOLON (KEY_OFFSET + 0x125) +#define CTL_EQUAL (KEY_OFFSET + 0x126) +#define CTL_COMMA (KEY_OFFSET + 0x127) +#define CTL_MINUS (KEY_OFFSET + 0x128) +#define CTL_STOP (KEY_OFFSET + 0x129) +#define CTL_FSLASH (KEY_OFFSET + 0x12a) +#define CTL_BQUOTE (KEY_OFFSET + 0x12b) + +#define KEY_APPS (KEY_OFFSET + 0x12c) +#define KEY_SAPPS (KEY_OFFSET + 0x12d) +#define CTL_APPS (KEY_OFFSET + 0x12e) +#define ALT_APPS (KEY_OFFSET + 0x12f) + +#define KEY_PAUSE (KEY_OFFSET + 0x130) +#define KEY_SPAUSE (KEY_OFFSET + 0x131) +#define CTL_PAUSE (KEY_OFFSET + 0x132) + +#define KEY_PRINTSCREEN (KEY_OFFSET + 0x133) +#define ALT_PRINTSCREEN (KEY_OFFSET + 0x134) +#define KEY_SCROLLLOCK (KEY_OFFSET + 0x135) +#define ALT_SCROLLLOCK (KEY_OFFSET + 0x136) + +#define CTL_0 (KEY_OFFSET + 0x137) +#define CTL_1 (KEY_OFFSET + 0x138) +#define CTL_2 (KEY_OFFSET + 0x139) +#define CTL_3 (KEY_OFFSET + 0x13a) +#define CTL_4 (KEY_OFFSET + 0x13b) +#define CTL_5 (KEY_OFFSET + 0x13c) +#define CTL_6 (KEY_OFFSET + 0x13d) +#define CTL_7 (KEY_OFFSET + 0x13e) +#define CTL_8 (KEY_OFFSET + 0x13f) +#define CTL_9 (KEY_OFFSET + 0x140) + +#define KEY_BROWSER_BACK (KEY_OFFSET + 0x141) +#define KEY_SBROWSER_BACK (KEY_OFFSET + 0x142) +#define KEY_CBROWSER_BACK (KEY_OFFSET + 0x143) +#define KEY_ABROWSER_BACK (KEY_OFFSET + 0x144) +#define KEY_BROWSER_FWD (KEY_OFFSET + 0x145) +#define KEY_SBROWSER_FWD (KEY_OFFSET + 0x146) +#define KEY_CBROWSER_FWD (KEY_OFFSET + 0x147) +#define KEY_ABROWSER_FWD (KEY_OFFSET + 0x148) +#define KEY_BROWSER_REF (KEY_OFFSET + 0x149) +#define KEY_SBROWSER_REF (KEY_OFFSET + 0x14A) +#define KEY_CBROWSER_REF (KEY_OFFSET + 0x14B) +#define KEY_ABROWSER_REF (KEY_OFFSET + 0x14C) +#define KEY_BROWSER_STOP (KEY_OFFSET + 0x14D) +#define KEY_SBROWSER_STOP (KEY_OFFSET + 0x14E) +#define KEY_CBROWSER_STOP (KEY_OFFSET + 0x14F) +#define KEY_ABROWSER_STOP (KEY_OFFSET + 0x150) +#define KEY_SEARCH (KEY_OFFSET + 0x151) +#define KEY_SSEARCH (KEY_OFFSET + 0x152) +#define KEY_CSEARCH (KEY_OFFSET + 0x153) +#define KEY_ASEARCH (KEY_OFFSET + 0x154) +#define KEY_FAVORITES (KEY_OFFSET + 0x155) +#define KEY_SFAVORITES (KEY_OFFSET + 0x156) +#define KEY_CFAVORITES (KEY_OFFSET + 0x157) +#define KEY_AFAVORITES (KEY_OFFSET + 0x158) +#define KEY_BROWSER_HOME (KEY_OFFSET + 0x159) +#define KEY_SBROWSER_HOME (KEY_OFFSET + 0x15A) +#define KEY_CBROWSER_HOME (KEY_OFFSET + 0x15B) +#define KEY_ABROWSER_HOME (KEY_OFFSET + 0x15C) +#define KEY_VOLUME_MUTE (KEY_OFFSET + 0x15D) +#define KEY_SVOLUME_MUTE (KEY_OFFSET + 0x15E) +#define KEY_CVOLUME_MUTE (KEY_OFFSET + 0x15F) +#define KEY_AVOLUME_MUTE (KEY_OFFSET + 0x160) +#define KEY_VOLUME_DOWN (KEY_OFFSET + 0x161) +#define KEY_SVOLUME_DOWN (KEY_OFFSET + 0x162) +#define KEY_CVOLUME_DOWN (KEY_OFFSET + 0x163) +#define KEY_AVOLUME_DOWN (KEY_OFFSET + 0x164) +#define KEY_VOLUME_UP (KEY_OFFSET + 0x165) +#define KEY_SVOLUME_UP (KEY_OFFSET + 0x166) +#define KEY_CVOLUME_UP (KEY_OFFSET + 0x167) +#define KEY_AVOLUME_UP (KEY_OFFSET + 0x168) +#define KEY_NEXT_TRACK (KEY_OFFSET + 0x169) +#define KEY_SNEXT_TRACK (KEY_OFFSET + 0x16A) +#define KEY_CNEXT_TRACK (KEY_OFFSET + 0x16B) +#define KEY_ANEXT_TRACK (KEY_OFFSET + 0x16C) +#define KEY_PREV_TRACK (KEY_OFFSET + 0x16D) +#define KEY_SPREV_TRACK (KEY_OFFSET + 0x16E) +#define KEY_CPREV_TRACK (KEY_OFFSET + 0x16F) +#define KEY_APREV_TRACK (KEY_OFFSET + 0x170) +#define KEY_MEDIA_STOP (KEY_OFFSET + 0x171) +#define KEY_SMEDIA_STOP (KEY_OFFSET + 0x172) +#define KEY_CMEDIA_STOP (KEY_OFFSET + 0x173) +#define KEY_AMEDIA_STOP (KEY_OFFSET + 0x174) +#define KEY_PLAY_PAUSE (KEY_OFFSET + 0x175) +#define KEY_SPLAY_PAUSE (KEY_OFFSET + 0x176) +#define KEY_CPLAY_PAUSE (KEY_OFFSET + 0x177) +#define KEY_APLAY_PAUSE (KEY_OFFSET + 0x178) +#define KEY_LAUNCH_MAIL (KEY_OFFSET + 0x179) +#define KEY_SLAUNCH_MAIL (KEY_OFFSET + 0x17A) +#define KEY_CLAUNCH_MAIL (KEY_OFFSET + 0x17B) +#define KEY_ALAUNCH_MAIL (KEY_OFFSET + 0x17C) +#define KEY_MEDIA_SELECT (KEY_OFFSET + 0x17D) +#define KEY_SMEDIA_SELECT (KEY_OFFSET + 0x17E) +#define KEY_CMEDIA_SELECT (KEY_OFFSET + 0x17F) +#define KEY_AMEDIA_SELECT (KEY_OFFSET + 0x180) +#define KEY_LAUNCH_APP1 (KEY_OFFSET + 0x181) +#define KEY_SLAUNCH_APP1 (KEY_OFFSET + 0x182) +#define KEY_CLAUNCH_APP1 (KEY_OFFSET + 0x183) +#define KEY_ALAUNCH_APP1 (KEY_OFFSET + 0x184) +#define KEY_LAUNCH_APP2 (KEY_OFFSET + 0x185) +#define KEY_SLAUNCH_APP2 (KEY_OFFSET + 0x186) +#define KEY_CLAUNCH_APP2 (KEY_OFFSET + 0x187) +#define KEY_ALAUNCH_APP2 (KEY_OFFSET + 0x188) + +#define KEY_MIN KEY_BREAK /* Minimum curses key value */ +#define KEY_MAX KEY_ALAUNCH_APP2 /* Maximum curses key */ + +#define KEY_F(n) (KEY_F0 + (n)) + +/*---------------------------------------------------------------------- + * + * PDCurses Function Declarations + * + */ + +/* Standard */ + +PDCEX int addch(const chtype); +PDCEX int addchnstr(const chtype *, int); +PDCEX int addchstr(const chtype *); +PDCEX int addnstr(const char *, int); +PDCEX int addstr(const char *); +PDCEX int attroff(chtype); +PDCEX int attron(chtype); +PDCEX int attrset(chtype); +PDCEX int attr_get(attr_t *, short *, void *); +PDCEX int attr_off(attr_t, void *); +PDCEX int attr_on(attr_t, void *); +PDCEX int attr_set(attr_t, short, void *); +PDCEX int baudrate(void); +PDCEX int beep(void); +PDCEX int bkgd(chtype); +PDCEX void bkgdset(chtype); +PDCEX int border(chtype, chtype, chtype, chtype, + chtype, chtype, chtype, chtype); +PDCEX int box(WINDOW *, chtype, chtype); +PDCEX bool can_change_color(void); +PDCEX int cbreak(void); +PDCEX int chgat(int, attr_t, short, const void *); +PDCEX int clearok(WINDOW *, bool); +PDCEX int clear(void); +PDCEX int clrtobot(void); +PDCEX int clrtoeol(void); +PDCEX int color_content(short, short *, short *, short *); +PDCEX int color_set(short, void *); +PDCEX int copywin(const WINDOW *, WINDOW *, int, int, int, + int, int, int, int); +PDCEX int curs_set(int); +PDCEX int def_prog_mode(void); +PDCEX int def_shell_mode(void); +PDCEX int delay_output(int); +PDCEX int delch(void); +PDCEX int deleteln(void); +PDCEX void delscreen(SCREEN *); +PDCEX int delwin(WINDOW *); +PDCEX WINDOW *derwin(WINDOW *, int, int, int, int); +PDCEX int doupdate(void); +PDCEX WINDOW *dupwin(WINDOW *); +PDCEX int echochar(const chtype); +PDCEX int echo(void); +PDCEX int endwin(void); +PDCEX char erasechar(void); +PDCEX int erase(void); +PDCEX void filter(void); +PDCEX int flash(void); +PDCEX int flushinp(void); +PDCEX chtype getbkgd(WINDOW *); +PDCEX int getnstr(char *, int); +PDCEX int getstr(char *); +PDCEX WINDOW *getwin(FILE *); +PDCEX int halfdelay(int); +PDCEX bool has_colors(void); +PDCEX bool has_ic(void); +PDCEX bool has_il(void); +PDCEX int hline(chtype, int); +PDCEX void idcok(WINDOW *, bool); +PDCEX int idlok(WINDOW *, bool); +PDCEX void immedok(WINDOW *, bool); +PDCEX int inchnstr(chtype *, int); +PDCEX int inchstr(chtype *); +PDCEX chtype inch(void); +PDCEX int init_color(short, short, short, short); +PDCEX int init_pair(short, short, short); +PDCEX WINDOW *initscr(void); +PDCEX int innstr(char *, int); +PDCEX int insch(chtype); +PDCEX int insdelln(int); +PDCEX int insertln(void); +PDCEX int insnstr(const char *, int); +PDCEX int insstr(const char *); +PDCEX int instr(char *); +PDCEX int intrflush(WINDOW *, bool); +PDCEX bool isendwin(void); +PDCEX bool is_linetouched(WINDOW *, int); +PDCEX bool is_wintouched(WINDOW *); +PDCEX char *keyname(int); +PDCEX int keypad(WINDOW *, bool); +PDCEX char killchar(void); +PDCEX int leaveok(WINDOW *, bool); +PDCEX char *longname(void); +PDCEX int meta(WINDOW *, bool); +PDCEX int move(int, int); +PDCEX int mvaddch(int, int, const chtype); +PDCEX int mvaddchnstr(int, int, const chtype *, int); +PDCEX int mvaddchstr(int, int, const chtype *); +PDCEX int mvaddnstr(int, int, const char *, int); +PDCEX int mvaddstr(int, int, const char *); +PDCEX int mvchgat(int, int, int, attr_t, short, const void *); +PDCEX int mvcur(int, int, int, int); +PDCEX int mvdelch(int, int); +PDCEX int mvderwin(WINDOW *, int, int); +PDCEX int mvgetch(int, int); +PDCEX int mvgetnstr(int, int, char *, int); +PDCEX int mvgetstr(int, int, char *); +PDCEX int mvhline(int, int, chtype, int); +PDCEX chtype mvinch(int, int); +PDCEX int mvinchnstr(int, int, chtype *, int); +PDCEX int mvinchstr(int, int, chtype *); +PDCEX int mvinnstr(int, int, char *, int); +PDCEX int mvinsch(int, int, chtype); +PDCEX int mvinsnstr(int, int, const char *, int); +PDCEX int mvinsstr(int, int, const char *); +PDCEX int mvinstr(int, int, char *); +PDCEX int mvprintw(int, int, const char *, ...); +PDCEX int mvscanw(int, int, const char *, ...); +PDCEX int mvvline(int, int, chtype, int); +PDCEX int mvwaddchnstr(WINDOW *, int, int, const chtype *, int); +PDCEX int mvwaddchstr(WINDOW *, int, int, const chtype *); +PDCEX int mvwaddch(WINDOW *, int, int, const chtype); +PDCEX int mvwaddnstr(WINDOW *, int, int, const char *, int); +PDCEX int mvwaddstr(WINDOW *, int, int, const char *); +PDCEX int mvwchgat(WINDOW *, int, int, int, attr_t, short, const void *); +PDCEX int mvwdelch(WINDOW *, int, int); +PDCEX int mvwgetch(WINDOW *, int, int); +PDCEX int mvwgetnstr(WINDOW *, int, int, char *, int); +PDCEX int mvwgetstr(WINDOW *, int, int, char *); +PDCEX int mvwhline(WINDOW *, int, int, chtype, int); +PDCEX int mvwinchnstr(WINDOW *, int, int, chtype *, int); +PDCEX int mvwinchstr(WINDOW *, int, int, chtype *); +PDCEX chtype mvwinch(WINDOW *, int, int); +PDCEX int mvwinnstr(WINDOW *, int, int, char *, int); +PDCEX int mvwinsch(WINDOW *, int, int, chtype); +PDCEX int mvwinsnstr(WINDOW *, int, int, const char *, int); +PDCEX int mvwinsstr(WINDOW *, int, int, const char *); +PDCEX int mvwinstr(WINDOW *, int, int, char *); +PDCEX int mvwin(WINDOW *, int, int); +PDCEX int mvwprintw(WINDOW *, int, int, const char *, ...); +PDCEX int mvwscanw(WINDOW *, int, int, const char *, ...); +PDCEX int mvwvline(WINDOW *, int, int, chtype, int); +PDCEX int napms(int); +PDCEX WINDOW *newpad(int, int); +PDCEX SCREEN *newterm(const char *, FILE *, FILE *); +PDCEX WINDOW *newwin(int, int, int, int); +PDCEX int nl(void); +PDCEX int nocbreak(void); +PDCEX int nodelay(WINDOW *, bool); +PDCEX int noecho(void); +PDCEX int nonl(void); +PDCEX void noqiflush(void); +PDCEX int noraw(void); +PDCEX int notimeout(WINDOW *, bool); +PDCEX int overlay(const WINDOW *, WINDOW *); +PDCEX int overwrite(const WINDOW *, WINDOW *); +PDCEX int pair_content(short, short *, short *); +PDCEX int pechochar(WINDOW *, chtype); +PDCEX int pnoutrefresh(WINDOW *, int, int, int, int, int, int); +PDCEX int prefresh(WINDOW *, int, int, int, int, int, int); +PDCEX int printw(const char *, ...); +PDCEX int putwin(WINDOW *, FILE *); +PDCEX void qiflush(void); +PDCEX int raw(void); +PDCEX int redrawwin(WINDOW *); +PDCEX int refresh(void); +PDCEX int reset_prog_mode(void); +PDCEX int reset_shell_mode(void); +PDCEX int resetty(void); +PDCEX int ripoffline(int, int (*)(WINDOW *, int)); +PDCEX int savetty(void); +PDCEX int scanw(const char *, ...); +PDCEX int scr_dump(const char *); +PDCEX int scr_init(const char *); +PDCEX int scr_restore(const char *); +PDCEX int scr_set(const char *); +PDCEX int scrl(int); +PDCEX int scroll(WINDOW *); +PDCEX int scrollok(WINDOW *, bool); +PDCEX SCREEN *set_term(SCREEN *); +PDCEX int setscrreg(int, int); +PDCEX int slk_attroff(const chtype); +PDCEX int slk_attr_off(const attr_t, void *); +PDCEX int slk_attron(const chtype); +PDCEX int slk_attr_on(const attr_t, void *); +PDCEX int slk_attrset(const chtype); +PDCEX int slk_attr_set(const attr_t, short, void *); +PDCEX int slk_clear(void); +PDCEX int slk_color(short); +PDCEX int slk_init(int); +PDCEX char *slk_label(int); +PDCEX int slk_noutrefresh(void); +PDCEX int slk_refresh(void); +PDCEX int slk_restore(void); +PDCEX int slk_set(int, const char *, int); +PDCEX int slk_touch(void); +PDCEX int standend(void); +PDCEX int standout(void); +PDCEX int start_color(void); +PDCEX WINDOW *subpad(WINDOW *, int, int, int, int); +PDCEX WINDOW *subwin(WINDOW *, int, int, int, int); +PDCEX int syncok(WINDOW *, bool); +PDCEX chtype termattrs(void); +PDCEX attr_t term_attrs(void); +PDCEX char *termname(void); +PDCEX void timeout(int); +PDCEX int touchline(WINDOW *, int, int); +PDCEX int touchwin(WINDOW *); +PDCEX int typeahead(int); +PDCEX int untouchwin(WINDOW *); +PDCEX void use_env(bool); +PDCEX int vidattr(chtype); +PDCEX int vid_attr(attr_t, short, void *); +PDCEX int vidputs(chtype, int (*)(int)); +PDCEX int vid_puts(attr_t, short, void *, int (*)(int)); +PDCEX int vline(chtype, int); +PDCEX int vw_printw(WINDOW *, const char *, va_list); +PDCEX int vwprintw(WINDOW *, const char *, va_list); +PDCEX int vw_scanw(WINDOW *, const char *, va_list); +PDCEX int vwscanw(WINDOW *, const char *, va_list); +PDCEX int waddchnstr(WINDOW *, const chtype *, int); +PDCEX int waddchstr(WINDOW *, const chtype *); +PDCEX int waddch(WINDOW *, const chtype); +PDCEX int waddnstr(WINDOW *, const char *, int); +PDCEX int waddstr(WINDOW *, const char *); +PDCEX int wattroff(WINDOW *, chtype); +PDCEX int wattron(WINDOW *, chtype); +PDCEX int wattrset(WINDOW *, chtype); +PDCEX int wattr_get(WINDOW *, attr_t *, short *, void *); +PDCEX int wattr_off(WINDOW *, attr_t, void *); +PDCEX int wattr_on(WINDOW *, attr_t, void *); +PDCEX int wattr_set(WINDOW *, attr_t, short, void *); +PDCEX void wbkgdset(WINDOW *, chtype); +PDCEX int wbkgd(WINDOW *, chtype); +PDCEX int wborder(WINDOW *, chtype, chtype, chtype, chtype, + chtype, chtype, chtype, chtype); +PDCEX int wchgat(WINDOW *, int, attr_t, short, const void *); +PDCEX int wclear(WINDOW *); +PDCEX int wclrtobot(WINDOW *); +PDCEX int wclrtoeol(WINDOW *); +PDCEX int wcolor_set(WINDOW *, short, void *); +PDCEX void wcursyncup(WINDOW *); +PDCEX int wdelch(WINDOW *); +PDCEX int wdeleteln(WINDOW *); +PDCEX int wechochar(WINDOW *, const chtype); +PDCEX int werase(WINDOW *); +PDCEX int wgetch(WINDOW *); +PDCEX int wgetnstr(WINDOW *, char *, int); +PDCEX int wgetstr(WINDOW *, char *); +PDCEX int whline(WINDOW *, chtype, int); +PDCEX int winchnstr(WINDOW *, chtype *, int); +PDCEX int winchstr(WINDOW *, chtype *); +PDCEX chtype winch(WINDOW *); +PDCEX int winnstr(WINDOW *, char *, int); +PDCEX int winsch(WINDOW *, chtype); +PDCEX int winsdelln(WINDOW *, int); +PDCEX int winsertln(WINDOW *); +PDCEX int winsnstr(WINDOW *, const char *, int); +PDCEX int winsstr(WINDOW *, const char *); +PDCEX int winstr(WINDOW *, char *); +PDCEX int wmove(WINDOW *, int, int); +PDCEX int wnoutrefresh(WINDOW *); +PDCEX int wprintw(WINDOW *, const char *, ...); +PDCEX int wredrawln(WINDOW *, int, int); +PDCEX int wrefresh(WINDOW *); +PDCEX int wscanw(WINDOW *, const char *, ...); +PDCEX int wscrl(WINDOW *, int); +PDCEX int wsetscrreg(WINDOW *, int, int); +PDCEX int wstandend(WINDOW *); +PDCEX int wstandout(WINDOW *); +PDCEX void wsyncdown(WINDOW *); +PDCEX void wsyncup(WINDOW *); +PDCEX void wtimeout(WINDOW *, int); +PDCEX int wtouchln(WINDOW *, int, int, int); +PDCEX int wvline(WINDOW *, chtype, int); + +/* Wide-character functions */ + +#ifdef PDC_WIDE +PDCEX int addnwstr(const wchar_t *, int); +PDCEX int addwstr(const wchar_t *); +PDCEX int add_wch(const cchar_t *); +PDCEX int add_wchnstr(const cchar_t *, int); +PDCEX int add_wchstr(const cchar_t *); +PDCEX int border_set(const cchar_t *, const cchar_t *, const cchar_t *, + const cchar_t *, const cchar_t *, const cchar_t *, + const cchar_t *, const cchar_t *); +PDCEX int box_set(WINDOW *, const cchar_t *, const cchar_t *); +PDCEX int echo_wchar(const cchar_t *); +PDCEX int erasewchar(wchar_t *); +PDCEX int getbkgrnd(cchar_t *); +PDCEX int getcchar(const cchar_t *, wchar_t *, attr_t *, short *, void *); +PDCEX int getn_wstr(wint_t *, int); +PDCEX int get_wch(wint_t *); +PDCEX int get_wstr(wint_t *); +PDCEX int hline_set(const cchar_t *, int); +PDCEX int innwstr(wchar_t *, int); +PDCEX int ins_nwstr(const wchar_t *, int); +PDCEX int ins_wch(const cchar_t *); +PDCEX int ins_wstr(const wchar_t *); +PDCEX int inwstr(wchar_t *); +PDCEX int in_wch(cchar_t *); +PDCEX int in_wchnstr(cchar_t *, int); +PDCEX int in_wchstr(cchar_t *); +PDCEX char *key_name(wchar_t); +PDCEX int killwchar(wchar_t *); +PDCEX int mvaddnwstr(int, int, const wchar_t *, int); +PDCEX int mvaddwstr(int, int, const wchar_t *); +PDCEX int mvadd_wch(int, int, const cchar_t *); +PDCEX int mvadd_wchnstr(int, int, const cchar_t *, int); +PDCEX int mvadd_wchstr(int, int, const cchar_t *); +PDCEX int mvgetn_wstr(int, int, wint_t *, int); +PDCEX int mvget_wch(int, int, wint_t *); +PDCEX int mvget_wstr(int, int, wint_t *); +PDCEX int mvhline_set(int, int, const cchar_t *, int); +PDCEX int mvinnwstr(int, int, wchar_t *, int); +PDCEX int mvins_nwstr(int, int, const wchar_t *, int); +PDCEX int mvins_wch(int, int, const cchar_t *); +PDCEX int mvins_wstr(int, int, const wchar_t *); +PDCEX int mvinwstr(int, int, wchar_t *); +PDCEX int mvin_wch(int, int, cchar_t *); +PDCEX int mvin_wchnstr(int, int, cchar_t *, int); +PDCEX int mvin_wchstr(int, int, cchar_t *); +PDCEX int mvvline_set(int, int, const cchar_t *, int); +PDCEX int mvwaddnwstr(WINDOW *, int, int, const wchar_t *, int); +PDCEX int mvwaddwstr(WINDOW *, int, int, const wchar_t *); +PDCEX int mvwadd_wch(WINDOW *, int, int, const cchar_t *); +PDCEX int mvwadd_wchnstr(WINDOW *, int, int, const cchar_t *, int); +PDCEX int mvwadd_wchstr(WINDOW *, int, int, const cchar_t *); +PDCEX int mvwgetn_wstr(WINDOW *, int, int, wint_t *, int); +PDCEX int mvwget_wch(WINDOW *, int, int, wint_t *); +PDCEX int mvwget_wstr(WINDOW *, int, int, wint_t *); +PDCEX int mvwhline_set(WINDOW *, int, int, const cchar_t *, int); +PDCEX int mvwinnwstr(WINDOW *, int, int, wchar_t *, int); +PDCEX int mvwins_nwstr(WINDOW *, int, int, const wchar_t *, int); +PDCEX int mvwins_wch(WINDOW *, int, int, const cchar_t *); +PDCEX int mvwins_wstr(WINDOW *, int, int, const wchar_t *); +PDCEX int mvwin_wch(WINDOW *, int, int, cchar_t *); +PDCEX int mvwin_wchnstr(WINDOW *, int, int, cchar_t *, int); +PDCEX int mvwin_wchstr(WINDOW *, int, int, cchar_t *); +PDCEX int mvwinwstr(WINDOW *, int, int, wchar_t *); +PDCEX int mvwvline_set(WINDOW *, int, int, const cchar_t *, int); +PDCEX int pecho_wchar(WINDOW *, const cchar_t*); +PDCEX int setcchar(cchar_t*, const wchar_t*, const attr_t, + short, const void*); +PDCEX int slk_wset(int, const wchar_t *, int); +PDCEX int unget_wch(const wchar_t); +PDCEX int vline_set(const cchar_t *, int); +PDCEX int waddnwstr(WINDOW *, const wchar_t *, int); +PDCEX int waddwstr(WINDOW *, const wchar_t *); +PDCEX int wadd_wch(WINDOW *, const cchar_t *); +PDCEX int wadd_wchnstr(WINDOW *, const cchar_t *, int); +PDCEX int wadd_wchstr(WINDOW *, const cchar_t *); +PDCEX int wbkgrnd(WINDOW *, const cchar_t *); +PDCEX void wbkgrndset(WINDOW *, const cchar_t *); +PDCEX int wborder_set(WINDOW *, const cchar_t *, const cchar_t *, + const cchar_t *, const cchar_t *, const cchar_t *, + const cchar_t *, const cchar_t *, const cchar_t *); +PDCEX int wecho_wchar(WINDOW *, const cchar_t *); +PDCEX int wgetbkgrnd(WINDOW *, cchar_t *); +PDCEX int wgetn_wstr(WINDOW *, wint_t *, int); +PDCEX int wget_wch(WINDOW *, wint_t *); +PDCEX int wget_wstr(WINDOW *, wint_t *); +PDCEX int whline_set(WINDOW *, const cchar_t *, int); +PDCEX int winnwstr(WINDOW *, wchar_t *, int); +PDCEX int wins_nwstr(WINDOW *, const wchar_t *, int); +PDCEX int wins_wch(WINDOW *, const cchar_t *); +PDCEX int wins_wstr(WINDOW *, const wchar_t *); +PDCEX int winwstr(WINDOW *, wchar_t *); +PDCEX int win_wch(WINDOW *, cchar_t *); +PDCEX int win_wchnstr(WINDOW *, cchar_t *, int); +PDCEX int win_wchstr(WINDOW *, cchar_t *); +PDCEX wchar_t *wunctrl(cchar_t *); +PDCEX int wvline_set(WINDOW *, const cchar_t *, int); +#endif + +/* Quasi-standard */ + +PDCEX chtype getattrs(WINDOW *); +PDCEX int getbegx(WINDOW *); +PDCEX int getbegy(WINDOW *); +PDCEX int getmaxx(WINDOW *); +PDCEX int getmaxy(WINDOW *); +PDCEX int getparx(WINDOW *); +PDCEX int getpary(WINDOW *); +PDCEX int getcurx(WINDOW *); +PDCEX int getcury(WINDOW *); +PDCEX void traceoff(void); +PDCEX void traceon(void); +PDCEX char *unctrl(chtype); + +PDCEX int crmode(void); +PDCEX int nocrmode(void); +PDCEX int draino(int); +PDCEX int resetterm(void); +PDCEX int fixterm(void); +PDCEX int saveterm(void); +PDCEX void setsyx(int, int); + +PDCEX int mouse_set(unsigned long); +PDCEX int mouse_on(unsigned long); +PDCEX int mouse_off(unsigned long); +PDCEX int request_mouse_pos(void); +PDCEX int map_button(unsigned long); +PDCEX void wmouse_position(WINDOW *, int *, int *); +PDCEX unsigned long getmouse(void); +PDCEX unsigned long getbmap(void); + +/* ncurses */ + +PDCEX int assume_default_colors(int, int); +PDCEX const char *curses_version(void); +PDCEX bool has_key(int); +PDCEX int use_default_colors(void); +PDCEX int wresize(WINDOW *, int, int); + +PDCEX int mouseinterval(int); +PDCEX mmask_t mousemask(mmask_t, mmask_t *); +PDCEX bool mouse_trafo(int *, int *, bool); +PDCEX int nc_getmouse(MEVENT *); +PDCEX int ungetmouse(MEVENT *); +PDCEX bool wenclose(const WINDOW *, int, int); +PDCEX bool wmouse_trafo(const WINDOW *, int *, int *, bool); + +/* PDCurses */ + +PDCEX int addrawch(chtype); +PDCEX int insrawch(chtype); +PDCEX bool is_termresized(void); +PDCEX int mvaddrawch(int, int, chtype); +PDCEX int mvdeleteln(int, int); +PDCEX int mvinsertln(int, int); +PDCEX int mvinsrawch(int, int, chtype); +PDCEX int mvwaddrawch(WINDOW *, int, int, chtype); +PDCEX int mvwdeleteln(WINDOW *, int, int); +PDCEX int mvwinsertln(WINDOW *, int, int); +PDCEX int mvwinsrawch(WINDOW *, int, int, chtype); +PDCEX int raw_output(bool); +PDCEX int resize_term(int, int); +PDCEX WINDOW *resize_window(WINDOW *, int, int); +PDCEX int waddrawch(WINDOW *, chtype); +PDCEX int winsrawch(WINDOW *, chtype); +PDCEX char wordchar(void); + +#ifdef PDC_WIDE +PDCEX wchar_t *slk_wlabel(int); +#endif + +PDCEX void PDC_debug(const char *, ...); +PDCEX int PDC_ungetch(int); +PDCEX int PDC_set_blink(bool); +PDCEX int PDC_set_line_color(short); +PDCEX void PDC_set_title(const char *); + +PDCEX int PDC_clearclipboard(void); +PDCEX int PDC_freeclipboard(char *); +PDCEX int PDC_getclipboard(char **, long *); +PDCEX int PDC_setclipboard(const char *, long); + +PDCEX unsigned long PDC_get_input_fd(void); +PDCEX unsigned long PDC_get_key_modifiers(void); +PDCEX int PDC_return_key_modifiers(bool); +PDCEX int PDC_save_key_modifiers(bool); +PDCEX void PDC_set_resize_limits( const int new_min_lines, + const int new_max_lines, + const int new_min_cols, + const int new_max_cols); + +#define FUNCTION_KEY_SHUT_DOWN 0 +#define FUNCTION_KEY_PASTE 1 +#define FUNCTION_KEY_ENLARGE_FONT 2 +#define FUNCTION_KEY_SHRINK_FONT 3 +#define FUNCTION_KEY_CHOOSE_FONT 4 +#define FUNCTION_KEY_ABORT 5 +#define PDC_MAX_FUNCTION_KEYS 6 + +PDCEX int PDC_set_function_key( const unsigned function, + const int new_key); + +PDCEX WINDOW *Xinitscr(int, char **); +#ifdef XCURSES +PDCEX void XCursesExit(void); +PDCEX int sb_init(void); +PDCEX int sb_set_horz(int, int, int); +PDCEX int sb_set_vert(int, int, int); +PDCEX int sb_get_horz(int *, int *, int *); +PDCEX int sb_get_vert(int *, int *, int *); +PDCEX int sb_refresh(void); + #endif + +/*** Functions defined as macros ***/ + +/* getch() and ungetch() conflict with some DOS libraries */ + +#define getch() wgetch(stdscr) +#define ungetch(ch) PDC_ungetch(ch) + +#define COLOR_PAIR(n) (((chtype)(n) << PDC_COLOR_SHIFT) & A_COLOR) +#define PAIR_NUMBER(n) ((((n) & A_COLOR) >> PDC_COLOR_SHIFT) & 0xff) + +/* These will _only_ work as macros */ + +#define getbegyx(w, y, x) (y = getbegy(w), x = getbegx(w)) +#define getmaxyx(w, y, x) (y = getmaxy(w), x = getmaxx(w)) +#define getparyx(w, y, x) (y = getpary(w), x = getparx(w)) +#define getyx(w, y, x) (y = getcury(w), x = getcurx(w)) + +#define getsyx(y, x) { if (curscr->_leaveit) (y)=(x)=-1; \ + else getyx(curscr,(y),(x)); } + +#ifdef NCURSES_MOUSE_VERSION +# define getmouse(x) nc_getmouse(x) +#endif + +/* return codes from PDC_getclipboard() and PDC_setclipboard() calls */ + +#define PDC_CLIP_SUCCESS 0 +#define PDC_CLIP_ACCESS_ERROR 1 +#define PDC_CLIP_EMPTY 2 +#define PDC_CLIP_MEMORY_ERROR 3 + +/* PDCurses key modifier masks */ + +#define PDC_KEY_MODIFIER_SHIFT 1 +#define PDC_KEY_MODIFIER_CONTROL 2 +#define PDC_KEY_MODIFIER_ALT 4 +#define PDC_KEY_MODIFIER_NUMLOCK 8 +#define PDC_KEY_MODIFIER_REPEAT 16 + +#ifdef __cplusplus +# undef bool +} +#endif + +#endif /* __PDCURSES__ */ diff --git a/src/cc/rogue/x86_64-w64-msvc/deps/install/include/curspriv.h b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/curspriv.h new file mode 100644 index 000000000..b5edcc173 --- /dev/null +++ b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/curspriv.h @@ -0,0 +1,134 @@ +/* Public Domain Curses */ + +/* Private definitions and declarations for use within PDCurses. + These should generally not be referenced by applications. */ + +#ifndef __CURSES_INTERNALS__ +#define __CURSES_INTERNALS__ 1 + +#define CURSES_LIBRARY +#include + +#if defined(__TURBOC__) || defined(__EMX__) || defined(__DJGPP__) || \ + defined(__CYGWIN__) || defined(__MINGW32__) || \ + defined(__WATCOMC__) || defined(__PACIFIC__) +# ifndef HAVE_VSSCANF +# define HAVE_VSSCANF /* have vsscanf() */ +# endif +#endif + +#if defined(__CYGWIN__) || defined(__MINGW32__) || \ + defined(__LCC__) || defined(__WATCOMC__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF /* have vsnprintf() */ +# endif +#endif + +#if defined(_MSC_VER) && defined(_WIN32) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE 1 /* kill nonsense warnings */ +#endif + +/*----------------------------------------------------------------------*/ + +typedef struct /* structure for ripped off lines */ +{ + int line; + int (*init)(WINDOW *, int); +} RIPPEDOFFLINE; + +/* Window properties */ + +#define _SUBWIN 0x01 /* window is a subwindow */ +#define _PAD 0x10 /* X/Open Pad. */ +#define _SUBPAD 0x20 /* X/Open subpad. */ + +/* Miscellaneous */ + +#define _NO_CHANGE -1 /* flags line edge unchanged */ + +#define _ECHAR 0x08 /* Erase char (^H) */ +#define _DWCHAR 0x17 /* Delete Word char (^W) */ +#define _DLCHAR 0x15 /* Delete Line char (^U) */ + +extern WINDOW *pdc_lastscr; +extern FILE *pdc_dbfp; /* tracing file pointer (NULL = off) */ +extern bool pdc_color_started; +extern unsigned long pdc_key_modifiers; +extern MOUSE_STATUS pdc_mouse_status; + +/*----------------------------------------------------------------------*/ + +/* Platform implementation functions */ + +void PDC_beep(void); +bool PDC_can_change_color(void); +int PDC_color_content(short, short *, short *, short *); +bool PDC_check_key(void); +int PDC_curs_set(int); +void PDC_flushinp(void); +int PDC_get_columns(void); +int PDC_get_cursor_mode(void); +int PDC_get_key(void); +int PDC_get_rows(void); +void PDC_gotoyx(int, int); +int PDC_init_color(short, short, short, short); +void PDC_init_pair(short, short, short); +int PDC_modifiers_set(void); +int PDC_mouse_set(void); +void PDC_napms(int); +int PDC_pair_content(short, short *, short *); +void PDC_reset_prog_mode(void); +void PDC_reset_shell_mode(void); +int PDC_resize_screen(int, int); +void PDC_restore_screen_mode(int); +void PDC_save_screen_mode(int); +void PDC_scr_close(void); +void PDC_scr_free(void); +int PDC_scr_open(int, char **); +void PDC_set_keyboard_binary(bool); +void PDC_transform_line(int, int, int, const chtype *); +const char *PDC_sysname(void); + +/* Internal cross-module functions */ + +void PDC_init_atrtab(void); +WINDOW *PDC_makelines(WINDOW *); +WINDOW *PDC_makenew(int, int, int, int); +int PDC_mouse_in_slk(int, int); +void PDC_slk_free(void); +void PDC_slk_initialize(void); +void PDC_sync(WINDOW *); + +#ifdef PDC_WIDE +int PDC_mbtowc(wchar_t *, const char *, size_t); +size_t PDC_mbstowcs(wchar_t *, const char *, size_t); +size_t PDC_wcstombs(char *, const wchar_t *, size_t); +#endif + +#ifdef PDCDEBUG +# define PDC_LOG(x) if (pdc_dbfp) PDC_debug x +#else +# define PDC_LOG(x) +#endif + +/* Internal macros for attributes */ + +#ifdef CHTYPE_LONG +# define PDC_COLOR_PAIRS 256 +#else +# define PDC_COLOR_PAIRS 32 +#endif + +#ifndef max +# define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +# define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define DIVROUND(num, divisor) (((num) + ((divisor) >> 1)) / (divisor)) + +#define PDC_CLICK_PERIOD 150 /* time to wait for a click, if + not set by mouseinterval() */ + +#endif /* __CURSES_INTERNALS__*/ diff --git a/src/cc/rogue/x86_64-w64-msvc/deps/install/include/getopt.h b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/getopt.h new file mode 100644 index 000000000..4de6e853e --- /dev/null +++ b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/getopt.h @@ -0,0 +1,93 @@ +/* $Id: getopt.h,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */ +/* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */ +/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#if 0 +#include +#endif + +/* + * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions + */ +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +struct option { + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int getopt_long(int, char * const *, const char *, + const struct option *, int *); +int getopt_long_only(int, char * const *, const char *, + const struct option *, int *); +#ifndef _GETOPT_DEFINED +#define _GETOPT_DEFINED +int getopt(int, char * const *, const char *); +int getsubopt(char **, char * const *, char **); + +extern char *optarg; /* getopt(3) external variables */ +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; +extern char *suboptarg; /* getsubopt(3) external variable */ +#endif /* _GETOPT_DEFINED */ + +#ifdef __cplusplus +} +#endif +#endif /* !_GETOPT_H_ */ diff --git a/src/cc/rogue/x86_64-w64-msvc/deps/install/include/panel.h b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/panel.h new file mode 100644 index 000000000..7f1fb1f17 --- /dev/null +++ b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/panel.h @@ -0,0 +1,56 @@ +/* Public Domain Curses */ + +/*----------------------------------------------------------------------* + * Panels for PDCurses * + *----------------------------------------------------------------------*/ + +#ifndef __PDCURSES_PANEL_H__ +#define __PDCURSES_PANEL_H__ 1 + +#include + +#if defined(__cplusplus) || defined(__cplusplus__) || defined(__CPLUSPLUS) +extern "C" +{ +#endif + +typedef struct panelobs +{ + struct panelobs *above; + struct panel *pan; +} PANELOBS; + +typedef struct panel +{ + WINDOW *win; + int wstarty; + int wendy; + int wstartx; + int wendx; + struct panel *below; + struct panel *above; + const void *user; + struct panelobs *obscure; +} PANEL; + +PDCEX int bottom_panel(PANEL *pan); +PDCEX int del_panel(PANEL *pan); +PDCEX int hide_panel(PANEL *pan); +PDCEX int move_panel(PANEL *pan, int starty, int startx); +PDCEX PANEL *new_panel(WINDOW *win); +PDCEX PANEL *panel_above(const PANEL *pan); +PDCEX PANEL *panel_below(const PANEL *pan); +PDCEX int panel_hidden(const PANEL *pan); +PDCEX const void *panel_userptr(const PANEL *pan); +PDCEX WINDOW *panel_window(const PANEL *pan); +PDCEX int replace_panel(PANEL *pan, WINDOW *win); +PDCEX int set_panel_userptr(PANEL *pan, const void *uptr); +PDCEX int show_panel(PANEL *pan); +PDCEX int top_panel(PANEL *pan); +PDCEX void update_panels(void); + +#if defined(__cplusplus) || defined(__cplusplus__) || defined(__CPLUSPLUS) +} +#endif + +#endif /* __PDCURSES_PANEL_H__ */ diff --git a/src/cc/rogue/x86_64-w64-msvc/deps/install/include/term.h b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/term.h new file mode 100644 index 000000000..0ba0b7a7f --- /dev/null +++ b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/term.h @@ -0,0 +1,48 @@ +/* Public Domain Curses */ + +/* PDCurses doesn't operate with terminfo, but we need these functions for + compatibility, to allow some things (notably, interface libraries for + other languages) to be compiled. Anyone who tries to actually _use_ + them will be disappointed, since they only return ERR. */ + +#ifndef __PDCURSES_TERM_H__ +#define __PDCURSES_TERM_H__ 1 + +#include + +#if defined(__cplusplus) || defined(__cplusplus__) || defined(__CPLUSPLUS) +extern "C" +{ +#endif + +typedef struct +{ + const char *_termname; +} TERMINAL; + +/* PDCEX is defined in curses.h */ +PDCEX TERMINAL *cur_term; + +int del_curterm(TERMINAL *); +int putp(const char *); +int restartterm(const char *, int, int *); +TERMINAL *set_curterm(TERMINAL *); +int setterm(const char *); +int setupterm(const char *, int, int *); +int tgetent(char *, const char *); +int tgetflag(const char *); +int tgetnum(const char *); +char *tgetstr(const char *, char **); +char *tgoto(const char *, int, int); +int tigetflag(const char *); +int tigetnum(const char *); +char *tigetstr(const char *); +char *tparm(const char *, long, long, long, long, long, + long, long, long, long); +int tputs(const char *, int, int (*)(int)); + +#if defined(__cplusplus) || defined(__cplusplus__) || defined(__CPLUSPLUS) +} +#endif + +#endif /* __PDCURSES_TERM_H__ */ diff --git a/src/cc/rogue/x86_64-w64-msvc/deps/install/include/unistd.h b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/unistd.h new file mode 100644 index 000000000..5d2440309 --- /dev/null +++ b/src/cc/rogue/x86_64-w64-msvc/deps/install/include/unistd.h @@ -0,0 +1,56 @@ +#ifndef _UNISTD_H +#define _UNISTD_H 1 + +/* This is intended as a drop-in replacement for unistd.h on Windows. + * Please add functionality as neeeded. + * https://stackoverflow.com/a/826027/1202830 + */ + +#include +#include +#include /* getopt at: https://gist.github.com/ashelly/7776712 */ +#include /* for getpid() and the exec..() family */ +#include /* for _getcwd() and _chdir() */ + +#define srandom srand +#define random rand + +/* Values for the second argument to access. + These may be OR'd together. */ +#define R_OK 4 /* Test for read permission. */ +#define W_OK 2 /* Test for write permission. */ +//#define X_OK 1 /* execute permission - unsupported in windows*/ +#define F_OK 0 /* Test for existence. */ + +#define access _access +#define dup2 _dup2 +#define execve _execve +#define ftruncate _chsize +#define unlink _unlink +#define fileno _fileno +#define getcwd _getcwd +#define chdir _chdir +#define isatty _isatty +#define lseek _lseek +/* read, write, and close are NOT being #defined here, because while there are file handle specific versions for Windows, they probably don't work for sockets. You need to look at your app and consider whether to call e.g. closesocket(). */ + +#ifdef _WIN64 +#define ssize_t __int64 +#else +#define ssize_t long +#endif + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +/* should be in some equivalent to */ +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#endif /* unistd.h */ \ No newline at end of file diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index 1a4f7c1cd..495fa8774 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -169,16 +169,18 @@ CScript rogue_highlanderopret(uint8_t funcid,uint256 gametxid,int32_t regslot,CP uint8_t rogue_highlanderopretdecode(uint256 &gametxid, uint256 &tokenid, int32_t ®slot, CPubKey &pk, std::vector &playerdata, std::string &symbol, std::string &pname,CScript scriptPubKey) { std::string name, description; std::vector vorigPubkey; + std::vector> oprets, opretsDummy; std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; uint8_t e, f,*script; std::vector voutPubkeys; tokenid = zeroid; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description,vopretNonfungible)) == 'c' ) + if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description, oprets)) == 'c' ) { + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); vopret = vopretNonfungible; } - else if ( script[1] != 'H' && script[1] != 'Q' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, vopretDummy)) != 0 ) + else if ( script[1] != 'H' && script[1] != 'Q' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, opretsDummy)) != 0 ) { //fprintf(stderr,"decode opret %c tokenid.%s\n",script[1],tokenid.GetHex().c_str()); GetNonfungibleData(tokenid, vopretNonfungible); //load nonfungible data from the 'tokenbase' tx @@ -206,17 +208,20 @@ uint8_t rogue_keystrokesopretdecode(uint256 &gametxid,uint256 &batontxid,CPubKey uint8_t rogue_registeropretdecode(uint256 &gametxid,uint256 &tokenid,uint256 &playertxid,CScript scriptPubKey) { std::string name, description; std::vector vorigPubkey; + std::vector> oprets; std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; uint8_t e, f,*script; std::vector voutPubkeys; tokenid = zeroid; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description,vopretNonfungible)) == 'c' ) + if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description,oprets)) == 'c' ) { + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); vopret = vopretNonfungible; } - else if ( script[1] != 'R' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, vopretDummy)) != 0 ) + else if ( script[1] != 'R' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, oprets)) != 0 ) { + GetOpretBlob(oprets, OPRETID_ROGUEGAMEDATA, vopretDummy); // blob from non-creation tx opret vopret = vopretDummy; } if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> gametxid; ss >> playertxid) != 0 && e == EVAL_ROGUE && f == 'R' ) @@ -277,54 +282,6 @@ int32_t rogue_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx, return(0); } -int32_t rogue_playersalive(int32_t &numplayers,uint256 gametxid,int32_t maxplayers) -{ - int32_t i,alive = 0; uint64_t txfee = 10000; - numplayers = 0; - for (i=0; iGetHeight(); - delay = ROGUE_REGISTRATION * (maxplayers > 1); - obj.push_back(Pair("height",ht)); - obj.push_back(Pair("start",ht+delay)); - if ( komodo_nextheight() > ht+delay ) - { - if ( (pindex= komodo_chainactive(ht+delay)) != 0 ) - { - hashBlock = pindex->GetBlockHash(); - obj.push_back(Pair("starthash",hashBlock.ToString())); - memcpy(&seed,&hashBlock,sizeof(seed)); - seed &= (1LL << 62) - 1; - obj.push_back(Pair("seed",(int64_t)seed)); - if ( rogue_iamregistered(maxplayers,gametxid,tx,myrogueaddr) > 0 ) - sprintf(cmd,"cc/rogue/rogue %llu %s",(long long)seed,gametxid.ToString().c_str()); - else sprintf(cmd,"./komodo-cli -ac_name=%s cclib register %d \"[%%22%s%%22]\"",ASSETCHAINS_SYMBOL,EVAL_ROGUE,gametxid.ToString().c_str()); - obj.push_back(Pair("run",cmd)); - } - } - } - obj.push_back(Pair("alive",rogue_playersalive(numplayers,gametxid,maxplayers))); - obj.push_back(Pair("numplayers",numplayers)); - obj.push_back(Pair("maxplayers",maxplayers)); - obj.push_back(Pair("buyin",ValueFromAmount(buyin))); - return(seed); -} - int32_t rogue_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0) { uint256 hashBlock; int32_t i,numvouts; char coinaddr[64]; CPubKey roguepk; uint64_t txfee = 10000; @@ -338,7 +295,7 @@ int32_t rogue_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransa txid = tx.GetHash(); //fprintf(stderr,"set txid %s %llu\n",txid.GetHex().c_str(),(long long)CCgettxout(txid,0,1)); } - if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) == txfee && (unspentv0 == 0 || CCgettxout(txid,0,1) == txfee) ) + if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) == txfee && (unspentv0 == 0 || CCgettxout(txid,0,1,0) == txfee) ) { if ( rogue_newgameopreturndecode(buyin,maxplayers,tx.vout[numvouts-1].scriptPubKey) == 'G' ) { @@ -364,9 +321,29 @@ int32_t rogue_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransa } else return(-1); } -UniValue rogue_playerobj(std::vector playerdata,uint256 playertxid,uint256 tokenid,std::string symbol,std::string pname) +void disp_playerdata(std::vector playerdata) { - int32_t i; struct rogue_player P; char packitemstr[512],*datastr=0; UniValue obj(UniValue::VOBJ),a(UniValue::VARR); + struct rogue_player P; int32_t i; char packitemstr[512]; + if ( playerdata.size() > 0 ) + { + for (i=0; i>16,P.level,P.experience,P.dungeonlevel); + for (i=0; i playerdata,uint256 playertxid,uint256 tokenid,std::string symbol,std::string pname,uint256 gametxid) +{ + int32_t i,vout,spentvini,numvouts,n=0; uint256 txid,spenttxid,hashBlock; struct rogue_player P; char packitemstr[512],*datastr=0; UniValue obj(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx; memset(&P,0,sizeof(P)); if ( playerdata.size() > 0 ) { @@ -384,6 +361,37 @@ UniValue rogue_playerobj(std::vector playerdata,uint256 playertxid,uint rogue_packitemstr(packitemstr,&P.roguepack[i]); a.push_back(packitemstr); } + txid = playertxid; + vout = 1; + while ( CCgettxout(txid,vout,1,0) < 0 ) + { + spenttxid = zeroid; + spentvini = -1; + if ( (spentvini= myIsutxo_spent(spenttxid,txid,vout)) >= 0 ) + txid = spenttxid; + else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) + { + fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); + break; + } + txid = spenttxid; + vout = 0; + if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) + { + for (i=0; i ROGUE_MAXITERATIONS ) + break; + } + obj.push_back(Pair("gametxid",gametxid.GetHex())); + if ( txid != playertxid ) + obj.push_back(Pair("batontxid",txid.GetHex())); obj.push_back(Pair("playertxid",playertxid.GetHex())); if ( tokenid != zeroid ) obj.push_back(Pair("tokenid",tokenid.GetHex())); @@ -447,6 +455,7 @@ int32_t rogue_playerdata(struct CCcontract_info *cp,uint256 &origplayergame,uint { if ( (f= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,playertx.vout[numvouts-1].scriptPubKey)) == 'H' || f == 'Q' ) { + origplayergame = gametxid; if ( tokenid != zeroid ) { playertxid = tokenid; @@ -472,19 +481,34 @@ int32_t rogue_playerdata(struct CCcontract_info *cp,uint256 &origplayergame,uint int32_t rogue_playerdataspend(CMutableTransaction &mtx,uint256 playertxid,int32_t vout,uint256 origplayergame) { - int64_t txfee = 10000; - if ( CCgettxout(playertxid,vout,1) == 1 ) // not sure if this is enough validation + int64_t txfee = 10000; CTransaction tx; uint256 hashBlock; + if ( CCgettxout(playertxid,vout,1,0) == 1 ) // not sure if this is enough validation { mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); return(0); - } else return(-1); + } + else + { + vout = 0; + if ( myGetTransaction(playertxid,tx,hashBlock) != 0 && tx.vout[vout].nValue == 1 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) + { + if ( CCgettxout(playertxid,vout,1,0) == 1 ) // not sure if this is enough validation + { + mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); + return(0); + } + } + return(-1); + } } int32_t rogue_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) { int32_t i,numvouts,spentvini,n,matches = 0; CPubKey pk; uint256 tid,active,spenttxid,tokenid,hashBlock,txid,origplayergame; CTransaction spenttx,matchtx,batontx; std::vector checkdata; CBlockIndex *pindex; char ccaddr[64],*keystrokes=0; - numkeys = numplayers = 0; - playertxid = zeroid; + batonvalue = numkeys = numplayers = batonht = 0; + playertxid = batontxid = zeroid; + if ( keystrokesp != 0 ) + *keystrokesp = 0; for (i=0; i= 0 ) + txid = spenttxid; + else { - spenttxid = zeroid; - spentvini = -1; - if ( (spentvini= myIsutxo_spent(spenttxid,txid,0)) >= 0 ) - txid = spenttxid; - else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,0) == 0 || spenttxid == zeroid ) + if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,0) == 0 || spenttxid == zeroid ) { fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); return(-2); } - txid = spenttxid; - if ( spentvini != 0 ) - return(-3); - if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) - { - uint256 g,b; CPubKey p; std::vector k; - if ( rogue_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) - { - keystrokes = (char *)realloc(keystrokes,numkeys + (int32_t)k.size()); - for (i=0; i= ROGUE_MAXITERATIONS ) - { - fprintf(stderr,"rogue_findbaton n.%d, seems something is wrong\n",n); - return(-5); - } - //fprintf(stderr,"n.%d txid.%s\n",n,txid.GetHex().c_str()); } - //fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); - batontxid = txid; - batonvout = 0; // not vini - // how to detect timeout, bailedout, highlander - hashBlock = zeroid; - if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 0 ) + txid = spenttxid; + //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); + if ( spentvini != 0 ) // game is over? { - if ( hashBlock == zeroid ) - batonht = komodo_nextheight(); - else if ( (pindex= komodo_blockindex(hashBlock)) == 0 ) - return(-4); - else batonht = pindex->GetHeight(); - batonvalue = batontx.vout[0].nValue; - //printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); return(0); - } else fprintf(stderr,"couldnt find baton\n"); - } else fprintf(stderr,"error with playerdata\n"); - } else fprintf(stderr,"findbaton opret error\n"); - } - else - { - fprintf(stderr,"already played\n"); - return(-5); - } + } + if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) + { + uint256 g,b; CPubKey p; std::vector k; + if ( rogue_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) + { + keystrokes = (char *)realloc(keystrokes,numkeys + (int32_t)k.size()); + for (i=0; i= ROGUE_MAXITERATIONS ) + { + fprintf(stderr,"rogue_findbaton n.%d, seems something is wrong\n",n); + return(-5); + } + } + //fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); + batontxid = txid; + batonvout = 0; // not vini + // how to detect timeout, bailedout, highlander + hashBlock = zeroid; + if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 0 ) + { + if ( hashBlock == zeroid ) + batonht = komodo_nextheight(); + else if ( (pindex= komodo_blockindex(hashBlock)) == 0 ) + return(-4); + else batonht = pindex->GetHeight(); + batonvalue = batontx.vout[0].nValue; + //printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); + return(0); + } else fprintf(stderr,"couldnt find baton\n"); + } else fprintf(stderr,"error with playerdata\n"); + } else fprintf(stderr,"findbaton opret error\n"); } return(-1); } +int32_t rogue_playersalive(int32_t &openslots,int32_t &numplayers,uint256 gametxid,int32_t maxplayers,int32_t gameht,CTransaction gametx) +{ + int32_t i,n,vout,spentvini,registration_open = 0,alive = 0; CTransaction tx; uint256 txid,spenttxid,hashBlock; CBlockIndex *pindex; uint64_t txfee = 10000; + numplayers = openslots = 0; + if ( komodo_nextheight() <= gameht+ROGUE_MAXKEYSTROKESGAP ) + registration_open = 1; + for (i=0; i= 0 ) + txid = spenttxid; + else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) + { + fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); + break; + } + txid = spenttxid; + vout = 0; + //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); + if ( spentvini != 0 ) + break; + if ( n++ > ROGUE_MAXITERATIONS ) + break; + } + if ( txid != zeroid ) + { + if ( myGetTransaction(txid,tx,hashBlock) != 0 ) + { + if ( (pindex= komodo_blockindex(hashBlock)) != 0 ) + { + if ( pindex->GetHeight() <= gameht+ROGUE_MAXKEYSTROKESGAP ) + alive++; + } + } + } + } + } + else if ( registration_open != 0 ) + openslots++; + } + //fprintf(stderr,"numalive.%d openslots.%d\n",alive,openslots); + return(alive); +} + +uint64_t rogue_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *myrogueaddr) +{ + CBlockIndex *pindex; int32_t ht,openslots,delay,numplayers; uint256 hashBlock; uint64_t seed=0; char cmd[512]; CTransaction tx; + if ( myGetTransaction(gametxid,tx,hashBlock) != 0 && (pindex= komodo_blockindex(hashBlock)) != 0 ) + { + ht = pindex->GetHeight(); + delay = ROGUE_REGISTRATION * (maxplayers > 1); + obj.push_back(Pair("height",ht)); + obj.push_back(Pair("start",ht+delay)); + if ( komodo_nextheight() > ht+delay ) + { + if ( (pindex= komodo_chainactive(ht+delay)) != 0 ) + { + hashBlock = pindex->GetBlockHash(); + obj.push_back(Pair("starthash",hashBlock.ToString())); + memcpy(&seed,&hashBlock,sizeof(seed)); + seed &= (1LL << 62) - 1; + obj.push_back(Pair("seed",(int64_t)seed)); + if ( rogue_iamregistered(maxplayers,gametxid,tx,myrogueaddr) > 0 ) + sprintf(cmd,"cc/rogue/rogue %llu %s",(long long)seed,gametxid.ToString().c_str()); + else sprintf(cmd,"./komodo-cli -ac_name=%s cclib register %d \"[%%22%s%%22]\"",ASSETCHAINS_SYMBOL,EVAL_ROGUE,gametxid.ToString().c_str()); + obj.push_back(Pair("run",cmd)); + } + } + obj.push_back(Pair("alive",rogue_playersalive(openslots,numplayers,gametxid,maxplayers,ht,tx))); + obj.push_back(Pair("openslots",openslots)); + obj.push_back(Pair("numplayers",numplayers)); + } + obj.push_back(Pair("maxplayers",maxplayers)); + obj.push_back(Pair("buyin",ValueFromAmount(buyin))); + return(seed); +} + void rogue_gameplayerinfo(struct CCcontract_info *cp,UniValue &obj,uint256 gametxid,CTransaction gametx,int32_t vout,int32_t maxplayers,char *myrogueaddr) { // identify if bailout or quit or timed out @@ -594,7 +708,7 @@ void rogue_gameplayerinfo(struct CCcontract_info *cp,UniValue &obj,uint256 gamet obj.push_back(Pair("slot",(int64_t)vout-1)); if ( (retval= rogue_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,destaddr,numplayers,symbol,pname)) == 0 ) { - if ( CCgettxout(gametxid,maxplayers+vout,1) == 10000 ) + if ( CCgettxout(gametxid,maxplayers+vout,1,0) == 10000 ) { if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 1 ) { @@ -611,7 +725,7 @@ void rogue_gameplayerinfo(struct CCcontract_info *cp,UniValue &obj,uint256 gamet obj.push_back(Pair("batonvalue",ValueFromAmount(batonvalue))); obj.push_back(Pair("batonht",(int64_t)batonht)); if ( playerdata.size() > 0 ) - obj.push_back(Pair("player",rogue_playerobj(playerdata,playertxid,tokenid,symbol,pname))); + obj.push_back(Pair("player",rogue_playerobj(playerdata,playertxid,tokenid,symbol,pname,gametxid))); } else fprintf(stderr,"findbaton err.%d\n",retval); } @@ -624,7 +738,7 @@ int64_t rogue_registrationbaton(CMutableTransaction &mtx,uint256 gametxid,CTrans for (j=0; jCCpriv,destaddr); mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode, 1, burnpk)); - std::vector vopretExtra; uint8_t e, funcid; uint256 tid; std::vector voutPubkeys, voutPubkeysEmpty; int32_t didtx = 0; + uint8_t e, funcid; uint256 tid; std::vector voutPubkeys, voutPubkeysEmpty; int32_t didtx = 0; CScript opretRegister = rogue_registeropret(gametxid, playertxid); if ( playertxid != zeroid ) { voutPubkeysEmpty.push_back(burnpk); if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 ) { - if ( (funcid= DecodeTokenOpRet(playertx.vout.back().scriptPubKey, e, tid, voutPubkeys, vopretExtra)) != 0) + std::vector> oprets; + if ( (funcid= DecodeTokenOpRet(playertx.vout.back().scriptPubKey, e, tid, voutPubkeys, oprets)) != 0) { // if token in the opret didtx = 1; if ( funcid == 'c' ) tid = tokenid == zeroid ? playertxid : tokenid; + vscript_t vopretRegister; + GetOpReturnData(opretRegister, vopretRegister); rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, - EncodeTokenOpRet(tid, voutPubkeysEmpty /*=never spent*/, opretRegister)); + EncodeTokenOpRet(tid, voutPubkeysEmpty /*=never spent*/, std::make_pair(OPRETID_ROGUEGAMEDATA, vopretRegister))); } } } @@ -835,19 +952,20 @@ UniValue rogue_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *param char *rogue_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *rogueaddr) { - CPubKey roguepk; int32_t i,num,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct rogue_player P,endP; + CPubKey roguepk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct rogue_player P,endP; roguepk = GetUnspendable(cp,0); *numkeysp = 0; seed = 0; num = numkeys = 0; playertxid = zeroid; + str[0] = 0; if ( (err= rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) { - if ( rogue_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,rogueaddr,numplayers,symbol,pname) == 0 ) + if ( (retval= rogue_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,rogueaddr,numplayers,symbol,pname)) == 0 ) { UniValue obj; seed = rogue_gamefields(obj,maxplayers,buyin,gametxid,rogueaddr); - //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Rogue_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); +//fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Rogue_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); memset(&P,0,sizeof(P)); if ( playerdata.size() > 0 ) { @@ -873,6 +991,7 @@ char *rogue_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vecto fclose(fp); } } + //fprintf(stderr,"call replay2\n"); num = rogue_replay2(newplayer,seed,keystrokes,numkeys,playerdata.size()==0?0:&P,0); newdata.resize(num); for (i=0; i no playerdata\n"); + sprintf(str,"zero value character was killed -> no playerdata\n"); newdata.resize(0); - //P.gold = (P.gold * 8) / 10; + *numkeysp = numkeys; + return(keystrokes); + /* P.gold = (P.gold * 8) / 10; if ( keystrokes != 0 ) { free(keystrokes); keystrokes = 0; *numkeysp = 0; - } + return(keystrokes); + }*/ } else { - sprintf(str,"extracted $$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); - fprintf(stderr,"%s\n",str); + sprintf(str,"$$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); + //fprintf(stderr,"%s\n",str); *numkeysp = numkeys; return(keystrokes); } @@ -903,7 +1026,7 @@ char *rogue_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vecto } else { - fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p\n",keystrokes); + fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p retval.%d\n",keystrokes,retval); if ( keystrokes != 0 ) free(keystrokes), keystrokes = 0; } @@ -914,11 +1037,12 @@ char *rogue_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vecto UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result(UniValue::VOBJ); CPubKey pk,roguepk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],rogueaddr[64],*pubstr,*keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; + UniValue result(UniValue::VOBJ); CPubKey pk,roguepk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],rogueaddr[64],*pubstr,*hexstr,*keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; pk = pubkey2pk(Mypubkey()); roguepk = GetUnspendable(cp,0); result.push_back(Pair("name","rogue")); result.push_back(Pair("method","extract")); + rogueaddr[0] = 0; if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) { if ( n > 0 ) @@ -927,23 +1051,35 @@ UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) result.push_back(Pair("gametxid",gametxid.GetHex())); if ( n == 2 ) { - if ( (pubstr= jstr(jitem(params,1),0)) != 0 && strlen(pubstr) == 66 ) + if ( (pubstr= jstr(jitem(params,1),0)) != 0 ) { - decode_hex(pub33,33,pubstr); - pk = buf2pk(pub33); + if (strlen(pubstr) == 66 ) + { + decode_hex(pub33,33,pubstr); + pk = buf2pk(pub33); + } + else if ( strlen(pubstr) < 36 ) + strcpy(rogueaddr,pubstr); } //fprintf(stderr,"gametxid.%s %s\n",gametxid.GetHex().c_str(),pubstr); } - GetCCaddress1of2(cp,rogueaddr,roguepk,pk); + if ( rogueaddr[0] == 0 ) + GetCCaddress1of2(cp,rogueaddr,roguepk,pk); result.push_back(Pair("rogueaddr",rogueaddr)); str[0] = 0; if ( (keystrokes= rogue_extractgame(1,str,&numkeys,newdata,seed,playertxid,cp,gametxid,rogueaddr)) != 0 ) { result.push_back(Pair("status","success")); flag = 1; + hexstr = (char *)malloc(numkeys*2 + 1); + for (i=0; i playerdata,uint256 gametxid,CPubKey pk) +int32_t rogue_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) { static uint32_t good,bad; static uint256 prevgame; - char str[512],*keystrokes,rogueaddr[64],str2[67]; int32_t i,numkeys; std::vector newdata; uint64_t seed; CPubKey roguepk; struct rogue_player P; - if ( gametxid == prevgame ) - return(0); - prevgame = gametxid; + char str[512],*keystrokes,rogueaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed,mult = 10; CPubKey roguepk; struct rogue_player P; + *cashoutp = 0; roguepk = GetUnspendable(cp,0); GetCCaddress1of2(cp,rogueaddr,roguepk,pk); - //fprintf(stderr,"call extractgame\n"); if ( (keystrokes= rogue_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,rogueaddr)) != 0 ) { - //fprintf(stderr,"numkeys.%d rogue_extractgame %s\n",numkeys,gametxid.GetHex().c_str()); free(keystrokes); - //fprintf(stderr,"extracted.(%s)\n",str); + sprintf(fname,"rogue.%llu.pack",(long long)seed); + remove(fname); + + for (i=0; i no playerdata, good.%d bad.%d\n",good,bad); + } + *cashoutp = 0; return(0); } - fprintf(stderr,"zero value character was killed -> no playerdata, good.%d bad.%d\n",good,bad); } - bad++; - fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); - fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,rogueaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); + if ( gametxid != prevgame ) + { + prevgame = gametxid; + bad++; + disp_playerdata(newdata); + disp_playerdata(playerdata); + fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); + fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,rogueaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); + } } - //fprintf(stderr,"no keys rogue_extractgame %s\n",gametxid.GetHex().c_str()); + sprintf(fname,"rogue.%llu.pack",(long long)seed); + remove(fname); + //fprintf(stderr,"no keys rogue_extractgame %s\n",gametxid.GetHex().c_str()); return(-1); } @@ -1020,7 +1192,7 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param // vout0 -> 1% ingame gold // get any playerdata, get all keystrokes, replay game and compare final state CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed,mult; int64_t buyin,batonvalue,inputsum,cashout,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char myrogueaddr[64],*keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,roguepk; uint8_t player[10000],mypriv[32],funcid; + UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed,mult; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char myrogueaddr[64],*keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,roguepk; uint8_t player[10000],mypriv[32],funcid; struct CCcontract_info *cpTokens, tokensC; if ( txfee == 0 ) @@ -1086,33 +1258,38 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param } else { - //if ( maxplayers == 1 ) - // mult /= 2; cpTokens = CCinit(&tokensC, EVAL_TOKENS); mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); if ( P.amulet != 0 ) mult *= 5; dungeonlevel = P.dungeonlevel; - if ( P.amulet != 0 && dungeonlevel < 21 ) - dungeonlevel = 21; + if ( P.amulet != 0 && dungeonlevel < 26 ) + dungeonlevel = 26; cashout = (uint64_t)P.gold * P.gold * mult * dungeonlevel; fprintf(stderr,"\nextracted $$$gold.%d -> %.8f ROGUE hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,(double)cashout/COIN,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); if ( funcid == 'H' && maxplayers > 1 ) { - if ( (numplayers != maxplayers || (numplayers - rogue_playersalive(tmp,gametxid,maxplayers)) > 1) && P.amulet == 0 ) - return(cclib_error(result,"highlander must be a winner or last one standing")); + if ( P.amulet == 0 ) + { + if ( numplayers != maxplayers ) + return(cclib_error(result,"numplayers != maxplayers")); + else if ( rogue_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) + return(cclib_error(result,"highlander must be a winner or last one standing")); + } cashout += numplayers * buyin; } - if ( cashout >= txfee ) + if ( cashout > 0 ) { - if ( (inputsum= AddCClibInputs(cp,mtx,roguepk,cashout,16,cp->unspendableCCaddr)) > (uint64_t)P.gold*mult ) + if ( (inputsum= AddCClibInputs(cp,mtx,roguepk,cashout,60,cp->unspendableCCaddr)) > cashout ) CCchange = (inputsum - cashout); - mtx.vout.push_back(CTxOut(cashout,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + else fprintf(stderr,"couldnt find enough utxos\n"); } + mtx.vout.push_back(CTxOut(cashout,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); } } - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange + (batonvalue-3*txfee),roguepk)); + if ( CCchange + (batonvalue-3*txfee) >= txfee ) + mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange + (batonvalue-3*txfee),roguepk)); Myprivkey(mypriv); CCaddr1of2set(cp,roguepk,mypk,mypriv,myrogueaddr); CScript opret; @@ -1154,7 +1331,7 @@ UniValue rogue_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *param UniValue rogue_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i,n,gameheight,maxplayers,numvouts; uint256 txid; CTransaction tx; int64_t buyin; uint64_t seed; bits256 t; char myrogueaddr[64]; CPubKey mypk,roguepk; + UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i,n,gameheight,maxplayers,numvouts; uint256 txid; CTransaction tx; int64_t buyin; uint64_t seed; bits256 t; char myrogueaddr[64],str[64]; CPubKey mypk,roguepk; result.push_back(Pair("name","rogue")); result.push_back(Pair("method","gameinfo")); if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) @@ -1175,12 +1352,17 @@ UniValue rogue_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) result.push_back(Pair("seed",(int64_t)seed)); for (i=0; i > unspentOutputs; roguepk = GetUnspendable(cp,0); GetCCaddress(cp,coinaddr,roguepk); @@ -1206,8 +1388,8 @@ UniValue rogue_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) continue; if ( rogue_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,1) == 0 && nextheight <= gameheight+ROGUE_MAXKEYSTROKESGAP ) { - rogue_playersalive(numplayers,txid,maxplayers); - if ( numplayers < maxplayers ) + rogue_playersalive(openslots,numplayers,txid,maxplayers,gameheight,tx); + if ( openslots > 0 ) a.push_back(txid.GetHex()); } } @@ -1270,7 +1452,7 @@ UniValue rogue_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { if ( rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 ) { - if ( CCgettxout(txid,vout,1) < 0 ) + if ( CCgettxout(txid,vout,1,0) < 0 ) b.push_back(gametxid.GetHex()); else a.push_back(gametxid.GetHex()); } @@ -1308,11 +1490,19 @@ UniValue rogue_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { - CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid; int32_t i,maxplayers,decoded=0,regslot,ind,err,dispflag,gameheight,score,numvouts; CTransaction vintx,gametx; CPubKey pk; uint256 hashBlock,gametxid,tokenid,batontxid,playertxid,ptxid; int64_t buyin; std::vector playerdata,keystrokes; std::string symbol,pname; - if ( strcmp(ASSETCHAINS_SYMBOL,"ROGUE") == 0 && height < 21274 ) - return(true); + CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid,tokentx=0; int32_t i,maxplayers,enabled = 0,decoded=0,regslot,ind,err,dispflag,gameheight,score,numvouts; CTransaction vintx,gametx; CPubKey pk; uint256 hashBlock,gametxid,txid,tokenid,batontxid,playertxid,ptxid; int64_t buyin,cashout; std::vector playerdata,keystrokes; std::string symbol,pname; + if ( strcmp(ASSETCHAINS_SYMBOL,"ROGUE") == 0 ) + { + if (height < 21274 ) + return(true); + else if ( height > 50000 ) + enabled = 1; + } else enabled = 1; if ( (numvouts= tx.vout.size()) > 1 ) { + txid = tx.GetHash(); + if ( txid == Parseuint256("1ae04dc0c5f2fca2053819a3a1b2efe5d355c34f58d6f16d59e5e2573e7baf7f") ) // osx rogue chain ht.50902 + enabled = 0; scriptPubKey = tx.vout[numvouts-1].scriptPubKey; GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() > 2 ) @@ -1321,6 +1511,7 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C funcid = script[1]; if ( (e= script[0]) == EVAL_TOKENS ) { + tokentx = funcid; if ( (funcid= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) == 0 ) { if ( (funcid= rogue_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) == 0 ) @@ -1351,9 +1542,7 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C case 'R': if ( (funcid= rogue_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) != 'R' ) { - //fprintf(stderr,"height.%d couldnt decode register opret\n",height); - //if ( height > 20000 ) - return eval->Invalid("couldnt decode register opret"); + return eval->Invalid("couldnt decode register opret"); } // baton is created // validation is done below @@ -1361,22 +1550,13 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C case 'K': if ( (funcid= rogue_keystrokesopretdecode(gametxid,batontxid,pk,keystrokes,scriptPubKey)) != 'K' ) { - //fprintf(stderr,"height.%d couldnt decode keystrokes opret\n",height); - //if ( height > 20000 ) - return eval->Invalid("couldnt decode keystrokes opret"); + return eval->Invalid("couldnt decode keystrokes opret"); } // spending the baton proves it is the user if the pk is the signer return(true); break; case 'H': case 'Q': - if ( (f= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) != funcid ) - { - //fprintf(stderr,"height.%d couldnt decode H/Q opret\n",height); - //if ( height > 20000 ) - return eval->Invalid("couldnt decode H/Q opret"); - } - // spending the baton proves it is the user if the pk is the signer - // rest of validation is done below + // done in the next switch statement as there are some H/Q tx with playerdata which would skip this section break; default: return eval->Invalid("illegal rogue non-decoded funcid"); @@ -1390,13 +1570,40 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C return(true); case 'H': // win case 'Q': // bailout - // verify pk belongs to this tx - if ( playerdata.size() > 0 ) + if ( (f= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) != funcid ) { - if ( rogue_playerdata_validate(ptxid,cp,playerdata,gametxid,pk) < 0 ) + //fprintf(stderr,"height.%d couldnt decode H/Q opret\n",height); + //if ( height > 20000 ) + return eval->Invalid("couldnt decode H/Q opret"); + } + // verify pk belongs to this tx + if ( tokentx == 'c' ) + { + if ( playerdata.size() > 0 ) { - //fprintf(stderr,"ht.%d gametxid.%s player.%s invalid playerdata[%d]\n",height,gametxid.GetHex().c_str(),ptxid.GetHex().c_str(),(int32_t)playerdata.size()); - } //else fprintf(stderr,"ht.%d playertxid.%s validated\n",height,ptxid.GetHex().c_str()); + static char laststr[512]; char cashstr[512]; + if ( rogue_playerdata_validate(&cashout,ptxid,cp,playerdata,gametxid,pk) < 0 ) + { + sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d gametxid.%s player.%s invalid playerdata[%d]\n",tokentx,decoded,height,gametxid.GetHex().c_str(),ptxid.GetHex().c_str(),(int32_t)playerdata.size()); + if ( strcmp(laststr,cashstr) != 0 ) + { + strcpy(laststr,cashstr); + fprintf(stderr,"%s\n",cashstr); + } + if ( enabled != 0 ) + return eval->Invalid("mismatched playerdata"); + } + if ( funcid == 'H' ) + cashout *= 2; + sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d txid.%s %.8f vs vout2 %.8f",tokentx,decoded,height,txid.GetHex().c_str(),(double)cashout/COIN,(double)tx.vout[2].nValue/COIN); + if ( strcmp(laststr,cashstr) != 0 ) + { + strcpy(laststr,cashstr); + fprintf(stderr,"%s\n",cashstr); + } + } else cashout = 10000; + if ( enabled != 0 && tx.vout[2].nValue > cashout ) + return eval->Invalid("mismatched cashout amount"); } if ( funcid == 'Q' ) { diff --git a/src/cc/sudoku.cpp b/src/cc/sudoku.cpp index 49bcf79d9..a9efdd950 100644 --- a/src/cc/sudoku.cpp +++ b/src/cc/sudoku.cpp @@ -2859,7 +2859,7 @@ UniValue sudoku_solution(uint64_t txfee,struct CCcontract_info *cp,cJSON *params decode_hex((uint8_t *)&txid,32,txidstr); txid = revuint256(txid); result.push_back(Pair("txid",txid.GetHex())); - if ( CCgettxout(txid,0,1) < 0 ) + if ( CCgettxout(txid,0,1,0) < 0 ) result.push_back(Pair("error","already solved")); else if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 1 ) { diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp new file mode 100644 index 000000000..d6ae473fe --- /dev/null +++ b/src/cc/tetris.cpp @@ -0,0 +1,2411 @@ + +/***************************************************************************/ +/** https://github.com/brenns10/tetris + @file main.c + @author Stephen Brennan + @date Created Wednesday, 10 June 2015 + @brief Main program for tetris. + @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised + BSD License. See LICENSE.txt for details. + *******************************************************************************/ + + +#ifndef TETRIS_H +#define TETRIS_H + +#include // for FILE +#include // for bool +#include +#include +#include +#include +#include + +#include +#include + +//#include +//#include + + +/* + Convert a tetromino type to its corresponding cell. + */ +#define TYPE_TO_CELL(x) ((x)+1) + +/* + Strings for how you would print a tetris board. + */ +#define TC_EMPTY_STR " " +#define TC_BLOCK_STR "\u2588" + +/* + Questions about a tetris cell. + */ +#define TC_IS_EMPTY(x) ((x) == TC_EMPTY) +#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x)) + +/* + How many cells in a tetromino? + */ +#define TETRIS 4 +/* + How many tetrominos? + */ +#define NUM_TETROMINOS 7 +/* + How many orientations of a tetromino? + */ +#define NUM_ORIENTATIONS 4 + +/* + Level constants. + */ +#define MAX_LEVEL 19 +#define LINES_PER_LEVEL 10 + +/* + A "cell" is a 1x1 block within a tetris board. + */ +typedef enum { + TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ +} tetris_cell; + +/* + A "type" is a type/shape of a tetromino. Not including orientation. + */ +typedef enum { + TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z +} tetris_type; + +/* + A row,column pair. Negative numbers allowed, because we need them for + offsets. + */ +typedef struct { + int row; + int col; +} tetris_location; + +/* + A "block" is a struct that contains information about a tetromino. + Specifically, what type it is, what orientation it has, and where it is. + */ +typedef struct { + int typ; + int ori; + tetris_location loc; +} tetris_block; + +/* + All possible moves to give as input to the game. + */ +typedef enum { + TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE +} tetris_move; + +/* + A game object! + */ +typedef struct { + /* + Game board stuff: + */ + int rows; + int cols; + char *board; + /* + Scoring information: + */ + int points; + int level; + /* + Falling block is the one currently going down. Next block is the one that + will be falling after this one. Stored is the block that you can swap out. + */ + tetris_block falling; + tetris_block next; + tetris_block stored; + /* + Number of game ticks until the block will move down. + */ + int ticks_till_gravity; + /* + Number of lines until you advance to the next level. + */ + int lines_remaining; +} tetris_game; + +/* + This array stores all necessary information about the cells that are filled by + each tetromino. The first index is the type of the tetromino (i.e. shape, + e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final + array contains 4 tetris_location objects, each mapping to an offset from a + point on the upper left that is the tetromino "origin". + */ +extern tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; + +/* + This array tells you how many ticks per gravity by level. Decreases as level + increases, to add difficulty. + */ +extern int GRAVITY_LEVEL[MAX_LEVEL+1]; + +// Data structure manipulation. +void tg_init(tetris_game *obj, int rows, int cols); +tetris_game *tg_create(int rows, int cols); +void tg_destroy(tetris_game *obj); +void tg_delete(tetris_game *obj); +tetris_game *tg_load(FILE *f); +void tg_save(tetris_game *obj, FILE *f); + +// Public methods not related to memory: +char tg_get(tetris_game *obj, int row, int col); +bool tg_check(tetris_game *obj, int row, int col); +bool tg_tick(tetris_game *obj, tetris_move move); +void tg_print(tetris_game *obj, FILE *f); + +#endif // TETRIS_H + + +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) + +/******************************************************************************* + Array Definitions + *******************************************************************************/ + +tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = { + // I + {{{1, 0}, {1, 1}, {1, 2}, {1, 3}}, + {{0, 2}, {1, 2}, {2, 2}, {3, 2}}, + {{3, 0}, {3, 1}, {3, 2}, {3, 3}}, + {{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, + // J + {{{0, 0}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {2, 1}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 2}}, + {{0, 1}, {1, 1}, {2, 0}, {2, 1}}}, + // L + {{{0, 2}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {1, 1}, {2, 1}, {2, 2}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 0}}, + {{0, 0}, {0, 1}, {1, 1}, {2, 1}}}, + // O + {{{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}}, + // S + {{{0, 1}, {0, 2}, {1, 0}, {1, 1}}, + {{0, 1}, {1, 1}, {1, 2}, {2, 2}}, + {{1, 1}, {1, 2}, {2, 0}, {2, 1}}, + {{0, 0}, {1, 0}, {1, 1}, {2, 1}}}, + // T + {{{0, 1}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {1, 1}, {1, 2}, {2, 1}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 1}}, + {{0, 1}, {1, 0}, {1, 1}, {2, 1}}}, + // Z + {{{0, 0}, {0, 1}, {1, 1}, {1, 2}}, + {{0, 2}, {1, 1}, {1, 2}, {2, 1}}, + {{1, 0}, {1, 1}, {2, 1}, {2, 2}}, + {{0, 1}, {1, 0}, {1, 1}, {2, 0}}}, +}; + +int GRAVITY_LEVEL[MAX_LEVEL+1] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, + //10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 30, 28, 26, 24, 22, 20, 16, 12, 8, 4 +}; + +/******************************************************************************* + Helper Functions for Blocks + *******************************************************************************/ + +void sleep_milli(int milliseconds) +{ + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = milliseconds * 1000 * 1000; + nanosleep(&ts, NULL); +} + +/* + Return the block at the given row and column. + */ +char tg_get(tetris_game *obj, int row, int column) +{ + return obj->board[obj->cols * row + column]; +} + +/* + Set the block at the given row and column. + */ +static void tg_set(tetris_game *obj, int row, int column, char value) +{ + obj->board[obj->cols * row + column] = value; +} + +/* + Check whether a row and column are in bounds. + */ +bool tg_check(tetris_game *obj, int row, int col) +{ + return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols; +} + +/* + Place a block onto the board. + */ +static void tg_put(tetris_game *obj, tetris_block block) +{ + int i; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, + TYPE_TO_CELL(block.typ)); + } +} + +/* + Clear a block out of the board. + */ +static void tg_remove(tetris_game *obj, tetris_block block) +{ + int i; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY); + } +} + +/* + Check if a block can be placed on the board. + */ +static bool tg_fits(tetris_game *obj, tetris_block block) +{ + int i, r, c; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + r = block.loc.row + cell.row; + c = block.loc.col + cell.col; + if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) { + return false; + } + } + return true; +} + +/* + Return a random tetromino type. + */ +static int random_tetromino(void) { + return rand() % NUM_TETROMINOS; +} + +/* + Create a new falling block and populate the next falling block with a random + one. + */ +static void tg_new_falling(tetris_game *obj) +{ + // Put in a new falling tetromino. + obj->falling = obj->next; + obj->next.typ = random_tetromino(); + obj->next.ori = 0; + obj->next.loc.row = 0; + obj->next.loc.col = obj->cols/2 - 2; +} + +/******************************************************************************* + Game Turn Helpers + *******************************************************************************/ + +/* + Tick gravity, and move the block down if gravity should act. + */ +static void tg_do_gravity_tick(tetris_game *obj) +{ + obj->ticks_till_gravity--; + if (obj->ticks_till_gravity <= 0) { + tg_remove(obj, obj->falling); + obj->falling.loc.row++; + if (tg_fits(obj, obj->falling)) { + obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; + } else { + obj->falling.loc.row--; + tg_put(obj, obj->falling); + + tg_new_falling(obj); + } + tg_put(obj, obj->falling); + } +} + +/* + Move the falling tetris block left (-1) or right (+1). + */ +static void tg_move(tetris_game *obj, int direction) +{ + tg_remove(obj, obj->falling); + obj->falling.loc.col += direction; + if (!tg_fits(obj, obj->falling)) { + obj->falling.loc.col -= direction; + } + tg_put(obj, obj->falling); +} + +/* + Send the falling tetris block to the bottom. + */ +static void tg_down(tetris_game *obj) +{ + tg_remove(obj, obj->falling); + while (tg_fits(obj, obj->falling)) { + obj->falling.loc.row++; + } + obj->falling.loc.row--; + tg_put(obj, obj->falling); + tg_new_falling(obj); +} + +/* + Rotate the falling block in either direction (+/-1). + */ +static void tg_rotate(tetris_game *obj, int direction) +{ + tg_remove(obj, obj->falling); + + while (true) { + obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS; + + // If the new orientation fits, we're done. + if (tg_fits(obj, obj->falling)) + break; + + // Otherwise, try moving left to make it fit. + obj->falling.loc.col--; + if (tg_fits(obj, obj->falling)) + break; + + // Finally, try moving right to make it fit. + obj->falling.loc.col += 2; + if (tg_fits(obj, obj->falling)) + break; + + // Put it back in its original location and try the next orientation. + obj->falling.loc.col--; + // Worst case, we come back to the original orientation and it fits, so this + // loop will terminate. + } + + tg_put(obj, obj->falling); +} + +/* + Swap the falling block with the block in the hold buffer. + */ +static void tg_hold(tetris_game *obj) +{ + tg_remove(obj, obj->falling); + if (obj->stored.typ == -1) { + obj->stored = obj->falling; + tg_new_falling(obj); + } else { + int typ = obj->falling.typ, ori = obj->falling.ori; + obj->falling.typ = obj->stored.typ; + obj->falling.ori = obj->stored.ori; + obj->stored.typ = typ; + obj->stored.ori = ori; + while (!tg_fits(obj, obj->falling)) { + obj->falling.loc.row--; + } + } + tg_put(obj, obj->falling); +} + +/* + Perform the action specified by the move. + */ +static void tg_handle_move(tetris_game *obj, tetris_move move) +{ + switch (move) { + case TM_LEFT: + tg_move(obj, -1); + break; + case TM_RIGHT: + tg_move(obj, 1); + break; + case TM_DROP: + tg_down(obj); + break; + case TM_CLOCK: + tg_rotate(obj, 1); + break; + case TM_COUNTER: + tg_rotate(obj, -1); + break; + case TM_HOLD: + tg_hold(obj); + break; + default: + // pass + break; + } +} + +/* + Return true if line i is full. + */ +static bool tg_line_full(tetris_game *obj, int i) +{ + int j; + for (j = 0; j < obj->cols; j++) { + if (TC_IS_EMPTY(tg_get(obj, i, j))) + return false; + } + return true; +} + +/* + Shift every row above r down one. + */ +static void tg_shift_lines(tetris_game *obj, int r) +{ + int i, j; + for (i = r-1; i >= 0; i--) { + for (j = 0; j < obj->cols; j++) { + tg_set(obj, i+1, j, tg_get(obj, i, j)); + tg_set(obj, i, j, TC_EMPTY); + } + } +} + +/* + Find rows that are filled, remove them, shift, and return the number of + cleared rows. + */ +static int tg_check_lines(tetris_game *obj) +{ + int i, nlines = 0; + tg_remove(obj, obj->falling); // don't want to mess up falling block + + for (i = obj->rows-1; i >= 0; i--) { + if (tg_line_full(obj, i)) { + tg_shift_lines(obj, i); + i++; // do this line over again since they're shifted + nlines++; + } + } + + tg_put(obj, obj->falling); // replace + return nlines; +} + +/* + Adjust the score for the game, given how many lines were just cleared. + */ +static void tg_adjust_score(tetris_game *obj, int lines_cleared) +{ + static int line_multiplier[] = {0, 40, 100, 300, 1200}; + obj->points += line_multiplier[lines_cleared] * (obj->level + 1); + if (lines_cleared >= obj->lines_remaining) { + obj->level = MIN(MAX_LEVEL, obj->level + 1); + lines_cleared -= obj->lines_remaining; + obj->lines_remaining = LINES_PER_LEVEL - lines_cleared; + } else { + obj->lines_remaining -= lines_cleared; + } +} + +/* + Return true if the game is over. + */ +static bool tg_game_over(tetris_game *obj) +{ + int i, j; + bool over = false; + tg_remove(obj, obj->falling); + for (i = 0; i < 2; i++) { + for (j = 0; j < obj->cols; j++) { + if (TC_IS_FILLED(tg_get(obj, i, j))) { + over = true; + } + } + } + tg_put(obj, obj->falling); + return over; +} + +/******************************************************************************* + Main Public Functions + *******************************************************************************/ + +/* + Do a single game tick: process gravity, user input, and score. Return true if + the game is still running, false if it is over. + */ +bool tg_tick(tetris_game *obj, tetris_move move) +{ + int lines_cleared; + // Handle gravity. + tg_do_gravity_tick(obj); + + // Handle input. + tg_handle_move(obj, move); + + // Check for cleared lines + lines_cleared = tg_check_lines(obj); + + tg_adjust_score(obj, lines_cleared); + + // Return whether the game will continue (NOT whether it's over) + return !tg_game_over(obj); +} + +void tg_init(tetris_game *obj, int rows, int cols) +{ + // Initialization logic + obj->rows = rows; + obj->cols = cols; + obj->board = (char *)malloc(rows * cols); + memset(obj->board, TC_EMPTY, rows * cols); + obj->points = 0; + obj->level = 0; + obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; + obj->lines_remaining = LINES_PER_LEVEL; + srand(time(NULL)); + tg_new_falling(obj); + tg_new_falling(obj); + obj->stored.typ = -1; + obj->stored.ori = 0; + obj->stored.loc.row = 0; + obj->next.loc.col = obj->cols/2 - 2; + printf("%d", obj->falling.loc.col); +} + +tetris_game *tg_create(int rows, int cols) +{ + tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); + tg_init(obj, rows, cols); + return obj; +} + +void tg_destroy(tetris_game *obj) +{ + // Cleanup logic + free(obj->board); +} + +void tg_delete(tetris_game *obj) { + tg_destroy(obj); + free(obj); +} + +/* + Load a game from a file. + */ +tetris_game *tg_load(FILE *f) +{ + tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); + if (fread(obj, sizeof(tetris_game), 1, f) != 1 ) + { + fprintf(stderr,"read game error\n"); + free(obj); + obj = 0; + } + else + { + obj->board = (char *)malloc(obj->rows * obj->cols); + if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + { + fprintf(stderr,"fread error\n"); + free(obj->board); + free(obj); + obj = 0; + } + } + return obj; +} + +/* + Save a game to a file. + */ +void tg_save(tetris_game *obj, FILE *f) +{ + if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) + fprintf(stderr,"error writing tetrisgame\n"); + else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + fprintf(stderr,"error writing board\n"); +} + +/* + Print a game board to a file. Really just for early debugging. + */ +void tg_print(tetris_game *obj, FILE *f) { + int i, j; + for (i = 0; i < obj->rows; i++) { + for (j = 0; j < obj->cols; j++) { + if (TC_IS_EMPTY(tg_get(obj, i, j))) { + fputs(TC_EMPTY_STR, f); + } else { + fputs(TC_BLOCK_STR, f); + } + } + fputc('\n', f); + } +} + +/* + 2 columns per cell makes the game much nicer. + */ +#define COLS_PER_CELL 2 +/* + Macro to print a cell of a specific type to a window. + */ +#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \ +waddch((w),' '|A_REVERSE|COLOR_PAIR(x)) +#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ') + +/* + Print the tetris board onto the ncurses window. + */ +void display_board(WINDOW *w, tetris_game *obj) +{ + int i, j; + box(w, 0, 0); + for (i = 0; i < obj->rows; i++) { + wmove(w, 1 + i, 1); + for (j = 0; j < obj->cols; j++) { + if (TC_IS_FILLED(tg_get(obj, i, j))) { + ADD_BLOCK(w,tg_get(obj, i, j)); + } else { + ADD_EMPTY(w); + } + } + } + wnoutrefresh(w); +} + +/* + Display a tetris piece in a dedicated window. + */ +void display_piece(WINDOW *w, tetris_block block) +{ + int b; + tetris_location c; + wclear(w); + box(w, 0, 0); + if (block.typ == -1) { + wnoutrefresh(w); + return; + } + for (b = 0; b < TETRIS; b++) { + c = TETROMINOS[block.typ][block.ori][b]; + wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1); + ADD_BLOCK(w, TYPE_TO_CELL(block.typ)); + } + wnoutrefresh(w); +} + +/* + Display score information in a dedicated window. + */ +void display_score(WINDOW *w, tetris_game *tg) +{ + wclear(w); + box(w, 0, 0); + wprintw(w, "Score\n%d\n", tg->points); + wprintw(w, "Level\n%d\n", tg->level); + wprintw(w, "Lines\n%d\n", tg->lines_remaining); + wnoutrefresh(w); +} + +/* + Boss mode! Make it look like you're doing work. + */ +void boss_mode(void) +{ + clear(); + //Mix_PauseMusic(); + printw("user@workstation-312:~/Documents/presentation $ ls -l\n" + "total 528\n" + "drwxr-xr-x 2 user users 4096 Jun 9 17:05 .\n" + "drwxr-xr-x 4 user users 4096 Jun 10 09:52 ..\n" + "-rw-r--r-- 1 user users 88583 Jun 9 14:13 figure1.png\n" + "-rw-r--r-- 1 user users 65357 Jun 9 15:40 figure2.png\n" + "-rw-r--r-- 1 user users 4469 Jun 9 16:17 presentation.aux\n" + "-rw-r--r-- 1 user users 42858 Jun 9 16:17 presentation.log\n" + "-rw-r--r-- 1 user users 2516 Jun 9 16:17 presentation.nav\n" + "-rw-r--r-- 1 user users 183 Jun 9 16:17 presentation.out\n" + "-rw-r--r-- 1 user users 349607 Jun 9 16:17 presentation.pdf\n" + "-rw-r--r-- 1 user users 0 Jun 9 16:17 presentation.snm\n" + "-rw-r--r-- 1 user users 9284 Jun 9 17:05 presentation.tex\n" + "-rw-r--r-- 1 user users 229 Jun 9 16:17 presentation.toc\n" + "\n" + "user@workstation-312:~/Documents/presentation $ "); + echo(); + timeout(-1); + while (getch() != KEY_F(1)); + timeout(0); + noecho(); + clear(); + //Mix_ResumeMusic(); +} + +/* + Save and exit the game. + */ +void save(tetris_game *game, WINDOW *w) +{ + FILE *f; + + wclear(w); + box(w, 0, 0); // return the border + wmove(w, 1, 1); + wprintw(w, "Save and exit? [Y/n] "); + wrefresh(w); + timeout(-1); + if (getch() == 'n') { + timeout(0); + return; + } + f = fopen("tetris.save", "w"); + tg_save(game, f); + fclose(f); + tg_delete(game); + endwin(); + printf("Game saved to \"tetris.save\".\n"); + printf("Resume by passing the filename as an argument to this program.\n"); + exit(EXIT_SUCCESS); +} + +/* + Do the NCURSES initialization steps for color blocks. + */ +void init_colors(void) +{ + start_color(); + //init_color(COLOR_ORANGE, 1000, 647, 0); + init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK); + init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK); + init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK); + init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK); + init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK); + init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK); + init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); +} + +/* + Main tetris game! + */ +#ifdef STANDALONE + +int main(int argc, char **argv) +{ + tetris_game *tg; + tetris_move move = TM_NONE; + bool running = true; + WINDOW *board, *next, *hold, *score; + //Mix_Music *music; + + // Load file if given a filename. + if (argc >= 2) { + FILE *f = fopen(argv[1], "r"); + if (f == NULL) { + perror("tetris"); + exit(EXIT_FAILURE); + } + tg = tg_load(f); + fclose(f); + } else { + // Otherwise create new game. + tg = tg_create(22, 10); + } + + /* Initialize music. + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + fprintf(stderr, "unable to initialize SDL\n"); + exit(EXIT_FAILURE); + } + if (Mix_Init(MIX_INIT_MP3) != MIX_INIT_MP3) { + fprintf(stderr, "unable to initialize SDL_mixer\n"); + exit(EXIT_FAILURE); + } + if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024) != 0) { + fprintf(stderr, "unable to initialize audio\n"); + exit(EXIT_FAILURE); + } + Mix_AllocateChannels(1); // only need background music + music = Mix_LoadMUS("tetris.mp3"); + if (music) { + Mix_PlayMusic(music, -1); + }*/ + + // NCURSES initialization: + initscr(); // initialize curses + cbreak(); // pass key presses to program, but not signals + noecho(); // don't echo key presses to screen + keypad(stdscr, TRUE); // allow arrow keys + timeout(0); // no blocking on getch() + curs_set(0); // set the cursor to invisible + init_colors(); // setup tetris colors + + // Create windows for each section of the interface. + board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); + next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); + hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); + score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); + int32_t counter = 0; + // Game loop + while (running) { + running = tg_tick(tg, move); + display_board(board, tg); + display_piece(next, tg->next); + display_piece(hold, tg->stored); + display_score(score, tg); + if ( (counter++ % 5) == 0 ) + doupdate(); + sleep_milli(10); + + switch (getch()) { + case KEY_LEFT: + move = TM_LEFT; + break; + case KEY_RIGHT: + move = TM_RIGHT; + break; + case KEY_UP: + move = TM_CLOCK; + break; + case KEY_DOWN: + move = TM_DROP; + break; + case 'q': + running = false; + move = TM_NONE; + break; + case 'p': + wclear(board); + box(board, 0, 0); + wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); + wprintw(board, "PAUSED"); + wrefresh(board); + timeout(-1); + getch(); + timeout(0); + move = TM_NONE; + break; + case 'b': + boss_mode(); + move = TM_NONE; + break; + case 's': + save(tg, board); + move = TM_NONE; + break; + case ' ': + move = TM_HOLD; + break; + default: + move = TM_NONE; + } + } + + // Deinitialize NCurses + wclear(stdscr); + endwin(); + + /* Deinitialize Sound + Mix_HaltMusic(); + Mix_FreeMusic(music); + Mix_CloseAudio(); + Mix_Quit();*/ + + // Output ending message. + printf("Game over!\n"); + printf("You finished with %d points on level %d.\n", tg->points, tg->level); + + // Deinitialize Tetris + tg_delete(tg); + return 0; +} +#else + +/****************************************************************************** + * Copyright © 2014-2019 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "cJSON.h" +#include "CCinclude.h" + +#define TETRIS_REGISTRATION 5 +#define TETRIS_REGISTRATIONSIZE (100 * 10000) +#define TETRIS_MAXPLAYERS 64 // need to send unused fees back to globalCC address to prevent leeching +#define TETRIS_MAXKEYSTROKESGAP 60 +#define TETRIS_MAXITERATIONS 777 + + +std::string Tetris_pname = ""; + +CScript tetris_newgameopret(int64_t buyin,int32_t maxplayers) +{ + CScript opret; uint8_t evalcode = EVAL_TETRIS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'G' << buyin << maxplayers); + return(opret); +} + +CScript tetris_registeropret(uint256 gametxid,uint256 playertxid) +{ + CScript opret; uint8_t evalcode = EVAL_TETRIS; + //fprintf(stderr,"opret.(%s %s).R\n",gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'R' << gametxid << playertxid); + return(opret); +} + +CScript tetris_keystrokesopret(uint256 gametxid,uint256 batontxid,CPubKey pk,std::vectorkeystrokes) +{ + CScript opret; uint8_t evalcode = EVAL_TETRIS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'K' << gametxid << batontxid << pk << keystrokes); + return(opret); +} + +CScript tetris_highlanderopret(uint8_t funcid,uint256 gametxid,int32_t regslot,CPubKey pk,std::vectorplayerdata,std::string pname) +{ + CScript opret; uint8_t evalcode = EVAL_TETRIS; std::string symbol(ASSETCHAINS_SYMBOL); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << gametxid << symbol << pname << regslot << pk << playerdata ); + return(opret); +} + +uint8_t tetris_highlanderopretdecode(uint256 &gametxid, uint256 &tokenid, int32_t ®slot, CPubKey &pk, std::vector &playerdata, std::string &symbol, std::string &pname,CScript scriptPubKey) +{ + std::string name, description; std::vector vorigPubkey; + std::vector> oprets, opretsDummy; + std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; + uint8_t e, f,*script; std::vector voutPubkeys; + tokenid = zeroid; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description, oprets)) == 'c' ) + { + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); + vopret = vopretNonfungible; + } + else if ( script[1] != 'H' && script[1] != 'Q' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, opretsDummy)) != 0 ) + { + //fprintf(stderr,"decode opret %c tokenid.%s\n",script[1],tokenid.GetHex().c_str()); + GetNonfungibleData(tokenid, vopretNonfungible); //load nonfungible data from the 'tokenbase' tx + vopret = vopretNonfungible; + } + if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> gametxid; ss >> symbol; ss >> pname; ss >> regslot; ss >> pk; ss >> playerdata) != 0 && e == EVAL_TETRIS && (f == 'H' || f == 'Q') ) + { + return(f); + } + fprintf(stderr,"SKIP obsolete: e.%d f.%c game.%s regslot.%d psize.%d\n",e,f,gametxid.GetHex().c_str(),regslot,(int32_t)playerdata.size()); + return(0); +} + +uint8_t tetris_keystrokesopretdecode(uint256 &gametxid,uint256 &batontxid,CPubKey &pk,std::vector &keystrokes,CScript scriptPubKey) +{ + std::vector vopret; uint8_t e,f; + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> gametxid; ss >> batontxid; ss >> pk; ss >> keystrokes) != 0 && e == EVAL_TETRIS && f == 'K' ) + { + return(f); + } + return(0); +} + +uint8_t tetris_registeropretdecode(uint256 &gametxid,uint256 &tokenid,uint256 &playertxid,CScript scriptPubKey) +{ + std::string name, description; std::vector vorigPubkey; + std::vector> oprets; + std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; + uint8_t e, f,*script; std::vector voutPubkeys; + tokenid = zeroid; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description,oprets)) == 'c' ) + { + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); + vopret = vopretNonfungible; + } + else if ( script[1] != 'R' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, oprets)) != 0 ) + { + GetOpretBlob(oprets, OPRETID_TETRISGAMEDATA, vopretDummy); // blob from non-creation tx opret + vopret = vopretDummy; + } + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> gametxid; ss >> playertxid) != 0 && e == EVAL_TETRIS && f == 'R' ) + { + return(f); + } + //fprintf(stderr,"e.%d f.%c game.%s playertxid.%s\n",e,f,gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); + return(0); +} + +uint8_t tetris_newgameopreturndecode(int64_t &buyin,int32_t &maxplayers,CScript scriptPubKey) +{ + std::vector vopret; uint8_t e,f; + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> buyin; ss >> maxplayers) != 0 && e == EVAL_TETRIS && f == 'G' ) + { + return(f); + } + return(0); +} + +void tetris_univalue(UniValue &result,const char *method,int64_t maxplayers,int64_t buyin) +{ + if ( method != 0 ) + { + result.push_back(Pair("name","tetris")); + result.push_back(Pair("method",method)); + } + if ( maxplayers > 0 ) + result.push_back(Pair("maxplayers",maxplayers)); + if ( buyin >= 0 ) + { + result.push_back(Pair("buyin",ValueFromAmount(buyin))); + if ( buyin == 0 ) + result.push_back(Pair("type","newbie")); + else result.push_back(Pair("type","buyin")); + } +} + +int32_t tetris_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx,char *mytetrisaddr) +{ + int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; char destaddr[64]; + for (i=0; i= 0 ) + { + if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) + { + Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey); + if ( strcmp(mytetrisaddr,destaddr) == 0 ) + return(1); + //else fprintf(stderr,"myaddr.%s vs %s\n",mytetrisaddr,destaddr); + } //else fprintf(stderr,"cant find spenttxid.%s\n",spenttxid.GetHex().c_str()); + } //else fprintf(stderr,"vout %d is unspent\n",vout); + } + return(0); +} + +int32_t tetris_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0) +{ + uint256 hashBlock; int32_t i,numvouts; char coinaddr[64]; CPubKey tetrispk; uint64_t txfee = 10000; + buyin = maxplayers = 0; + if ( (txid == zeroid || myGetTransaction(txid,tx,hashBlock) != 0) && (numvouts= tx.vout.size()) > 1 ) + { + if ( txid != zeroid ) + gameheight = komodo_blockheight(hashBlock); + else + { + txid = tx.GetHash(); + //fprintf(stderr,"set txid %s %llu\n",txid.GetHex().c_str(),(long long)CCgettxout(txid,0,1)); + } + if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) == txfee && (unspentv0 == 0 || CCgettxout(txid,0,1,0) == txfee) ) + { + if ( tetris_newgameopreturndecode(buyin,maxplayers,tx.vout[numvouts-1].scriptPubKey) == 'G' ) + { + if ( maxplayers < 1 || maxplayers > TETRIS_MAXPLAYERS || buyin < 0 ) + return(-6); + if ( numvouts > 2*maxplayers+1 ) + { + for (i=0; i playerdata,uint256 playertxid,uint256 tokenid,std::string symbol,std::string pname,uint256 gametxid) +{ + int32_t i,vout,spentvini,numvouts,n=0; uint256 txid,spenttxid,hashBlock; struct tetris_player P; char packitemstr[512],*datastr=0; UniValue obj(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx; + memset(&P,0,sizeof(P)); + if ( playerdata.size() > 0 ) + { + datastr = (char *)malloc(playerdata.size()*2+1); + for (i=0; i= 0 ) + txid = spenttxid; + else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) + { + fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); + break; + } + txid = spenttxid; + vout = 0; + if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) + { + for (i=0; i TETRIS_MAXITERATIONS ) + break; + } + obj.push_back(Pair("gametxid",gametxid.GetHex())); + if ( txid != playertxid ) + obj.push_back(Pair("batontxid",txid.GetHex())); + obj.push_back(Pair("playertxid",playertxid.GetHex())); + if ( tokenid != zeroid ) + obj.push_back(Pair("tokenid",tokenid.GetHex())); + else obj.push_back(Pair("tokenid",playertxid.GetHex())); + if ( datastr != 0 ) + { + obj.push_back(Pair("data",datastr)); + free(datastr); + } + obj.push_back(Pair("pack",a)); + obj.push_back(Pair("packsize",(int64_t)P.packsize)); + obj.push_back(Pair("hitpoints",(int64_t)P.hitpoints)); + obj.push_back(Pair("strength",(int64_t)(P.strength&0xffff))); + obj.push_back(Pair("maxstrength",(int64_t)(P.strength>>16))); + obj.push_back(Pair("level",(int64_t)P.level)); + obj.push_back(Pair("experience",(int64_t)P.experience)); + obj.push_back(Pair("dungeonlevel",(int64_t)P.dungeonlevel)); + obj.push_back(Pair("chain",symbol)); + obj.push_back(Pair("pname",pname)); + return(obj); +} + +int32_t tetris_iterateplayer(uint256 ®istertxid,uint256 firsttxid,int32_t firstvout,uint256 lasttxid) // retrace playertxid vins to reach highlander <- this verifies player is valid and tetris_playerdataspend makes sure it can only be used once +{ + uint256 spenttxid,txid = firsttxid; int32_t spentvini,n,vout = firstvout; + registertxid = zeroid; + if ( vout < 0 ) + return(-1); + n = 0; + while ( (spentvini= myIsutxo_spent(spenttxid,txid,vout)) == 0 ) + { + txid = spenttxid; + vout = spentvini; + if ( registertxid == zeroid ) + registertxid = txid; + if ( ++n >= TETRIS_MAXITERATIONS ) + { + fprintf(stderr,"tetris_iterateplayer n.%d, seems something is wrong\n",n); + return(-2); + } + } + if ( txid == lasttxid ) + return(0); + else + { + fprintf(stderr,"firsttxid.%s/v%d -> %s != last.%s\n",firsttxid.ToString().c_str(),firstvout,txid.ToString().c_str(),lasttxid.ToString().c_str()); + return(-1); + } +} + +/* + playertxid is whoever owns the nonfungible satoshi and it might have been bought and sold many times. + highlander is the game winning tx with the player data and is the only place where the unique player data exists + origplayergame is the gametxid that ends up being won by the highlander and they are linked directly as the highlander tx spends gametxid.vout0 + */ + +int32_t tetris_playerdata(struct CCcontract_info *cp,uint256 &origplayergame,uint256 &tokenid,CPubKey &pk,std::vector &playerdata,std::string &symbol,std::string &pname,uint256 playertxid) +{ + uint256 origplayertxid,hashBlock,gametxid,registertxid; CTransaction gametx,playertx,highlandertx; std::vector vopret; uint8_t *script,e,f; int32_t i,regslot,gameheight,numvouts,maxplayers; int64_t buyin; + if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 && (numvouts= playertx.vout.size()) > 0 ) + { + if ( (f= tetris_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,playertx.vout[numvouts-1].scriptPubKey)) == 'H' || f == 'Q' ) + { + origplayergame = gametxid; + if ( tokenid != zeroid ) + { + playertxid = tokenid; + if ( myGetTransaction(playertxid,playertx,hashBlock) == 0 || (numvouts= playertx.vout.size()) <= 0 ) + { + fprintf(stderr,"couldnt get tokenid.%s\n",playertxid.GetHex().c_str()); + return(-2); + } + } + if ( tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 ) + { + //fprintf(stderr,"playertxid.%s got vin.%s/v%d gametxid.%s iterate.%d\n",playertxid.ToString().c_str(),playertx.vin[1].prevout.hash.ToString().c_str(),(int32_t)playertx.vin[1].prevout.n-maxplayers,gametxid.ToString().c_str(),tetris_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid)); + if ( (tokenid != zeroid || playertx.vin[1].prevout.hash == gametxid) && tetris_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid) == 0 ) + { + // if registertxid has vin from pk, it can be used + return(0); + } else fprintf(stderr,"hash mismatch or illegal gametxid\n"); + } else fprintf(stderr,"invalid game %s\n",gametxid.GetHex().c_str()); + } //else fprintf(stderr,"invalid player funcid.%c\n",f); + } else fprintf(stderr,"couldnt get playertxid.%s\n",playertxid.GetHex().c_str()); + return(-1); +} + +int32_t tetris_playerdataspend(CMutableTransaction &mtx,uint256 playertxid,int32_t vout,uint256 origplayergame) +{ + int64_t txfee = 10000; CTransaction tx; uint256 hashBlock; + if ( CCgettxout(playertxid,vout,1,0) == 1 ) // not sure if this is enough validation + { + mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); + return(0); + } + else + { + vout = 0; + if ( myGetTransaction(playertxid,tx,hashBlock) != 0 && tx.vout[vout].nValue == 1 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) + { + if ( CCgettxout(playertxid,vout,1,0) == 1 ) // not sure if this is enough validation + { + mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); + return(0); + } + } + return(-1); + } +} + +int32_t tetris_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) +{ + int32_t i,numvouts,spentvini,n,matches = 0; CPubKey pk; uint256 tid,active,spenttxid,tokenid,hashBlock,txid,origplayergame; CTransaction spenttx,matchtx,batontx; std::vector checkdata; CBlockIndex *pindex; char ccaddr[64],*keystrokes=0; + batonvalue = numkeys = numplayers = batonht = 0; + playertxid = batontxid = zeroid; + for (i=0; i= 0 ) + { + if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) + { + numplayers++; + Getscriptaddress(ccaddr,spenttx.vout[0].scriptPubKey); + if ( strcmp(destaddr,ccaddr) == 0 ) + { + matches++; + regslot = i; + matchtx = spenttx; + } //else fprintf(stderr,"%d+1 doesnt match %s vs %s\n",i,ccaddr,destaddr); + } //else fprintf(stderr,"%d+1 couldnt find spenttx.%s\n",i,spenttxid.GetHex().c_str()); + } //else fprintf(stderr,"%d+1 unspent\n",i); + } + if ( matches == 1 ) + { + numvouts = matchtx.vout.size(); + //fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); + if ( tetris_registeropretdecode(txid,tokenid,playertxid,matchtx.vout[numvouts-1].scriptPubKey) == 'R' )//&& txid == gametxid ) + { + //fprintf(stderr,"tokenid.%s txid.%s vs gametxid.%s player.%s\n",tokenid.GetHex().c_str(),txid.GetHex().c_str(),gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); + if ( tokenid != zeroid ) + active = tokenid; + else active = playertxid; + if ( active == zeroid || tetris_playerdata(cp,origplayergame,tid,pk,playerdata,symbol,pname,active) == 0 ) + { + txid = matchtx.GetHash(); + //fprintf(stderr,"scan forward active.%s spenttxid.%s\n",active.GetHex().c_str(),txid.GetHex().c_str()); + n = 0; + while ( CCgettxout(txid,0,1,0) < 0 ) + { + spenttxid = zeroid; + spentvini = -1; + if ( (spentvini= myIsutxo_spent(spenttxid,txid,0)) >= 0 ) + txid = spenttxid; + else + { + if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,0) == 0 || spenttxid == zeroid ) + { + fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); + return(-2); + } + } + txid = spenttxid; + //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); + if ( spentvini != 0 ) // game is over? + { + return(0); + } + if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) + { + uint256 g,b; CPubKey p; std::vector k; + if ( tetris_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) + { + keystrokes = (char *)realloc(keystrokes,numkeys + (int32_t)k.size()); + for (i=0; i= TETRIS_MAXITERATIONS ) + { + fprintf(stderr,"tetris_findbaton n.%d, seems something is wrong\n",n); + return(-5); + } + } + //fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); + batontxid = txid; + batonvout = 0; // not vini + // how to detect timeout, bailedout, highlander + hashBlock = zeroid; + if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 0 ) + { + if ( hashBlock == zeroid ) + batonht = komodo_nextheight(); + else if ( (pindex= komodo_blockindex(hashBlock)) == 0 ) + return(-4); + else batonht = pindex->GetHeight(); + batonvalue = batontx.vout[0].nValue; + //printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); + return(0); + } else fprintf(stderr,"couldnt find baton\n"); + } else fprintf(stderr,"error with playerdata\n"); + } else fprintf(stderr,"findbaton opret error\n"); + } + return(-1); +} + +int32_t tetris_playersalive(int32_t &openslots,int32_t &numplayers,uint256 gametxid,int32_t maxplayers,int32_t gameht,CTransaction gametx) +{ + int32_t i,n,vout,spentvini,registration_open = 0,alive = 0; CTransaction tx; uint256 txid,spenttxid,hashBlock; CBlockIndex *pindex; uint64_t txfee = 10000; + numplayers = openslots = 0; + if ( komodo_nextheight() <= gameht+TETRIS_MAXKEYSTROKESGAP ) + registration_open = 1; + for (i=0; i= 0 ) + txid = spenttxid; + else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) + { + fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); + break; + } + txid = spenttxid; + vout = 0; + //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); + if ( spentvini != 0 ) + break; + if ( n++ > TETRIS_MAXITERATIONS ) + break; + } + if ( txid != zeroid ) + { + if ( myGetTransaction(txid,tx,hashBlock) != 0 ) + { + if ( (pindex= komodo_blockindex(hashBlock)) != 0 ) + { + if ( pindex->GetHeight() <= gameht+TETRIS_MAXKEYSTROKESGAP ) + alive++; + } + } + } + } + } + else if ( registration_open != 0 ) + openslots++; + } + //fprintf(stderr,"numalive.%d openslots.%d\n",alive,openslots); + return(alive); +} + +uint64_t tetris_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mytetrisaddr) +{ + CBlockIndex *pindex; int32_t ht,openslots,delay,numplayers; uint256 hashBlock; uint64_t seed=0; char cmd[512]; CTransaction tx; + if ( myGetTransaction(gametxid,tx,hashBlock) != 0 && (pindex= komodo_blockindex(hashBlock)) != 0 ) + { + ht = pindex->GetHeight(); + delay = TETRIS_REGISTRATION * (maxplayers > 1); + obj.push_back(Pair("height",ht)); + obj.push_back(Pair("start",ht+delay)); + if ( komodo_nextheight() > ht+delay ) + { + if ( (pindex= komodo_chainactive(ht+delay)) != 0 ) + { + hashBlock = pindex->GetBlockHash(); + obj.push_back(Pair("starthash",hashBlock.ToString())); + memcpy(&seed,&hashBlock,sizeof(seed)); + seed &= (1LL << 62) - 1; + obj.push_back(Pair("seed",(int64_t)seed)); + if ( tetris_iamregistered(maxplayers,gametxid,tx,mytetrisaddr) > 0 ) + sprintf(cmd,"cc/tetris %llu %s",(long long)seed,gametxid.ToString().c_str()); + else sprintf(cmd,"./komodo-cli -ac_name=%s cclib register %d \"[%%22%s%%22]\"",ASSETCHAINS_SYMBOL,EVAL_TETRIS,gametxid.ToString().c_str()); + obj.push_back(Pair("run",cmd)); + } + } + obj.push_back(Pair("alive",tetris_playersalive(openslots,numplayers,gametxid,maxplayers,ht,tx))); + obj.push_back(Pair("openslots",openslots)); + obj.push_back(Pair("numplayers",numplayers)); + } + obj.push_back(Pair("maxplayers",maxplayers)); + obj.push_back(Pair("buyin",ValueFromAmount(buyin))); + return(seed); +} + +void tetris_gameplayerinfo(struct CCcontract_info *cp,UniValue &obj,uint256 gametxid,CTransaction gametx,int32_t vout,int32_t maxplayers,char *mytetrisaddr) +{ + // identify if bailout or quit or timed out + uint256 batontxid,spenttxid,gtxid,ptxid,tokenid,hashBlock,playertxid; CTransaction spenttx,batontx; int32_t numplayers,regslot,numkeys,batonvout,batonht,retval; int64_t batonvalue; std::vector playerdata; char destaddr[64]; std::string symbol,pname; + destaddr[0] = 0; + if ( myIsutxo_spent(spenttxid,gametxid,vout) >= 0 ) + { + if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) + Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey); + } + obj.push_back(Pair("slot",(int64_t)vout-1)); + if ( (retval= tetris_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,destaddr,numplayers,symbol,pname)) == 0 ) + { + if ( CCgettxout(gametxid,maxplayers+vout,1,0) == 10000 ) + { + if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 1 ) + { + if ( tetris_registeropretdecode(gtxid,tokenid,ptxid,batontx.vout[batontx.vout.size()-1].scriptPubKey) == 'R' && ptxid == playertxid && gtxid == gametxid ) + obj.push_back(Pair("status","registered")); + else obj.push_back(Pair("status","alive")); + } else obj.push_back(Pair("status","error")); + } else obj.push_back(Pair("status","finished")); + obj.push_back(Pair("baton",batontxid.ToString())); + obj.push_back(Pair("tokenid",tokenid.ToString())); + obj.push_back(Pair("batonaddr",destaddr)); + obj.push_back(Pair("ismine",strcmp(mytetrisaddr,destaddr)==0)); + obj.push_back(Pair("batonvout",(int64_t)batonvout)); + obj.push_back(Pair("batonvalue",ValueFromAmount(batonvalue))); + obj.push_back(Pair("batonht",(int64_t)batonht)); + if ( playerdata.size() > 0 ) + obj.push_back(Pair("player",tetris_playerobj(playerdata,playertxid,tokenid,symbol,pname,gametxid))); + } else fprintf(stderr,"findbaton err.%d\n",retval); +} + +int64_t tetris_registrationbaton(CMutableTransaction &mtx,uint256 gametxid,CTransaction gametx,int32_t maxplayers) +{ + int32_t vout,j,r; int64_t nValue; + if ( gametx.vout.size() > maxplayers+1 ) + { + r = rand() % maxplayers; + for (j=0; j 0 ) + { + result.push_back(Pair("hex",rawtx)); + if ( DecodeHexTx(tx,rawtx) != 0 ) + { + if ( broadcastflag != 0 && myAddtomempool(tx) != 0 ) + RelayTransaction(tx); + result.push_back(Pair("txid",tx.GetHash().ToString())); + result.push_back(Pair("result","success")); + } else result.push_back(Pair("error","decode hex")); + } else result.push_back(Pair("error","couldnt finalize CCtx")); + return(result); +} + +UniValue tetris_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey tetrispk,mypk; char *jsonstr; uint64_t inputsum,change,required,buyin=0; int32_t i,n,maxplayers = 1; + if ( txfee == 0 ) + txfee = 10000; + if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) + { + if ( n > 0 ) + { + maxplayers = juint(jitem(params,0),0); + if ( n > 1 ) + buyin = jdouble(jitem(params,1),0) * COIN + 0.0000000049; + } + } + if ( maxplayers < 1 || maxplayers > TETRIS_MAXPLAYERS ) + return(cclib_error(result,"illegal maxplayers")); + mypk = pubkey2pk(Mypubkey()); + tetrispk = GetUnspendable(cp,0); + tetris_univalue(result,"newgame",maxplayers,buyin); + required = (3*txfee + maxplayers*(TETRIS_REGISTRATIONSIZE+txfee)); + if ( (inputsum= AddCClibInputs(cp,mtx,tetrispk,required,16,cp->unspendableCCaddr)) >= required ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,tetrispk)); // for highlander TCBOO creation + for (i=0; ievalcode,TETRIS_REGISTRATIONSIZE,tetrispk,tetrispk)); + for (i=0; ievalcode,txfee,tetrispk,tetrispk)); + if ( (change= inputsum - required) >= txfee ) + mtx.vout.push_back(MakeCC1vout(cp->evalcode,change,tetrispk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,tetris_newgameopret(buyin,maxplayers)); + return(tetris_rawtxresult(result,rawtx,1)); + } + else return(cclib_error(result,"illegal maxplayers")); + return(result); +} + +UniValue tetris_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); std::vector playerdata; uint256 playertxid,tokenid,origplayergame;int32_t n; CPubKey pk; bits256 t; std::string symbol,pname; + result.push_back(Pair("result","success")); + tetris_univalue(result,"playerinfo",-1,-1); + if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) + { + if ( n > 0 ) + { + playertxid = juint256(jitem(params,0)); + if ( tetris_playerdata(cp,origplayergame,tokenid,pk,playerdata,symbol,pname,playertxid) < 0 ) + return(cclib_error(result,"invalid playerdata")); + result.push_back(Pair("player",tetris_playerobj(playerdata,playertxid,tokenid,symbol,pname,origplayergame))); + } else return(cclib_error(result,"no playertxid")); + return(result); + } else return(cclib_error(result,"couldnt reparse params")); +} + +UniValue tetris_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + // vin0 -> TETRIS_REGISTRATIONSIZE 1of2 registration baton from creategame + // vin1 -> optional nonfungible character vout @ + // vin2 -> original creation TCBOO playerdata used + // vin3+ -> buyin + // vout0 -> keystrokes/completion baton + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); char destaddr[64],coinaddr[64]; uint256 tokenid,gametxid,origplayergame,playertxid,hashBlock; int32_t err,maxplayers,gameheight,n,numvouts,vout=1; int64_t inputsum,buyin,CCchange=0; CPubKey pk,mypk,tetrispk,burnpk; CTransaction tx,playertx; std::vector playerdata; std::string rawtx,symbol,pname; bits256 t; + + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + burnpk = pubkey2pk(ParseHex(CC_BURNPUBKEY)); + tetrispk = GetUnspendable(cp,0); + tetris_univalue(result,"register",-1,-1); + playertxid = tokenid = zeroid; + if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) + { + if ( n > 0 ) + { + gametxid = juint256(jitem(params,0)); + if ( (err= tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1)) == 0 ) + { + if ( n > 1 ) + { + playertxid = juint256(jitem(params,1)); + if ( tetris_playerdata(cp,origplayergame,tokenid,pk,playerdata,symbol,pname,playertxid) < 0 ) + return(cclib_error(result,"couldnt extract valid playerdata")); + if ( tokenid != zeroid ) // if it is tokentransfer this will be 0 + vout = 1; + } + if ( komodo_nextheight() > gameheight + TETRIS_MAXKEYSTROKESGAP ) + return(cclib_error(result,"didnt register in time, TETRIS_MAXKEYSTROKESGAP")); + tetris_univalue(result,0,maxplayers,buyin); + GetCCaddress1of2(cp,coinaddr,tetrispk,mypk); + if ( tetris_iamregistered(maxplayers,gametxid,tx,coinaddr) > 0 ) + return(cclib_error(result,"already registered")); + if ( (inputsum= tetris_registrationbaton(mtx,gametxid,tx,maxplayers)) != TETRIS_REGISTRATIONSIZE ) + return(cclib_error(result,"couldnt find available registration baton")); + else if ( playertxid != zeroid && tetris_playerdataspend(mtx,playertxid,vout,origplayergame) < 0 ) + return(cclib_error(result,"couldnt find playerdata to spend")); + else if ( buyin > 0 && AddNormalinputs(mtx,mypk,buyin,64) < buyin ) + return(cclib_error(result,"couldnt find enough normal funds for buyin")); + if ( tokenid != zeroid ) + { + mtx.vin.push_back(CTxIn(tokenid,0)); // spending cc marker as token is burned + char unspendableTokenAddr[64]; uint8_t tokenpriv[32]; struct CCcontract_info *cpTokens, tokensC; + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + CPubKey unspPk = GetUnspendable(cpTokens, tokenpriv); + GetCCaddress(cpTokens, unspendableTokenAddr, unspPk); + CCaddr2set(cp, EVAL_TOKENS, unspPk, tokenpriv, unspendableTokenAddr); + } + mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,buyin + inputsum - txfee,tetrispk,mypk)); + GetCCaddress1of2(cp,destaddr,tetrispk,tetrispk); + CCaddr1of2set(cp,tetrispk,tetrispk,cp->CCpriv,destaddr); + mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode, 1, burnpk)); + + uint8_t e, funcid; uint256 tid; std::vector voutPubkeys, voutPubkeysEmpty; int32_t didtx = 0; + CScript opretRegister = tetris_registeropret(gametxid, playertxid); + if ( playertxid != zeroid ) + { + voutPubkeysEmpty.push_back(burnpk); + if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 ) + { + std::vector> oprets; + if ( (funcid= DecodeTokenOpRet(playertx.vout.back().scriptPubKey, e, tid, voutPubkeys, oprets)) != 0) + { // if token in the opret + didtx = 1; + if ( funcid == 'c' ) + tid = tokenid == zeroid ? playertxid : tokenid; + vscript_t vopretRegister; + GetOpReturnData(opretRegister, vopretRegister); + rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, + EncodeTokenOpRet(tid, voutPubkeysEmpty /*=never spent*/, std::make_pair(OPRETID_TETRISGAMEDATA, vopretRegister))); + } + } + } + if ( didtx == 0 ) + rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, opretRegister); + + return(tetris_rawtxresult(result,rawtx,1)); + } else return(cclib_error(result,"invalid gametxid")); + } else return(cclib_error(result,"no gametxid")); + } else return(cclib_error(result,"couldnt reparse params")); +} + +UniValue tetris_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + // vin0 -> baton from registration or previous keystrokes + // vout0 -> new baton + // opret -> user input chars + // being killed should auto broadcast (possible to be suppressed?) + // respawn to be prevented by including timestamps + int32_t nextheight = komodo_nextheight(); + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); + UniValue result(UniValue::VOBJ); CPubKey tetrispk,mypk; uint256 gametxid,playertxid,batontxid; int64_t batonvalue,buyin; std::vector keystrokes,playerdata; int32_t numplayers,regslot,numkeys,batonht,batonvout,n,elapsed,gameheight,maxplayers; CTransaction tx; CTxOut txout; char *keystrokestr,destaddr[64]; std::string rawtx,symbol,pname; bits256 t; uint8_t mypriv[32]; + if ( txfee == 0 ) + txfee = 10000; + tetris_univalue(result,"keystrokes",-1,-1); + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 2 && (keystrokestr= jstr(jitem(params,1),0)) != 0 ) + { + gametxid = juint256(jitem(params,0)); + result.push_back(Pair("gametxid",gametxid.GetHex())); + result.push_back(Pair("keystrokes",keystrokestr)); + keystrokes = ParseHex(keystrokestr); + mypk = pubkey2pk(Mypubkey()); + tetrispk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,destaddr,tetrispk,mypk); + if ( tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1) == 0 ) + { + if ( tetris_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,tx,maxplayers,destaddr,numplayers,symbol,pname) == 0 ) + { + result.push_back(Pair("batontxid",batontxid.GetHex())); + result.push_back(Pair("playertxid",playertxid.GetHex())); + if ( maxplayers == 1 || nextheight <= batonht+TETRIS_MAXKEYSTROKESGAP ) + { + mtx.vin.push_back(CTxIn(batontxid,batonvout,CScript())); //this validates user if pk + mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,batonvalue-txfee,tetrispk,mypk)); + Myprivkey(mypriv); + CCaddr1of2set(cp,tetrispk,mypk,mypriv,destaddr); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,tetris_keystrokesopret(gametxid,batontxid,mypk,keystrokes)); + //fprintf(stderr,"KEYSTROKES.(%s)\n",rawtx.c_str()); + return(tetris_rawtxresult(result,rawtx,1)); + } else return(cclib_error(result,"keystrokes tx was too late")); + } else return(cclib_error(result,"couldnt find batontxid")); + } else return(cclib_error(result,"invalid gametxid")); + } else return(cclib_error(result,"couldnt reparse params")); +} + +char *tetris_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *tetrisaddr) +{ + CPubKey tetrispk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct tetris_player P,endP; + tetrispk = GetUnspendable(cp,0); + *numkeysp = 0; + seed = 0; + num = numkeys = 0; + playertxid = zeroid; + str[0] = 0; + if ( (err= tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) + { + if ( (retval= tetris_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,tetrisaddr,numplayers,symbol,pname)) == 0 ) + { + UniValue obj; + seed = tetris_gamefields(obj,maxplayers,buyin,gametxid,tetrisaddr); + //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Tetris_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); + memset(&P,0,sizeof(P)); + if ( playerdata.size() > 0 ) + { + for (i=0; i no playerdata\n"); + newdata.resize(0); + *numkeysp = numkeys; + return(keystrokes); + /* P.gold = (P.gold * 8) / 10; + if ( keystrokes != 0 ) + { + free(keystrokes); + keystrokes = 0; + *numkeysp = 0; + return(keystrokes); + }*/ + } + else + { + sprintf(str,"$$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); + //fprintf(stderr,"%s\n",str); + *numkeysp = numkeys; + return(keystrokes); + } + } else num = 0; + } + else + { + fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p retval.%d\n",keystrokes,retval); + if ( keystrokes != 0 ) + free(keystrokes), keystrokes = 0; + } + } else fprintf(stderr,"extractgame: invalid game\n"); + //fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str()); + return(0); +} + +UniValue tetris_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); CPubKey pk,tetrispk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],tetrisaddr[64],*pubstr,*hexstr,*keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; + pk = pubkey2pk(Mypubkey()); + tetrispk = GetUnspendable(cp,0); + result.push_back(Pair("name","tetris")); + result.push_back(Pair("method","extract")); + tetrisaddr[0] = 0; + if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) + { + if ( n > 0 ) + { + gametxid = juint256(jitem(params,0)); + result.push_back(Pair("gametxid",gametxid.GetHex())); + if ( n == 2 ) + { + if ( (pubstr= jstr(jitem(params,1),0)) != 0 ) + { + if (strlen(pubstr) == 66 ) + { + decode_hex(pub33,33,pubstr); + pk = buf2pk(pub33); + } + else if ( strlen(pubstr) < 36 ) + strcpy(tetrisaddr,pubstr); + } + //fprintf(stderr,"gametxid.%s %s\n",gametxid.GetHex().c_str(),pubstr); + } + if ( tetrisaddr[0] == 0 ) + GetCCaddress1of2(cp,tetrisaddr,tetrispk,pk); + result.push_back(Pair("tetrisaddr",tetrisaddr)); + str[0] = 0; + if ( (keystrokes= tetris_extractgame(1,str,&numkeys,newdata,seed,playertxid,cp,gametxid,tetrisaddr)) != 0 ) + { + result.push_back(Pair("status","success")); + flag = 1; + hexstr = (char *)malloc(numkeys*2 + 1); + for (i=0; i playerdata,uint256 gametxid,CPubKey pk) +{ + static uint32_t good,bad; static uint256 prevgame; + char str[512],*keystrokes,tetrisaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed,mult = 10; CPubKey tetrispk; struct tetris_player P; + *cashoutp = 0; + tetrispk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,tetrisaddr,tetrispk,pk); + //fprintf(stderr,"call extractgame\n"); + if ( (keystrokes= tetris_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,tetrisaddr)) != 0 ) + { + //fprintf(stderr,"numkeys.%d tetris_extractgame %s\n",numkeys,gametxid.GetHex().c_str()); + free(keystrokes); + sprintf(fname,"tetris.%llu.pack",(long long)seed); + remove(fname); + + //fprintf(stderr,"extracted.(%s)\n",str); + for (i=0; i no playerdata, good.%d bad.%d\n",good,bad); + } + *cashoutp = 0; + return(0); + } + } + if ( gametxid != prevgame ) + { + prevgame = gametxid; + bad++; + fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); + fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,tetrisaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); + } + } + sprintf(fname,"tetris.%llu.pack",(long long)seed); + remove(fname); + //fprintf(stderr,"no keys tetris_extractgame %s\n",gametxid.GetHex().c_str()); + return(-1); +} + +UniValue tetris_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,char *method) +{ + //vin0 -> highlander vout from creategame TCBOO + //vin1 -> keystrokes baton of completed game, must be last to quit or first to win, only spent registration batons matter. If more than 60 blocks since last keystrokes, it is forfeit + //vins2+ -> rest of unspent registration utxo so all newgame vouts are spent + //vout0 -> nonfungible character with pack @ + //vout1 -> 1% ingame gold and all the buyins + + // detect if last to bailout + // vin0 -> kestrokes baton of completed game with Q + // vout0 -> playerdata marker + // vout0 -> 1% ingame gold + // get any playerdata, get all keystrokes, replay game and compare final state + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed,mult; int64_t buyin,batonvalue,inputsum,cashout,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char mytetrisaddr[64],*keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,tetrispk; uint8_t player[10000],mypriv[32],funcid; + struct CCcontract_info *cpTokens, tokensC; + + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + tetrispk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,mytetrisaddr,tetrispk,mypk); + result.push_back(Pair("name","tetris")); + result.push_back(Pair("method",method)); + result.push_back(Pair("mytetrisaddr",mytetrisaddr)); + if ( strcmp(method,"bailout") == 0 ) + { + funcid = 'Q'; + mult = 10; //100000; + } + else + { + funcid = 'H'; + mult = 20; //200000; + } + if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) + { + if ( n > 0 ) + { + gametxid = juint256(jitem(params,0)); + result.push_back(Pair("gametxid",gametxid.GetHex())); + if ( (err= tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,1)) == 0 ) + { + if ( tetris_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,mytetrisaddr,numplayers,symbol,pname) == 0 ) + { + UniValue obj; struct tetris_player P; + seed = tetris_gamefields(obj,maxplayers,buyin,gametxid,mytetrisaddr); + fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d\n",pname.size()!=0?pname.c_str():Tetris_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size()); + memset(&P,0,sizeof(P)); + if ( playerdata.size() > 0 ) + { + for (i=0; i 0 ) + { + newdata.resize(num); + for (i=0; i no playerdata\n"); + newdata.resize(0); + //P.gold = (P.gold * 8) / 10; + } + else + { + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated + mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); + if ( P.amulet != 0 ) + mult *= 5; + dungeonlevel = P.dungeonlevel; + if ( P.amulet != 0 && dungeonlevel < 21 ) + dungeonlevel = 21; + cashout = (uint64_t)P.gold * P.gold * mult * dungeonlevel; + fprintf(stderr,"\nextracted $$$gold.%d -> %.8f TETRIS hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,(double)cashout/COIN,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); + if ( funcid == 'H' && maxplayers > 1 ) + { + if ( P.amulet == 0 ) + { + if ( numplayers != maxplayers ) + return(cclib_error(result,"numplayers != maxplayers")); + else if ( tetris_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) + return(cclib_error(result,"highlander must be a winner or last one standing")); + } + cashout += numplayers * buyin; + } + if ( cashout >= txfee ) + { + if ( (inputsum= AddCClibInputs(cp,mtx,tetrispk,cashout,16,cp->unspendableCCaddr)) > (uint64_t)P.gold*mult ) + CCchange = (inputsum - cashout); + mtx.vout.push_back(CTxOut(cashout,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + } + } + } + mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange + (batonvalue-3*txfee),tetrispk)); + Myprivkey(mypriv); + CCaddr1of2set(cp,tetrispk,mypk,mypriv,mytetrisaddr); + CScript opret; + if ( pname.size() == 0 ) + pname = Tetris_pname; + if ( newdata.size() == 0 ) + { + opret = tetris_highlanderopret(funcid, gametxid, regslot, mypk, nodata,pname); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,opret); + //fprintf(stderr,"nodata finalizetx.(%s)\n",rawtx.c_str()); + } + else + { + opret = tetris_highlanderopret(funcid, gametxid, regslot, mypk, newdata,pname); + char seedstr[32]; + sprintf(seedstr,"%llu",(long long)seed); + std::vector vopretNonfungible; + GetOpReturnData(opret, vopretNonfungible); + rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeTokenCreateOpRet('c', Mypubkey(), std::string(seedstr), gametxid.GetHex(), vopretNonfungible)); + } + return(tetris_rawtxresult(result,rawtx,1)); + } + result.push_back(Pair("result","success")); + } else fprintf(stderr,"illegal game err.%d\n",err); + } else fprintf(stderr,"parameters only n.%d\n",n); + } + return(result); +} + +UniValue tetris_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + return(tetris_finishgame(txfee,cp,params,"bailout")); +} + +UniValue tetris_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + return(tetris_finishgame(txfee,cp,params,"highlander")); +} + +UniValue tetris_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i,n,gameheight,maxplayers,numvouts; uint256 txid; CTransaction tx; int64_t buyin; uint64_t seed; bits256 t; char mytetrisaddr[64],str[64]; CPubKey mypk,tetrispk; + result.push_back(Pair("name","tetris")); + result.push_back(Pair("method","gameinfo")); + if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) + { + if ( n > 0 ) + { + txid = juint256(jitem(params,0)); + result.push_back(Pair("gametxid",txid.GetHex())); + if ( tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,0) == 0 ) + { + result.push_back(Pair("result","success")); + result.push_back(Pair("gameheight",(int64_t)gameheight)); + mypk = pubkey2pk(Mypubkey()); + tetrispk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,mytetrisaddr,tetrispk,mypk); + //fprintf(stderr,"mytetrisaddr.%s\n",mytetrisaddr); + seed = tetris_gamefields(result,maxplayers,buyin,txid,mytetrisaddr); + result.push_back(Pair("seed",(int64_t)seed)); + for (i=0; i > unspentOutputs; + tetrispk = GetUnspendable(cp,0); + GetCCaddress(cp,coinaddr,tetrispk); + SetCCunspents(unspentOutputs,coinaddr); + nextheight = komodo_nextheight(); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); + if ( it->second.satoshis != txfee || vout != 0 ) // reject any that are not highlander markers + continue; + if ( tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,1) == 0 && nextheight <= gameheight+TETRIS_MAXKEYSTROKESGAP ) + { + tetris_playersalive(openslots,numplayers,txid,maxplayers,gameheight,tx); + if ( openslots > 0 ) + a.push_back(txid.GetHex()); + } + } + result.push_back(Pair("result","success")); + tetris_univalue(result,"pending",-1,-1); + result.push_back(Pair("pending",a)); + result.push_back(Pair("numpending",(int64_t)a.size())); + return(result); +} + +UniValue tetris_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ),a(UniValue::VARR); int64_t buyin; uint256 tokenid,gametxid,txid,hashBlock; CTransaction playertx,tx; int32_t maxplayers,vout,numvouts; std::vector playerdata; CPubKey tetrispk,mypk,pk; std::string symbol,pname; char coinaddr[64]; + std::vector > unspentOutputs; + tetrispk = GetUnspendable(cp,0); + mypk = pubkey2pk(Mypubkey()); + GetTokensCCaddress(cp,coinaddr,mypk); + SetCCunspents(unspentOutputs,coinaddr); + tetris_univalue(result,"players",-1,-1); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); + if ( it->second.satoshis != 1 || vout > 1 ) + continue; + if ( tetris_playerdata(cp,gametxid,tokenid,pk,playerdata,symbol,pname,txid) == 0 )//&& pk == mypk ) + { + a.push_back(txid.GetHex()); + //a.push_back(Pair("playerdata",tetris_playerobj(playerdata))); + } + } + result.push_back(Pair("playerdata",a)); + result.push_back(Pair("numplayerdata",(int64_t)a.size())); + return(result); +} + +UniValue tetris_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ),a(UniValue::VARR),b(UniValue::VARR); uint256 txid,hashBlock,gametxid,tokenid,playertxid; int32_t vout,maxplayers,gameheight,numvouts; CPubKey tetrispk,mypk; char coinaddr[64]; CTransaction tx,gametx; int64_t buyin; + std::vector > addressIndex; + //std::vector > unspentOutputs; + tetrispk = GetUnspendable(cp,0); + mypk = pubkey2pk(Mypubkey()); + GetCCaddress1of2(cp,coinaddr,tetrispk,mypk); + //SetCCunspents(unspentOutputs,coinaddr); + SetCCtxids(addressIndex,coinaddr); + tetris_univalue(result,"games",-1,-1); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + //for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); + if ( vout == 0 ) + { + if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) + { + if ( tetris_registeropretdecode(gametxid,tokenid,playertxid,tx.vout[numvouts-1].scriptPubKey) == 'R' ) + { + if ( tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 ) + { + if ( CCgettxout(txid,vout,1,0) < 0 ) + b.push_back(gametxid.GetHex()); + else a.push_back(gametxid.GetHex()); + } + } + } + } + } + result.push_back(Pair("pastgames",b)); + result.push_back(Pair("games",a)); + result.push_back(Pair("numgames",(int64_t)(a.size()+b.size()))); + return(result); +} + +UniValue tetris_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); int32_t n; char *namestr = 0; + tetris_univalue(result,"setname",-1,-1); + if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) + { + if ( n > 0 ) + { + if ( (namestr= jstri(params,0)) != 0 ) + { + result.push_back(Pair("result","success")); + result.push_back(Pair("pname",namestr)); + tetris_pname = namestr; + return(result); + } + } + } + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt get name")); + return(result); +} + +bool tetris_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) +{ + CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid,tokentx=0; int32_t i,maxplayers,enabled = 0,decoded=0,regslot,ind,err,dispflag,gameheight,score,numvouts; CTransaction vintx,gametx; CPubKey pk; uint256 hashBlock,gametxid,txid,tokenid,batontxid,playertxid,ptxid; int64_t buyin,cashout; std::vector playerdata,keystrokes; std::string symbol,pname; + if ( strcmp(ASSETCHAINS_SYMBOL,"ROGUE") == 0 ) + { + if (height < 21274 ) + return(true); + else if ( height > 50000 ) + enabled = 1; + } else enabled = 1; + if ( (numvouts= tx.vout.size()) > 1 ) + { + txid = tx.GetHash(); + scriptPubKey = tx.vout[numvouts-1].scriptPubKey; + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() > 2 ) + { + script = (uint8_t *)vopret.data(); + funcid = script[1]; + if ( (e= script[0]) == EVAL_TOKENS ) + { + tokentx = funcid; + if ( (funcid= tetris_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) == 0 ) + { + if ( (funcid= tetris_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) == 0 ) + { + fprintf(stderr,"ht.%d couldnt decode tokens opret (%c)\n",height,script[1]); + } else e = EVAL_TETRIS, decoded = 1; + } else e = EVAL_TETRIS, decoded = 1; + } + if ( e == EVAL_TETRIS ) + { + //fprintf(stderr,"ht.%d tetris.(%c)\n",height,script[1]); + if ( decoded == 0 ) + { + switch ( funcid ) + { + case 'G': // seems just need to make sure no vout abuse is left to do + gametx = tx; + gametxid = tx.GetHash(); + gameheight = height; + if ( (err= tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,zeroid,0)) != 0 ) + { + fprintf(stderr,"height.%d %s tetris_isvalidgame error.%d\n",height,gametxid.GetHex().c_str(),err); + return eval->Invalid("invalid gametxid"); + } + //fprintf(stderr,"height.%d %s tetris_isvalidgame\n",height,gametxid.GetHex().c_str()); + return(true); + break; + case 'R': + if ( (funcid= tetris_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) != 'R' ) + { + return eval->Invalid("couldnt decode register opret"); + } + // baton is created + // validation is done below + break; + case 'K': + if ( (funcid= tetris_keystrokesopretdecode(gametxid,batontxid,pk,keystrokes,scriptPubKey)) != 'K' ) + { + return eval->Invalid("couldnt decode keystrokes opret"); + } + // spending the baton proves it is the user if the pk is the signer + return(true); + break; + case 'H': case 'Q': + // done in the next switch statement as there are some H/Q tx with playerdata which would skip this section + break; + default: + return eval->Invalid("illegal tetris non-decoded funcid"); + break; + } + } + switch ( funcid ) + { + case 'R': // register + // verify vout amounts are as they should be and no vins that shouldnt be + return(true); + case 'H': // win + case 'Q': // bailout + if ( (f= tetris_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) != funcid ) + { + //fprintf(stderr,"height.%d couldnt decode H/Q opret\n",height); + //if ( height > 20000 ) + return eval->Invalid("couldnt decode H/Q opret"); + } + // verify pk belongs to this tx + if ( tokentx == 'c' && playerdata.size() > 0 ) + { + static char laststr[512]; char cashstr[512]; + if ( tetris_playerdata_validate(&cashout,ptxid,cp,playerdata,gametxid,pk) < 0 ) + { + sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d gametxid.%s player.%s invalid playerdata[%d]\n",tokentx,decoded,height,gametxid.GetHex().c_str(),ptxid.GetHex().c_str(),(int32_t)playerdata.size()); + if ( strcmp(laststr,cashstr) != 0 ) + { + strcpy(laststr,cashstr); + fprintf(stderr,"%s\n",cashstr); + } + if ( enabled != 0 ) + return eval->Invalid("mismatched playerdata"); + } + if ( funcid == 'H' ) + cashout *= 2; + sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d txid.%s %.8f vs vout2 %.8f",tokentx,decoded,height,txid.GetHex().c_str(),(double)cashout/COIN,(double)tx.vout[2].nValue/COIN); + if ( strcmp(laststr,cashstr) != 0 ) + { + strcpy(laststr,cashstr); + fprintf(stderr,"%s\n",cashstr); + } + if ( enabled != 0 && tx.vout[2].nValue != cashout ) + return eval->Invalid("mismatched cashout amount"); + } + if ( funcid == 'Q' ) + { + // verify vin/vout + } + else // 'H' + { + // verify vin/vout and proper payouts + } + return(true); + break; + default: + return eval->Invalid("illegal tetris funcid"); + break; + } + } else return eval->Invalid("illegal evalcode"); + } else return eval->Invalid("opret too small"); + } else return eval->Invalid("not enough vouts"); + return(true); +} +#endif + diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a47c7fea3..6bfcc0e5c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -289,15 +289,22 @@ void *chainparams_commandline(void *ptr) mainParams.pchMessageStart[2] = (ASSETCHAINS_MAGIC >> 16) & 0xff; mainParams.pchMessageStart[3] = (ASSETCHAINS_MAGIC >> 24) & 0xff; fprintf(stderr,">>>>>>>>>> %s: p2p.%u rpc.%u magic.%08x %u %u coins\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_MAGIC,ASSETCHAINS_MAGIC,(uint32_t)ASSETCHAINS_SUPPLY); - - if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH) + if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH) { // this is only good for 60 second blocks with an averaging window of 45. for other parameters, use: - // nLwmaAjustedWeight = (N+1)/2 * (0.9989^(500/nPowAveragingWindow)) * nPowTargetSpacing + // nLwmaAjustedWeight = (N+1)/2 * (0.9989^(500/nPowAveragingWindow)) * nPowTargetSpacing mainParams.consensus.nLwmaAjustedWeight = 1350; mainParams.consensus.nPowAveragingWindow = 45; mainParams.consensus.powAlternate = uint256S("00000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); } + else if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASHV1_1) + { + // this is only good for 60 second blocks with an averaging window of 45. for other parameters, use: + // nLwmaAjustedWeight = (N+1)/2 * (0.9989^(500/nPowAveragingWindow)) * nPowTargetSpacing + mainParams.consensus.nLwmaAjustedWeight = 1350; + mainParams.consensus.nPowAveragingWindow = 45; + mainParams.consensus.powAlternate = uint256S("0000000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); + } if (ASSETCHAINS_LWMAPOS != 0) { @@ -668,7 +675,7 @@ public: BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); nEquihashN = N; nEquihashK = K; - + genesis = CreateGenesisBlock( 1296688602, uint256S("0x0000000000000000000000000000000000000000000000000000000000000009"), diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 4f004aac2..663e2e937 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -20,6 +20,7 @@ #include "clientversion.h" #include "tinyformat.h" +#include "util.h" #include @@ -34,7 +35,7 @@ * for both bitcoind and bitcoin-core, to make it harder for attackers to * target servers or GUI users specifically. */ -const std::string CLIENT_NAME("MagicBean"); +const std::string CLIENT_NAME = GetArg("-ac_clientname", "MagicBean"); /** * Client version number diff --git a/src/coins.h b/src/coins.h index f83fda7d2..e0ea7d822 100644 --- a/src/coins.h +++ b/src/coins.h @@ -446,7 +446,7 @@ class CCoinsViewCache; /** * A reference to a mutable cache entry. Encapsulating it allows us to run * cleanup code after the modification is finished, and keeping track of - * concurrent modifications. + * concurrent modifications. */ class CCoinsModifier { @@ -503,7 +503,7 @@ protected: /** * Make mutable so that we can "fill the cache" even from Get-methods - * declared as "const". + * declared as "const". */ mutable uint256 hashBlock; mutable CCoinsMap cacheCoins; diff --git a/src/crosschain.cpp b/src/crosschain.cpp index 8b6cb12a4..d65c5dd8c 100644 --- a/src/crosschain.cpp +++ b/src/crosschain.cpp @@ -66,7 +66,7 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh int seenOwnNotarisations = 0; - bool txscl = IsTXSCL(symbol); + int authority = GetSymbolAuthority(symbol); for (int i=0; i kmdHeight) break; @@ -90,13 +90,20 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh if (seenOwnNotarisations == 1) { BOOST_FOREACH(Notarisation& nota, notarisations) { - if (IsTXSCL(nota.second.symbol) == txscl) - if (nota.second.ccId == targetCCid) - moms.push_back(nota.second.MoM); + if (GetSymbolAuthority(nota.second.symbol) == authority) + if (nota.second.ccId == targetCCid) { + moms.push_back(nota.second.MoM); + //fprintf(stderr, "added mom: %s\n",nota.second.MoM.GetHex().data()); + } } } } + // Not enough own notarisations found to return determinate MoMoM + destNotarisationTxid = uint256(); + moms.clear(); + return uint256(); + end: return GetMerkleRoot(moms); } diff --git a/src/crosschain.h b/src/crosschain.h index b97afde98..b3d1af9b2 100644 --- a/src/crosschain.h +++ b/src/crosschain.h @@ -18,6 +18,18 @@ #include "cc/eval.h" +const int CROSSCHAIN_KOMODO = 1; +const int CROSSCHAIN_TXSCL = 2; +const int CROSSCHAIN_STAKED = 3; + +typedef struct CrosschainAuthority { + uint8_t notaries[64][33]; + int8_t size; + int8_t requiredSigs; +} CrosschainAuthority; + +int GetSymbolAuthority(const char* symbol); +bool CheckTxAuthority(const CTransaction &tx, CrosschainAuthority auth); /* On assetchain */ TxProof GetAssetchainProof(uint256 hash,CTransaction burnTx); diff --git a/src/crosschain_authority.cpp b/src/crosschain_authority.cpp new file mode 100644 index 000000000..7487e4879 --- /dev/null +++ b/src/crosschain_authority.cpp @@ -0,0 +1,70 @@ +#include "cc/eval.h" +#include "crosschain.h" +#include "notarisationdb.h" +#include "notaries_staked.h" + +int GetSymbolAuthority(const char* symbol) +{ + if (strncmp(symbol, "TXSCL", 5) == 0) + return CROSSCHAIN_TXSCL; + if (is_STAKED(symbol) != 0) { + //printf("RETURNED CROSSCHAIN STAKED AS TRUE\n"); + return CROSSCHAIN_STAKED; + } + //printf("RETURNED CROSSCHAIN KOMODO AS TRUE\n"); + return CROSSCHAIN_KOMODO; +} + + +bool CheckTxAuthority(const CTransaction &tx, CrosschainAuthority auth) +{ + EvalRef eval; + + if (tx.vin.size() < auth.requiredSigs) return false; + + uint8_t seen[64] = {0}; + + BOOST_FOREACH(const CTxIn &txIn, tx.vin) + { + // Get notary pubkey + CTransaction tx; + uint256 hashBlock; + if (!eval->GetTxUnconfirmed(txIn.prevout.hash, tx, hashBlock)) return false; + if (tx.vout.size() < txIn.prevout.n) return false; + CScript spk = tx.vout[txIn.prevout.n].scriptPubKey; + if (spk.size() != 35) return false; + const unsigned char *pk = &spk[0]; + if (pk++[0] != 33) return false; + if (pk[33] != OP_CHECKSIG) return false; + + // Check it's a notary + for (int i=0; i payouts, uint32_t nExpiryHeightOverride) { std::vector payload = E_MARSHAL(ss << EVAL_IMPORTCOIN); - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + if (mtx.fOverwintered) + mtx.nExpiryHeight = 0; mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), CScript() << payload)); mtx.vout = payouts; auto importData = E_MARSHAL(ss << proof; ss << burnTx); @@ -70,20 +72,10 @@ bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint std::vector burnOpret; uint32_t ccid = 0; if (burnTx.vout.size() == 0) return false; GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); - E_UNMARSHAL(burnOpret, ss >> VARINT(ccid)); - /*if ( ccid != 0xffffffff ) - { - return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid); - ss >> targetSymbol; - ss >> payoutsHash); - } - else*/ - { - return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid); - ss >> targetSymbol; - ss >> payoutsHash; - ss >> rawproof); - } + return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid); + ss >> targetSymbol; + ss >> payoutsHash; + ss >> rawproof); } @@ -111,7 +103,7 @@ bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& che auto pc = scriptSig.begin(); opcodetype opcode; std::vector evalScript; - + auto f = [&] () { if (!scriptSig.GetOp(pc, opcode, evalScript)) return false; diff --git a/src/init.cpp b/src/init.cpp index 3dd09ac50..d2546347d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -562,6 +562,37 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-metricsui", _("Set to 1 for a persistent metrics screen, 0 for sequential metrics output (default: 1 if running in a console, 0 otherwise)")); strUsage += HelpMessageOpt("-metricsrefreshtime", strprintf(_("Number of seconds between metrics refreshes (default: %u if running in a console, %u otherwise)"), 1, 600)); } + strUsage += HelpMessageGroup(_("Komodo Asset Chain options:")); + strUsage += HelpMessageOpt("-ac_algo", _("Choose PoW mining algorithm, default is Equihash")); + strUsage += HelpMessageOpt("-ac_blocktime", _("Block time in seconds, default is 60")); + strUsage += HelpMessageOpt("-ac_cc", _("Cryptoconditions, default 0")); + strUsage += HelpMessageOpt("-ac_beam", _("BEAM integration")); + strUsage += HelpMessageOpt("-ac_coda", _("CODA integration")); + strUsage += HelpMessageOpt("-ac_cclib", _("Cryptoconditions dynamicly loadable library")); + strUsage += HelpMessageOpt("-ac_ccenable", _("Cryptoconditions to enable")); + strUsage += HelpMessageOpt("-ac_ccactivate", _("Block height to enable Cryptoconditions")); + strUsage += HelpMessageOpt("-ac_clientname", _("Full node client name, default 'MagicBean'")); + strUsage += HelpMessageOpt("-ac_decay", _("Percentage of block reward decrease at each halving")); + strUsage += HelpMessageOpt("-ac_end", _("Block height at which block rewards will end")); + strUsage += HelpMessageOpt("-ac_eras", _("Block reward eras")); + strUsage += HelpMessageOpt("-ac_founders", _("Number of blocks between founders reward payouts")); + strUsage += HelpMessageOpt("-ac_halving", _("Number of blocks between each block reward halving")); + strUsage += HelpMessageOpt("-ac_name", _("Name of asset chain")); + strUsage += HelpMessageOpt("-ac_notarypay", _("Pay notaries, default 0")); + strUsage += HelpMessageOpt("-ac_perc", _("Percentage of block rewards paid to the founder")); + strUsage += HelpMessageOpt("-ac_private", _("Shielded transactions only (except coinbase + notaries), default is 0")); + strUsage += HelpMessageOpt("-ac_pubkey", _("Public key for receiving payments on the network")); + strUsage += HelpMessageOpt("-ac_public", _("Transparent transactions only, default 0")); + strUsage += HelpMessageOpt("-ac_reward", _("Block reward in satoshis, default is 0")); + strUsage += HelpMessageOpt("-ac_sapling", _("Sapling activation block height")); + strUsage += HelpMessageOpt("-ac_script", _("P2SH/multisig address to receive founders rewards")); + strUsage += HelpMessageOpt("-ac_staked", _("Percentage of blocks that are Proof-Of-Stake, default 0")); + strUsage += HelpMessageOpt("-ac_supply", _("Starting supply, default is 0")); + strUsage += HelpMessageOpt("-ac_timelockfrom", _("Timelocked coinbase start height")); + strUsage += HelpMessageOpt("-ac_timelockgte", _("Timelocked coinbase minimum amount to be locked")); + strUsage += HelpMessageOpt("-ac_timelockto", _("Timelocked coinbase stop height")); + strUsage += HelpMessageOpt("-ac_txpow", _("Enforce transaction-rate limit, default 0")); + strUsage += HelpMessageOpt("-ac_veruspos", _("Use Verus Proof-Of-Stake (-ac_veruspos=50) default 0")); return strUsage; } @@ -1177,7 +1208,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) globalVerifyHandle.reset(new ECCVerifyHandle()); // set the hash algorithm to use for this chain - extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH; + // Again likely better solution here, than using long IF ELSE. + extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH, ASSETCHAINS_VERUSHASHV1_1; CVerusHash::init(); CVerusHashV2::init(); if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH) @@ -1185,6 +1217,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // initialize VerusHash CBlockHeader::SetVerusHash(); } + else if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASHV1_1) + { + // initialize VerusHashV2 + CBlockHeader::SetVerusHashV2(); + } // Sanity check if (!InitSanityCheck()) @@ -1548,6 +1585,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (fReindex) { + boost::filesystem::remove(GetDataDir() / "komodostate"); + boost::filesystem::remove(GetDataDir() / "signedmasks"); pblocktree->WriteReindexing(true); //If we're reindexing in prune mode, wipe away unusable block files and all undo data files if (fPruneMode) diff --git a/src/komodo.h b/src/komodo.h index d3cda4e22..791adba33 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -16,6 +16,7 @@ #ifndef H_KOMODO_H #define H_KOMODO_H #include "komodo_defs.h" +#include "notaries_staked.h" #ifdef _WIN32 #define printf(...) @@ -26,6 +27,8 @@ #define KOMODO_ASSETCHAINS_WAITNOTARIZE #define KOMODO_PAXMAX (10000 * COIN) +extern int32_t NOTARIZED_HEIGHT; +uint256 NOTARIZED_HASH,NOTARIZED_DESTTXID; #include #include @@ -36,7 +39,8 @@ int32_t gettxout_scriptPubKey(uint8_t *scriptPubkey,int32_t maxsize,uint256 txid,int32_t n); void komodo_event_rewind(struct komodo_state *sp,char *symbol,int32_t height); -void komodo_connectblock(CBlockIndex *pindex,CBlock& block); +int32_t komodo_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block); +bool check_pprevnotarizedht(); #include "komodo_structs.h" #include "komodo_globals.h" @@ -530,7 +534,7 @@ int32_t komodo_validate_chain(uint256 srchash,int32_t notarized_height) } else return(1); } -int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scriptbuf,int32_t scriptlen,int32_t height,uint256 txhash,int32_t i,int32_t j,uint64_t *voutmaskp,int32_t *specialtxp,int32_t *notarizedheightp,uint64_t value,int32_t notarized,uint64_t signedmask,uint32_t timestamp) +int32_t komodo_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notaryid,uint8_t *scriptbuf,int32_t scriptlen,int32_t height,uint256 txhash,int32_t i,int32_t j,uint64_t *voutmaskp,int32_t *specialtxp,int32_t *notarizedheightp,uint64_t value,int32_t notarized,uint64_t signedmask,uint32_t timestamp) { static uint256 zero; static FILE *signedfp; int32_t opretlen,nid,offset,k,MoMdepth,matched,len = 0; uint256 MoM,srchash,desttxid; uint8_t crypto777[33]; struct komodo_state *sp; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; @@ -615,7 +619,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr if ( j == 1 && opretlen >= len+offset-opoffset ) { memset(&MoMoMdata,0,sizeof(MoMoMdata)); - if ( matched == 0 && bitweight(signedmask) >= KOMODO_MINRATIFY ) + if ( matched == 0 && signedmask != 0 && bitweight(signedmask) >= KOMODO_MINRATIFY ) notarized = 1; if ( strcmp("PIZZA",ccdata.symbol) == 0 || strncmp("TXSCL",ccdata.symbol,5) == 0 ) notarized = 1; @@ -628,6 +632,9 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr if ( matched != 0 ) validated = komodo_validate_chain(srchash,*notarizedheightp); else validated = 1; + // Any notarization that is matched and has a decodable op_return is enough to pay notaries. Otherwise bugs! + if ( fJustCheck && matched != 0 ) + return(-2); if ( notarized != 0 && validated != 0 ) { //sp->NOTARIZED_HEIGHT = *notarizedheightp; @@ -684,7 +691,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr else { komodo_rwccdata(ASSETCHAINS_SYMBOL,1,&ccdata,&MoMoMdata); - if ( matched != 0 ) + if ( !fJustCheck && matched != 0 ) printf("[%s] matched.%d VALID (%s) MoM.%s [%d] CCid.%u\n",ASSETCHAINS_SYMBOL,matched,ccdata.symbol,MoM.ToString().c_str(),MoMdepth&0xffff,(MoMdepth>>16)&0xffff); } if ( MoMoMdata.pairs != 0 ) @@ -694,6 +701,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr } else if ( ASSETCHAINS_SYMBOL[0] == 0 && matched != 0 && notarized != 0 && validated != 0 ) komodo_rwccdata((char *)"KMD",1,&ccdata,0); + if ( matched != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height ) { sp->NOTARIZED_HEIGHT = *notarizedheightp; @@ -706,11 +714,8 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr } 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 ) - printf("[%s] ht.%d NOTARIZED.%d %s.%s %sTXID.%s lens.(%d %d) MoM.%s %d\n",ASSETCHAINS_SYMBOL,height,*notarizedheightp,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 ( 0 && RemoveOrphanedBlocks(*notarizedheightp)) - { - //fprintf(stderr, "Sucessfully removed all known orphaned blocks before height %d\n",*notarizedheightp); - } + 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 ) @@ -735,13 +740,14 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen-len+4+3+(scriptbuf[1] == 0x4d),j,zero,0); } } - } + } //else if ( fJustCheck ) + // return (-3); // if the notarisation is only invalid because its out of order it cannot be mined in a block with a valid one! } else if ( opretlen != 149 && height > 600000 && matched != 0 ) printf("%s validated.%d notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s len.%d opretlen.%d\n",ccdata.symbol,validated,notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,srchash.ToString().c_str(),desttxid.ToString().c_str(),len,opretlen); } else if ( matched != 0 && i == 0 && j == 1 && opretlen == 149 ) { - if ( notaryid >= 0 && notaryid < 64 ) + if ( !fJustCheck && notaryid >= 0 && notaryid < 64 ) komodo_paxpricefeed(height,&scriptbuf[len],opretlen); } else if ( matched != 0 ) @@ -760,7 +766,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr printf("ISRATIFICATION (%s)\n",(char *)&scriptbuf[len+32*2+4]); } } - + if ( *isratificationp == 0 && (signedmask != 0 || (scriptbuf[len] != 'X' && scriptbuf[len] != 'A')) ) // && scriptbuf[len] != 'I') komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen,j,zero,0); } @@ -797,16 +803,19 @@ int32_t komodo_notarycmp(uint8_t *scriptPubKey,int32_t scriptlen,uint8_t pubkeys return(-1); } -void komodo_connectblock(CBlockIndex *pindex,CBlock& block) +// int32_t ! +int32_t komodo_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block) { static int32_t hwmheight; + int32_t staked_era; static int32_t lastStakedEra; + std::vector notarisations; uint64_t signedmask,voutmask; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; uint8_t scriptbuf[10001],pubkeys[64][33],rmd160[20],scriptPubKey[35]; uint256 zero,btctxid,txhash; int32_t i,j,k,numnotaries,notarized,scriptlen,isratification,nid,numvalid,specialtx,notarizedheight,notaryid,len,numvouts,numvins,height,txn_count; if ( pindex == 0 ) { fprintf(stderr,"komodo_connectblock null pindex\n"); - return; + return(0); } memset(&zero,0,sizeof(zero)); komodo_init(pindex->GetHeight()); @@ -814,9 +823,32 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) if ( (sp= komodo_stateptr(symbol,dest)) == 0 ) { fprintf(stderr,"unexpected null komodostateptr.[%s]\n",ASSETCHAINS_SYMBOL); - return; + return(0); + } + //fprintf(stderr,"%s connect.%d\n",ASSETCHAINS_SYMBOL,pindex->nHeight); + // Wallet Filter. Disabled here. Cant be activated by notaries or pools with some changes. + if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 || IS_STAKED_NOTARY > -1 ) + { + staked_era = STAKED_era(pindex->GetBlockTime()); + if ( !fJustCheck && staked_era != lastStakedEra ) + { + uint8_t tmp_pubkeys[64][33]; + int8_t numSN = numStakedNotaries(tmp_pubkeys,staked_era); + UpdateNotaryAddrs(tmp_pubkeys,numSN); + STAKED_ERA = staked_era; + if ( NOTARYADDRS[0][0] != 0 && NOTARY_PUBKEY33[0] != 0 ) + { + if ( (IS_STAKED_NOTARY= updateStakedNotary()) > -1 ) + { + IS_KOMODO_NOTARY = 0; + if ( MIN_RECV_SATS == -1 ) + MIN_RECV_SATS = 100000000; + fprintf(stderr, "Staked Notary Protection Active! NotaryID.%d RADD.%s ERA.%d MIN_TX_VALUE.%lu \n",IS_STAKED_NOTARY,NOTARY_ADDRESS.c_str(),staked_era,MIN_RECV_SATS); + } + } + lastStakedEra = staked_era; + } } - //fprintf(stderr,"%s connect.%d\n",ASSETCHAINS_SYMBOL,pindex->GetHeight()); numnotaries = komodo_notaries(pubkeys,pindex->GetHeight(),pindex->GetBlockTime()); calc_rmd160_sha256(rmd160,pubkeys[0],33); if ( pindex->GetHeight() > hwmheight ) @@ -829,16 +861,27 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) komodo_purge_ccdata((int32_t)pindex->GetHeight()); hwmheight = pindex->GetHeight(); } - komodo_event_rewind(sp,symbol,pindex->GetHeight()); - komodo_stateupdate(pindex->GetHeight(),0,0,0,zero,0,0,0,0,-pindex->GetHeight(),pindex->nTime,0,0,0,0,zero,0); + if (!fJustCheck) + { + komodo_event_rewind(sp,symbol,pindex->GetHeight()); + komodo_stateupdate(pindex->GetHeight(),0,0,0,zero,0,0,0,0,-pindex->GetHeight(),pindex->nTime,0,0,0,0,zero,0); + } } komodo_currentheight_set(chainActive.LastTip()->GetHeight()); + int transaction = 0; if ( pindex != 0 ) { height = pindex->GetHeight(); txn_count = block.vtx.size(); for (i=0; i 1 && ASSETCHAINS_NOTARY_PAY[0] != 0 ) + break; txhash = block.vtx[i].GetHash(); numvouts = block.vtx[i].vout.size(); notaryid = -1; @@ -863,11 +906,11 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) } //else printf("cant get scriptPubKey for ht.%d txi.%d vin.%d\n",height,i,j); } numvalid = bitweight(signedmask); - if ( (((height < 90000 || (signedmask & 1) != 0) && numvalid >= KOMODO_MINRATIFY) || + if ( ((height < 90000 || (signedmask & 1) != 0) && numvalid >= KOMODO_MINRATIFY) || (numvalid >= KOMODO_MINRATIFY && ASSETCHAINS_SYMBOL[0] != 0) || - numvalid > (numnotaries/5)) ) + numvalid > (numnotaries/5) ) { - if ( ASSETCHAINS_SYMBOL[0] != 0 ) + if ( !fJustCheck && ASSETCHAINS_SYMBOL[0] != 0) { static FILE *signedfp; if ( signedfp == 0 ) @@ -884,10 +927,18 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) fwrite(&signedmask,1,sizeof(signedmask),signedfp); 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); } notarized = 1; } + // simulate DPoW in regtest mode for dpowconfs tests/etc + if ( Params().NetworkIDString() == "regtest" && ( height%7 == 0) ) { + notarized = 1; + sp->NOTARIZED_HEIGHT = height; + sp->NOTARIZED_HASH = block.GetHash(); + sp->NOTARIZED_DESTTXID = txhash; + } if ( IS_KOMODO_NOTARY != 0 && ASSETCHAINS_SYMBOL[0] == 0 ) printf("(tx.%d: ",i); for (j=0; j= sizeof(uint32_t) && len <= sizeof(scriptbuf) ) { memcpy(scriptbuf,(uint8_t *)&block.vtx[i].vout[j].scriptPubKey[0],len); - notaryid = komodo_voutupdate(&isratification,notaryid,scriptbuf,len,height,txhash,i,j,&voutmask,&specialtx,¬arizedheight,(uint64_t)block.vtx[i].vout[j].nValue,notarized,signedmask,(uint32_t)chainActive.LastTip()->GetBlockTime()); + notaryid = komodo_voutupdate(fJustCheck,&isratification,notaryid,scriptbuf,len,height,txhash,i,j,&voutmask,&specialtx,¬arizedheight,(uint64_t)block.vtx[i].vout[j].nValue,notarized,signedmask,(uint32_t)chainActive.LastTip()->GetBlockTime()); + if ( fJustCheck && notaryid == -2 ) + { + // We see a valid notarisation here, save its location. + notarisations.push_back(i); + } if ( 0 && i > 0 ) { for (k=0; kGetHeight() == hwmheight ) + 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"); //KOMODO_INITDONE = (uint32_t)time(NULL); //fprintf(stderr,"%s end connect.%d\n",ASSETCHAINS_SYMBOL,pindex->GetHeight()); + if (fJustCheck) + { + if ( notarisations.size() == 0 ) + return(0); + if ( notarisations.size() == 1 && notarisations[0] == 1 ) + return(1); + if ( notarisations.size() > 1 || (notarisations.size() == 1 && notarisations[0] != 1) ) + return(-1); + } + else return(0); } - #endif diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 6cc7dc427..e76da09ec 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -25,9 +25,14 @@ int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp); +int32_t komodo_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notaryid,uint8_t *scriptbuf,int32_t scriptlen,int32_t height,uint256 txhash,int32_t i,int32_t j,uint64_t *voutmaskp,int32_t *specialtxp,int32_t *notarizedheightp,uint64_t value,int32_t notarized,uint64_t signedmask,uint32_t timestamp); unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params); bool EnsureWalletIsAvailable(bool avoidException); extern bool fRequestShutdown; + +int32_t MarmaraSignature(uint8_t *utxosig,CMutableTransaction &txNew); +uint8_t DecodeMaramaraCoinbaseOpRet(const CScript scriptPubKey,CPubKey &pk,int32_t &height,int32_t &unlockht); + //#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr)) struct MemoryStruct { char *memory; size_t size; }; @@ -57,6 +62,25 @@ void init_string(struct return_string *s) s->ptr[0] = '\0'; } +int tx_height( const uint256 &hash ){ + int nHeight = 0; + CTransaction tx; + uint256 hashBlock; + if (!GetTransaction(hash, tx, hashBlock, true)) { + fprintf(stderr,"tx hash %s does not exist!\n", hash.ToString().c_str() ); + } + + BlockMap::const_iterator it = mapBlockIndex.find(hashBlock); + if (it != mapBlockIndex.end()) { + nHeight = it->second->GetHeight(); + //fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight); + } else { + fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); + } + return nHeight; +} + + /************************************************************************ * * Use the "writer" to accumulate text until done @@ -1180,6 +1204,10 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); uint64_t komodo_commission(const CBlock *pblock,int32_t height) { + // LABS fungible chains, cannot have any block reward! + if ( is_STAKED(ASSETCHAINS_SYMBOL) == 2 ) + return(0); + int32_t i,j,n=0,txn_count; int64_t nSubsidy; uint64_t commission,total = 0; txn_count = pblock->vtx.size(); if ( ASSETCHAINS_FOUNDERS != 0 ) @@ -1190,7 +1218,12 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) if ( ASSETCHAINS_FOUNDERS > 1 ) { if ( (height % ASSETCHAINS_FOUNDERS) == 0 ) - commission = commission * ASSETCHAINS_FOUNDERS; + { + if ( ASSETCHAINS_FOUNDERS_REWARD == 0 ) + commission = commission * ASSETCHAINS_FOUNDERS; + else + commission = ASSETCHAINS_FOUNDERS_REWARD; + } else commission = 0; } } @@ -1250,7 +1283,8 @@ int8_t komodo_segid(int32_t nocache,int32_t height) if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value ) { segid = komodo_segid32(voutaddr) & 0x3f; - //fprintf(stderr,"komodo_segid.(%d) -> %02x\n",height,segid); + pindex->segid = segid; + //fprintf(stderr,"komodo_segid.(%d) -> %d\n",height,pindex->segid); } } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height); } @@ -1293,100 +1327,18 @@ uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 return(addrhash.uints[0]); } -uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr) -{ - bool fNegative,fOverflow; uint8_t hashbuf[256]; char address[64]; bits256 addrhash; arith_uint256 hashval,mindiff,ratio,coinage256; uint256 hash,pasthash; int32_t diff=0,segid,minage,i,iter=0; uint32_t txtime,segid32,winner = 0 ; uint64_t value,coinage; - txtime = komodo_txtime2(&value,txid,vout,address); - if ( validateflag == 0 ) - { - //fprintf(stderr,"blocktime.%u -> ",blocktime); - if ( blocktime < prevtime+3 ) - blocktime = prevtime+3; - if ( blocktime < GetAdjustedTime()-60 ) - blocktime = GetAdjustedTime()+30; - //fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime); - } - if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 ) - { - //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime); - return(0); - } - if ( value < SATOSHIDEN ) - return(0); - value /= SATOSHIDEN; - mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); - ratio = (mindiff / bnTarget); - if ( (minage= nHeight*3) > 6000 ) // about 100 blocks - minage = 6000; - komodo_segids(hashbuf,nHeight-101,100); - segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout); - segid = ((nHeight + segid32) & 0x3f); - for (iter=0; iter<600; iter++) - { - if ( blocktime+iter+segid*2 < txtime+minage ) - continue; - diff = (iter + blocktime - txtime - minage); - if ( diff < 0 ) - diff = 60; - else if ( diff > 3600*24*30 ) - { - //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage); - diff = 3600*24*30; - } - if ( iter > 0 ) - diff += segid*2; - coinage = (value * diff); - if ( blocktime+iter+segid*2 > prevtime+480 ) - coinage *= ((blocktime+iter+segid*2) - (prevtime+400)); - coinage256 = arith_uint256(coinage+1); - hashval = ratio * (UintToArith256(hash) / coinage256); - if ( hashval <= bnTarget ) - { - winner = 1; - if ( validateflag == 0 ) - { - //fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid); - blocktime += iter; - blocktime += segid * 2; - } - break; - } - if ( validateflag != 0 ) - { - /*for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); - fprintf(stderr," vs "); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff);*/ - break; - } - } - //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); - if ( 0 && validateflag != 0 ) - { - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); - fprintf(stderr," vs "); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d ht.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff,nHeight); - } - if ( nHeight < 10 ) - return(blocktime); - return(blocktime * winner); -} - arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc) { int32_t oldflag = 0,dispflag = 0; CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val; *percPoSp = percPoS = 0; - if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) ) + + if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) ) return(target); + sum = arith_uint256(0); ave = sum; - easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + easydiff.SetCompact(STAKING_MIN_DIFF,&fNegative,&fOverflow); for (i=n=m=0; i<100; i++) { ht = height - 100 + i; @@ -1408,12 +1360,22 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he sum += UintToArith256(pindex->GetBlockHash()); m++; } - } + } //else fprintf(stderr, "pindex returned null ht.%i\n",ht); if ( dispflag != 0 && ASSETCHAINS_STAKED < 100 && (i % 10) == 9 ) fprintf(stderr," %d, ",percPoS); } if ( m+n < 100 ) - percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100; + { + // We do actual PoS % at the start. Requires coin distribution in first 10 blocks! + 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 ) fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height); *percPoSp = percPoS; @@ -1472,13 +1434,127 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS); } } - else bnTarget = ave; // recent ave is perfect + else + bnTarget = ave; // recent ave is perfect return(bnTarget); } +uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr,int32_t PoSperc) +{ + bool fNegative,fOverflow; uint8_t hashbuf[256]; char address[64]; bits256 addrhash; arith_uint256 hashval,mindiff,ratio,coinage256; uint256 hash,pasthash; int32_t segid,minage,i,iter=0; int64_t diff=0; uint32_t txtime,segid32,winner = 0 ; uint64_t value,coinage; + txtime = komodo_txtime2(&value,txid,vout,address); + if ( validateflag == 0 ) + { + //fprintf(stderr,"blocktime.%u -> ",blocktime); + if ( blocktime < prevtime+3 ) + blocktime = prevtime+3; + if ( blocktime < GetAdjustedTime()-60 ) + blocktime = GetAdjustedTime()+30; + //fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime); + } + if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 ) + { + //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime); + return(0); + } + if ( value < SATOSHIDEN ) + return(0); + value /= SATOSHIDEN; + mindiff.SetCompact(STAKING_MIN_DIFF,&fNegative,&fOverflow); + ratio = (mindiff / bnTarget); + if ( (minage= nHeight*3) > 6000 ) // about 100 blocks + minage = 6000; + komodo_segids(hashbuf,nHeight-101,100); + segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout); + segid = ((nHeight + segid32) & 0x3f); + for (iter=0; iter<600; iter++) + { + if ( blocktime+iter+segid*2 < txtime+minage ) + continue; + diff = (iter + blocktime - txtime - minage); + if ( ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH || ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASHV1_1 ) + { + /*if ( PoSperc < ASSETCHAINS_STAKED ) + { + // Under PoS % target and we need to increase diff. + //fprintf(stderr, "PoS too low diff.%i changed to.",diff); + diff = diff * ( (ASSETCHAINS_STAKED - PoSperc + 1) * (ASSETCHAINS_STAKED - PoSperc + 1) * ( nHeight < 50 ? 1000 : 1)); + //fprintf(stderr, "%i \n",diff); + } + else */ + if ( PoSperc > ASSETCHAINS_STAKED ) + { + // Over PoS target need to lower diff. + //fprintf(stderr, "PoS too high diff.%i changed to.",diff); + diff = diff / ( (PoSperc - ASSETCHAINS_STAKED + 1) * (PoSperc - ASSETCHAINS_STAKED + 1) ); + //fprintf(stderr, "%i \n",diff); + } + } + if ( diff < 0 ) + diff = 60; + else if ( diff > 3600*24*30 ) + { + //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage); + diff = 3600*24*30; + } + if ( iter > 0 ) + diff += segid*2; + coinage = (value * diff); + if ( ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH || ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASHV1_1 ) + { + if ( PoSperc < ASSETCHAINS_STAKED ) + { + // Under PoS % target and we need to increase diff. + //fprintf(stderr, "PoS too low diff.%i changed to.",diff); + if ( blocktime+iter+segid*2 > prevtime+128 ) + coinage *= ((blocktime+iter+segid*2) - (prevtime+102)); + //fprintf(stderr, "%i \n",diff); + } + } + if ( blocktime+iter+segid*2 > prevtime+480 ) + coinage *= ((blocktime+iter+segid*2) - (prevtime+400)); + coinage256 = arith_uint256(coinage+1); + hashval = ratio * (UintToArith256(hash) / coinage256); + if ( hashval <= bnTarget ) + { + winner = 1; + if ( validateflag == 0 ) + { + //fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid); + blocktime += iter; + blocktime += segid * 2; + } + break; + } + if ( validateflag != 0 ) + { + /*for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); + fprintf(stderr," vs "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff); */ + break; + } + } + //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); + if ( 0 && validateflag != 0 ) + { + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); + fprintf(stderr," vs "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d ht.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff,nHeight); + } + if ( nHeight < 10 ) + return(blocktime); + return(blocktime * winner); +} + 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; + 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; if ( ASSETCHAINS_STAKED == 100 && height <= 10 ) return(1); BlockMap::const_iterator it = mapBlockIndex.find(pblock->GetHash()); @@ -1490,6 +1566,9 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_ return(0); else return(1); } + // Get PoSperc and POW Target. slowflag only here, calling it when blocks out of order causes problems. + if ( slowflag != 0 ) + POWTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED); txn_count = pblock->vtx.size(); //fprintf(stderr,"checkblock n.%d vins.%d vouts.%d %.8f %.8f\n",txn_count,(int32_t)pblock->vtx[txn_count-1].vin.size(),(int32_t)pblock->vtx[txn_count-1].vout.size(),(double)pblock->vtx[txn_count-1].vout[0].nValue/COIN,(double)pblock->vtx[txn_count-1].vout[1].nValue/COIN); if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 + (ASSETCHAINS_MARMARA!=0) ) @@ -1500,17 +1579,17 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_ txid = pblock->vtx[txn_count-1].vin[0].prevout.hash; vout = pblock->vtx[txn_count-1].vin[0].prevout.n; - if ( prevtime != 0 ) + if ( slowflag != 0 && prevtime != 0 ) { if ( komodo_isPoS(pblock,height) != 0 ) { - eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)""); + eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"",PoSperc); } if ( eligible == 0 || eligible > pblock->nTime ) { if ( 0 && ASSETCHAINS_STAKED < 100 ) fprintf(stderr,"komodo_is_PoSblock PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)pblock->nTime,(int32_t)(eligible - pblock->nTime)); - if ( slowflag != 0 && pindex != 0 ) + if ( pindex != 0 ) { pindex->segid = -1; //fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid); @@ -1519,24 +1598,20 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_ else { isPoS = 2; // 2 means staking utxo validated - if ( slowflag != 0 && height > 100 ) + CTxDestination voutaddress; char voutaddr[64]; + if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) ) { - CTxDestination voutaddress; char voutaddr[64]; - if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) ) - { - strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str()); - segid = komodo_segid32(voutaddr) & 0x3f; - //fprintf(stderr,"komodo_segid.(%d) -> %d\n",height,segid); - } - if ( pindex != 0 && segid >= 0 ) - { - pindex->segid = segid; - //fprintf(stderr,"B set segid.%d <- %d\n",height,pindex->segid); - } //else fprintf(stderr,"unexpected null pindex for slowflag set ht.%d segid.%d:%d\n",height,pindex!=0?pindex->segid:-3,segid); + strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str()); + segid = komodo_segid32(voutaddr) & 0x3f; } + if ( pindex != 0 && segid >= 0 ) + { + pindex->segid = segid; + //fprintf(stderr,"PoS block set segid.%d <- %d\n",height,pindex->segid); + } //else fprintf(stderr,"unexpected null pindex for slowflag set ht.%d segid.%d:%d\n",height,pindex!=0?pindex->segid:-3,segid); } - } - if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx + } + else if ( slowflag == 0 ) // previous blocks are not seen yet, do the best approx { if ( komodo_isPoS(pblock,height) != 0 ) isPoS = 1; @@ -1548,10 +1623,9 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_ fprintf(stderr,"ht.%d isPoS.%d utxo not validated -> must be PoW fake\n",height,isPoS); isPoS = 0; } - else + else if ( ASSETCHAINS_STAKED != 100 ) { - bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED); - if ( bhash < bnTarget ) + if ( bhash < POWTarget ) { //fprintf(stderr,"ht.%d isPoS but meets PoW diff!\n",height); isPoS = 0; @@ -1743,10 +1817,209 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height) return(isPOS); } +uint64_t komodo_notarypayamount(int32_t nHeight, int64_t notarycount) +{ + int8_t curEra = 0; int64_t ret = 0; + // if we have an end block in the first era, find our current era + if ( ASSETCHAINS_ENDSUBSIDY[0] > 1 ) + { + for ( curEra = 0; curEra <= ASSETCHAINS_LASTERA; curEra++ ) + { + if ( ASSETCHAINS_ENDSUBSIDY[curEra] > nHeight || ASSETCHAINS_ENDSUBSIDY[curEra] == 0 ) + break; + } + } + if ( curEra > ASSETCHAINS_LASTERA ) + return(0); + + if ( notarycount == 0 ) + { + fprintf(stderr, "komodo_notarypayamount failed num notaries is 0!\n"); + return(0); + } + // Because of reorgs we cannot use the notarized height value. + // We need to basically guess here and just pay some static amount. + // Has the unwanted effect of varying coin emission, but cannot be helped. + fprintf(stderr, "era.%i paying total of %lu\n",curEra, ASSETCHAINS_NOTARY_PAY[curEra]); + ret = ASSETCHAINS_NOTARY_PAY[curEra] / notarycount; + return(ret); +} + +int32_t komodo_getnotarizedheight(uint32_t timestamp,int32_t height, uint8_t *script, int32_t len) +{ + // Check the notarisation is valid, and extract notarised height. + uint64_t voutmask; + uint8_t scriptbuf[10001]; + int32_t isratification,specialtx,notarizedheight; + + if ( len >= sizeof(uint32_t) && len <= sizeof(scriptbuf) ) + { + memcpy(scriptbuf,script,len); + if ( komodo_voutupdate(true,&isratification,0,scriptbuf,len,height,uint256(),1,1,&voutmask,&specialtx,¬arizedheight,0,1,0,timestamp) == -2 ) + { + fprintf(stderr, ">>>>>>VALID NOTARIZATION ht.%i\n",notarizedheight); + } + else + { + // This should no longer happen. Unless notaries are making actual invalid notarizations. + fprintf(stderr, "<<<<< &NotarisationNotaries, uint32_t timestamp, int32_t height, uint8_t *script, int32_t len) +{ + // fetch notary pubkey array. + uint64_t total = 0, AmountToPay = 0; + int8_t numSN = 0; uint8_t notarypubkeys[64][33] = {0}; + numSN = komodo_notaries(notarypubkeys, height, timestamp); + + // No point going further, no notaries can be paid. + if ( notarypubkeys[0][0] == 0 ) + return(0); + + // Check the notarisation is valid. + int32_t notarizedheight = komodo_getnotarizedheight(timestamp, height, script, len); + if ( notarizedheight == 0 ) + return(0); + + // resize coinbase vouts to number of notary nodes +1 for coinbase itself. + txNew.vout.resize(NotarisationNotaries.size()+1); + + // Calcualte the amount to pay according to the current era. + AmountToPay = komodo_notarypayamount(height,NotarisationNotaries.size()); + if ( AmountToPay == 0 ) + return(0); + + // loop over notarisation vins and add transaction to coinbase. + // Commented prints here can be used to verify manually the pubkeys match. + for (int8_t n = 0; n < NotarisationNotaries.size(); n++) + { + uint8_t *ptr; + txNew.vout[n+1].scriptPubKey.resize(35); + ptr = (uint8_t *)&txNew.vout[n+1].scriptPubKey[0]; + ptr[0] = 33; + for (int8_t i=0; i<33; i++) + { + ptr[i+1] = notarypubkeys[NotarisationNotaries[n]][i]; + //fprintf(stderr,"%02x",ptr[i+1]); + } + ptr[34] = OP_CHECKSIG; + //fprintf(stderr," set notary %i PUBKEY33 into vout[%i] amount.%lu\n",NotarisationNotaries[n],n+1,AmountToPay); + txNew.vout[n+1].nValue = AmountToPay; + total += txNew.vout[n+1].nValue; + } + return(total); +} + +uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height) +{ + std::vector NotarisationNotaries; + uint32_t timestamp = pblock->nTime; + int8_t numSN = 0; uint8_t notarypubkeys[64][33] = {0}; + numSN = komodo_notaries(notarypubkeys, height, timestamp); + + // No point going further, no notaries can be paid. + if ( notarypubkeys[0][0] == 0 ) + return(0); + + uint8_t *script; int32_t scriptlen; + // Loop over the notarisation and extract the position of the participating notaries in the array of pukeys for this era. + BOOST_FOREACH(const CTxIn& txin, pblock->vtx[1].vin) + { + uint256 hash; CTransaction tx1; + if ( GetTransaction(txin.prevout.hash,tx1,hash,false) ) + { + for (int8_t i = 0; i < numSN; i++) + { + script = (uint8_t *)&tx1.vout[txin.prevout.n].scriptPubKey[0]; + scriptlen = (int32_t)tx1.vout[txin.prevout.n].scriptPubKey.size(); + if ( scriptlen == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && memcmp(script+1,notarypubkeys[i],33) == 0 ) + NotarisationNotaries.push_back(i); + } + } + } + // check a notary didnt sign twice (this would be an invalid notarisation later on and cause problems) + std::set checkdupes( NotarisationNotaries.begin(), NotarisationNotaries.end() ); + if ( checkdupes.size() != NotarisationNotaries.size() ) { + fprintf(stderr, "Possible notarisation is signed multiple times by same notary. It is invalid.\n"); + return(0); + } + const CChainParams& chainparams = Params(); + const Consensus::Params &consensusParams = chainparams.GetConsensus(); + uint64_t totalsats = 0; + CMutableTransaction txNew = CreateNewContextualCMutableTransaction(consensusParams, height); + if ( pblock->vtx[1].vout.size() == 2 && pblock->vtx[1].vout[1].nValue == 0 ) + { + // Get the OP_RETURN for the notarisation + uint8_t *script = (uint8_t *)&pblock->vtx[1].vout[1].scriptPubKey[0]; + int32_t scriptlen = (int32_t)pblock->vtx[1].vout[1].scriptPubKey.size(); + if ( script[0] == OP_RETURN ) + { + // Create the coinbase tx again, using the extracted data, this is the same function the miner uses, with the same data. + // This allows us to know exactly that the coinbase is correct. + totalsats = komodo_notarypay(txNew, NotarisationNotaries, pblock->nTime, height, script, scriptlen); + } + else + { + fprintf(stderr, "vout 2 of notarisation is not OP_RETURN scriptlen.%i\n", scriptlen); + return(0); + } + } else return(0); + + // if notarypay fails, because the notarisation is not valid, exit now as txNew was not created. + // This should never happen, as the notarisation is checked before this function is called. + if ( totalsats == 0 ) + { + fprintf(stderr, "notary pay returned 0!\n"); + return(0); + } + + int8_t n = 0, i = 0, matches = 0; + uint64_t total = 0, AmountToPay = 0; + + // get the pay amount from the created tx. + AmountToPay = txNew.vout[1].nValue; + + // Check the created coinbase pays the correct notaries. + BOOST_FOREACH(const CTxOut& txout, pblock->vtx[0].vout) + { + // skip the coinbase paid to the miner. + if ( n == 0 ) + { + n++; + continue; + } + // Check the pubkeys match the pubkeys in the notarisation. + script = (uint8_t *)&txout.scriptPubKey[0]; + scriptlen = (int32_t)txout.scriptPubKey.size(); + if ( scriptlen == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && memcmp(script+1,notarypubkeys[NotarisationNotaries[n-1]],33) == 0 ) + { + // check the value is correct + if ( pblock->vtx[0].vout[n].nValue == AmountToPay ) + { + matches++; + total += txout.nValue; + //fprintf(stderr, "MATCHED AmountPaid.%lu notaryid.%i\n",AmountToPay,NotarisationNotaries[n-1]); + } + else fprintf(stderr, "NOT MATCHED AmountPaid.%lu AmountToPay.%lu notaryid.%i\n", pblock->vtx[0].vout[n].nValue, AmountToPay, NotarisationNotaries[n-1]); + } + n++; + } + if ( matches != 0 && matches == NotarisationNotaries.size() && totalsats == total ) + { + fprintf(stderr, "Validated coinbase matches notarisation in tx position 1.\n" ); + return(totalsats); + } + return(0); +} + int64_t komodo_checkcommission(CBlock *pblock,int32_t height) { int64_t checktoshis=0; uint8_t *script,scripthex[8192]; int32_t scriptlen,matched = 0; - if ( ASSETCHAINS_COMMISSION != 0 ) + if ( ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 ) { checktoshis = komodo_commission(pblock,height); if ( checktoshis >= 10000 && pblock->vtx[0].vout.size() < 2 ) @@ -1758,10 +2031,13 @@ int64_t komodo_checkcommission(CBlock *pblock,int32_t height) { script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0]; scriptlen = (int32_t)pblock->vtx[0].vout[1].scriptPubKey.size(); - //int32_t i; - //for (i=0; ivtx[0].vout[1].nValue/COIN); + if ( 0 ) + { + int32_t i; + for (i=0; ivtx[0].vout[1].nValue/COIN); + } if ( ASSETCHAINS_SCRIPTPUB.size() > 1 ) { if ( ASSETCHAINS_SCRIPTPUB.size()/2 == scriptlen && scriptlen < sizeof(scripthex) ) @@ -1777,7 +2053,13 @@ int64_t komodo_checkcommission(CBlock *pblock,int32_t height) matched = 25; if ( matched == 0 ) { - fprintf(stderr," payment to wrong pubkey scriptlen.%d, scriptpub[%d] checktoshis.%llu\n",scriptlen,(int32_t)ASSETCHAINS_SCRIPTPUB.size()/2,(long long)checktoshis); + if ( 0 && ASSETCHAINS_SCRIPTPUB.size() > 1 ) + { + int32_t i; + for (i=0; i bnTarget ) + bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED); + if ( bhash > bnTarget && height > 100 ) { for (i=31; i>=16; i--) fprintf(stderr,"%02x",((uint8_t *)&bhash)[i]); @@ -1873,7 +2154,18 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED); return(-1); - } else failed = 0; + } + else + { + failed = 0; + CBlockIndex *pindex; + BlockMap::const_iterator it = mapBlockIndex.find(pblock->GetHash()); + pindex = it != mapBlockIndex.end() ? it->second : NULL; + if ( pindex != 0 && pindex->segid == -2 ) { + pindex->segid = -1; + //fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid); + } + } } } else if ( is_PoSblock < 0 ) @@ -1914,6 +2206,32 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height) return(-1); } } + // Consensus rule to force miners to mine the notary coinbase payment happens in ConnectBlock + // the default daemon miner, checks the actual vins so the only way this will fail, is if someone changes the miner, + // and then creates txs to the crypto address meeting min sigs and puts it in tx position 1. + // If they go through this effort, the block will still fail at connect block, and will be auto purged by the temp file fix. + if ( failed == 0 && ASSETCHAINS_NOTARY_PAY[0] != 0 && pblock->vtx[0].vout.size() > 1 ) + { + // We check the full validation in ConnectBlock directly to get the amount for coinbase. So just approx here. + if ( slowflag == 0 ) + { + // Check the notarisation tx is to the crypto address. + if ( !komodo_is_notarytx(pblock->vtx[1]) == 1 ) + { + fprintf(stderr, "notarisation is not to crypto address ht.%i\n",height); + return(-1); + } + // Check min sigs. + int8_t numSN = 0; uint8_t notarypubkeys[64][33] = {0}; + numSN = komodo_notaries(notarypubkeys, height, pblock->nTime); + if ( pblock->vtx[1].vin.size() < numSN/5 ) + { + fprintf(stderr, "ht.%i does not meet minsigs.%i sigs.%li\n",height,numSN/5,pblock->vtx[1].vin.size()); + return(-1); + } + } + } + //fprintf(stderr,"komodo_checkPOW possible.%d slowflag.%d ht.%d notaryid.%d failed.%d\n",possible,slowflag,height,notaryid,failed); if ( failed != 0 && possible == 0 && notaryid < 0 ) return(-1); @@ -2057,70 +2375,15 @@ struct komodo_staking *komodo_addutxo(struct komodo_staking *array,int32_t *numk return(array); } -arith_uint256 _komodo_eligible(struct komodo_staking *kp,arith_uint256 ratio,uint32_t blocktime,int32_t iter,int32_t minage,int32_t segid,int32_t nHeight,uint32_t prevtime) -{ - int32_t diff; uint64_t coinage; arith_uint256 coinage256,hashval; - diff = (iter + blocktime - kp->txtime - minage); - if ( diff < 0 ) - diff = 60; - else if ( diff > 3600*24*30 ) - diff = 3600*24*30; - if ( iter > 0 ) - diff += segid*2; - coinage = ((uint64_t)kp->nValue * diff); - if ( blocktime+iter+segid*2 > prevtime+480 ) - coinage *= ((blocktime+iter+segid*2) - (prevtime+400)); - coinage256 = arith_uint256(coinage+1); - hashval = ratio * (kp->hashval / coinage256); - return(hashval); -} - -uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komodo_staking *kp,int32_t nHeight,uint32_t blocktime,uint32_t prevtime,int32_t minage,uint8_t *hashbuf) -{ - int32_t maxiters = 600; uint256 hash; - int32_t segid,iter,diff; uint64_t coinage; arith_uint256 hashval,coinage256; - komodo_stakehash(&hash,kp->address,hashbuf,kp->txid,kp->vout); - kp->hashval = UintToArith256(hash); - segid = ((nHeight + kp->segid32) & 0x3f); - hashval = _komodo_eligible(kp,ratio,blocktime,maxiters,minage,segid,nHeight,prevtime); - /*for (int i=31; i>=16; i--) - fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); - fprintf(stderr," vs "); - for (int i=31; i>=16; i--) - fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," b.%u minage.%d segid.%d ht.%d prev.%u\n",blocktime,minage,segid,nHeight,prevtime);*/ - if ( hashval <= bnTarget ) - { - for (iter=0; itertxtime+minage ) - continue; - hashval = _komodo_eligible(kp,ratio,blocktime,iter,minage,segid,nHeight,prevtime); - if ( hashval <= bnTarget ) - { - //fprintf(stderr,"winner %.8f blocktime.%u iter.%d segid.%d\n",(double)kp->nValue/COIN,blocktime,iter,segid); - blocktime += iter; - blocktime += segid * 2; - return(blocktime); - } - } - } else fprintf(stderr,"maxiters is not good enough\n"); - return(0); -} - -int32_t MarmaraSignature(uint8_t *utxosig,CMutableTransaction &txNew); -uint8_t DecodeMaramaraCoinbaseOpRet(const CScript scriptPubKey,CPubKey &pk,int32_t &height,int32_t &unlockht); - int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime; - set setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock; + int32_t PoSperc; + set setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget,tmpTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock; if (!EnsureWalletIsAvailable(0)) return 0; - + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); - mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); - ratio = (mindiff / bnTarget); assert(pwalletMain != NULL); *utxovaluep = 0; memset(utxotxidp,0,sizeof(*utxotxidp)); @@ -2129,10 +2392,12 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt if ( (tipindex= chainActive.Tip()) == 0 ) return(0); nHeight = tipindex->GetHeight() + 1; + // Get the PoS% so we can pass it to komodo_stake, this is to adjust PoS dofficulty when it is under the target %! + tmpTarget = komodo_PoWtarget(&PoSperc,bnTarget,nHeight,ASSETCHAINS_STAKED); if ( (minage= nHeight*3) > 6000 ) // about 100 blocks minage = 6000; komodo_segids(hashbuf,nHeight-101,100); - if ( *blocktimep < tipindex->nTime+60 ) + 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); @@ -2150,7 +2415,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt } } - if ( time(NULL) > lasttime+600 || array == 0 || resetstaker ) + if ( resetstaker || array == 0 || time(NULL) > lasttime+600 ) { LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); @@ -2173,7 +2438,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt counter++; if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth ) { - fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth); + //fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth); continue; } CAmount nValue = out.tx->vout[out.i].nValue; @@ -2222,27 +2487,25 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt //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; + block_from_future_rejecttime = (uint32_t)GetAdjustedTime() + 57; for (i=winners=0; iGetHeight()+1 > nHeight ) { fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter); return(0); } kp = &array[i]; - if ( (eligible2= komodo_eligible(bnTarget,ratio,kp,nHeight,*blocktimep,(uint32_t)tipindex->nTime+27,minage,hashbuf)) == 0 ) - continue; - eligible = komodo_stake(0,bnTarget,nHeight,kp->txid,kp->vout,0,(uint32_t)tipindex->nTime+27,kp->address); -//fprintf(stderr,"i.%d %u vs %u\n",i,eligible2,eligible); + eligible = komodo_stake(0,bnTarget,nHeight,kp->txid,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; - if ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) ) + 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) ) + while ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address,PoSperc) ) { besttime = eligible; eligible--; @@ -2269,7 +2532,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt 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); + //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"); } diff --git a/src/komodo_defs.h b/src/komodo_defs.h index 9f33c6036..cbf84b7f0 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -34,24 +34,28 @@ #define GETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] & (1 << ((bitoffset) & 7))) #define CLEARBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] &= ~(1 << ((bitoffset) & 7))) +#define KOMODO_MAXNVALUE (((uint64_t)1 << 63) - 1) +#define KOMODO_BIT63SET(x) ((x) & ((uint64_t)1 << 63)) +#define KOMODO_VALUETOOBIG(x) ((x) > (uint64_t)10000000001*COIN) + extern uint8_t ASSETCHAINS_TXPOW,ASSETCHAINS_PUBLIC; int32_t MAX_BLOCK_SIZE(int32_t height); extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; extern uint32_t ASSETCHAIN_INIT, ASSETCHAINS_MAGIC,ASSETCHAINS_BLOCKTIME; extern int32_t VERUS_BLOCK_POSUNITS, ASSETCHAINS_LWMAPOS, ASSETCHAINS_SAPLING, ASSETCHAINS_OVERWINTER; -extern uint64_t ASSETCHAINS_SUPPLY; +extern uint64_t ASSETCHAINS_SUPPLY, ASSETCHAINS_FOUNDERS_REWARD; extern uint64_t ASSETCHAINS_TIMELOCKGTE; extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH,ASSETCHAINS_EQUIHASH,KOMODO_INITDONE; -extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,KOMODO_ON_DEMAND,KOMODO_PASSPORT_INITDONE; -extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_STAKED; +extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,KOMODO_ON_DEMAND,KOMODO_PASSPORT_INITDONE,ASSETCHAINS_STAKED; +extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_LASTERA; extern bool VERUS_MINTBLOCKS; -extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[]; +extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_NOTARY_PAY[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[]; extern const char *ASSETCHAINS_ALGORITHMS[]; extern int32_t VERUS_MIN_STAKEAGE; -extern uint32_t ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[]; +extern uint32_t ASSETCHAINS_VERUSHASH, ASSETCHAINS_VERUSHASHV1_1, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[]; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY,ASSETCHAINS_SCRIPTPUB; extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_MARMARA; @@ -74,5 +78,8 @@ extern int32_t VERUS_MIN_STAKEAGE; extern std::string DONATION_PUBKEY; extern uint8_t ASSETCHAINS_PRIVATE; extern int32_t USE_EXTERNAL_PUBKEY; +int tx_height( const uint256 &hash ); +extern char NOTARYADDRS[64][36]; +extern uint8_t NUM_NOTARIES; #endif diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 68e648b14..36409e67d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -710,7 +710,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } // we don't want these checks in VRSC, leave it at the Sapling upgrade if ( ASSETCHAINS_SYMBOL[0] == 0 || - (ASSETCHAINS_COMMISSION != 0 && height > 1) || + ((ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD) && height > 1) || NetworkUpgradeActive(height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING) ) { n = block.vtx[0].vout.size(); @@ -772,7 +772,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim else { checktoshis = 0; - if ( ASSETCHAINS_COMMISSION != 0 && height > 1 ) + if ( (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD) && height > 1 ) { if ( (checktoshis= komodo_checkcommission((CBlock *)&block,height)) < 0 ) { diff --git a/src/komodo_globals.h b/src/komodo_globals.h index c85c68451..69ad6b840 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -29,9 +29,8 @@ 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); -bool pubkey2addr(char *destaddr,uint8_t *pubkey33); -pthread_mutex_t komodo_mutex; +pthread_mutex_t komodo_mutex,staked_mutex; #define KOMODO_ELECTION_GAP 2000 //((ASSETCHAINS_SYMBOL[0] == 0) ? 2000 : 100) #define KOMODO_ASSETCHAIN_MAXLEN 65 @@ -46,15 +45,15 @@ struct komodo_state KOMODO_STATES[34]; int COINBASE_MATURITY = _COINBASE_MATURITY;//100; unsigned int WITNESS_CACHE_SIZE = _COINBASE_MATURITY+10; -int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,KOMODO_CONNECTING = -1,KOMODO_DEALERNODE,KOMODO_EXTRASATOSHI,ASSETCHAINS_FOUNDERS; +int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,IS_STAKED_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,STAKED_ERA,KOMODO_CONNECTING = -1,KOMODO_DEALERNODE,KOMODO_EXTRASATOSHI,ASSETCHAINS_FOUNDERS; int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1; -std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,ASSETCHAINS_SELFIMPORT,ASSETCHAINS_CCLIB; -uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEYHASH[20],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW,ASSETCHAINS_MARMARA; +std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,NOTARY_ADDRESS,WHITELIST_ADDRESS,ASSETCHAINS_SELFIMPORT,ASSETCHAINS_CCLIB; +uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEYHASH[20],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW,NUM_NOTARIES,ASSETCHAINS_MARMARA; bool VERUS_MINTBLOCKS; -char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096]; +char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096],NOTARYADDRS[64][36]; uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_BEAMPORT,ASSETCHAINS_CODAPORT; -uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC,KOMODO_STOPAT,KOMODO_DPOWCONFS = 1; +uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC,KOMODO_STOPAT,KOMODO_DPOWCONFS = 1,STAKING_MIN_DIFF; uint32_t ASSETCHAINS_MAGIC = 2387029918; int64_t ASSETCHAINS_GENESISTXVAL = 5000000000; @@ -69,20 +68,23 @@ int64_t MAX_MONEY = 200000000 * 100000000LL; uint64_t ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF; uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0; -uint32_t ASSETCHAINS_LASTERA = 1; -uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS]; +uint64_t ASSETCHAINS_LASTERA = 1; +uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_NOTARY_PAY[ASSETCHAINS_MAX_ERAS]; uint8_t ASSETCHAINS_CCDISABLES[256]; #define _ASSETCHAINS_EQUIHASH 0 -uint32_t ASSETCHAINS_NUMALGOS = 2; +uint32_t ASSETCHAINS_NUMALGOS = 3; uint32_t ASSETCHAINS_EQUIHASH = _ASSETCHAINS_EQUIHASH; uint32_t ASSETCHAINS_VERUSHASH = 1; -const char *ASSETCHAINS_ALGORITHMS[] = {"equihash", "verushash"}; -uint64_t ASSETCHAINS_NONCEMASK[] = {0xffff,0xfffffff}; -uint32_t ASSETCHAINS_NONCESHIFT[] = {32,16}; -uint32_t ASSETCHAINS_HASHESPERROUND[] = {1,4096}; +uint32_t ASSETCHAINS_VERUSHASHV1_1 = 2; +const char *ASSETCHAINS_ALGORITHMS[] = {"equihash", "verushash", "verushash11"}; +uint64_t ASSETCHAINS_NONCEMASK[] = {0xffff,0xfffffff,0xfffffff}; +uint32_t ASSETCHAINS_NONCESHIFT[] = {32,16,16}; +uint32_t ASSETCHAINS_HASHESPERROUND[] = {1,4096,4096}; uint32_t ASSETCHAINS_ALGO = _ASSETCHAINS_EQUIHASH; - +// min diff returned from GetNextWorkRequired needs to be added here for each algo, so they can work with ac_staked. +uint32_t ASSETCHAINS_MINDIFF[] = {537857807,504303375,487526159}; + // ^ wrong! // Verus proof of stake controls int32_t ASSETCHAINS_LWMAPOS = 0; // percentage of blocks should be PoS int32_t VERUS_BLOCK_POSUNITS = 1024; // one block is 1000 units @@ -94,7 +96,8 @@ int32_t ASSETCHAINS_SAPLING = -1; int32_t ASSETCHAINS_OVERWINTER = -1; uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; -uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10; +int32_t ASSETCHAINS_STAKED; +uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY = 10,MIN_RECV_SATS,ASSETCHAINS_FOUNDERS_REWARD; uint32_t KOMODO_INITDONE; char KMDUSERPASS[8192+512+1],BTCUSERPASS[8192]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771; @@ -126,20 +129,20 @@ int32_t komodo_baseid(char *origbase) #ifndef SATOSHIDEN #define SATOSHIDEN ((uint64_t)100000000L) #endif -int64_t komodo_current_supply(uint32_t nHeight) +uint64_t komodo_current_supply(uint32_t nHeight) { uint64_t cur_money; int32_t baseid; - if ( (baseid = komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 ) - cur_money = ASSETCHAINS_GENESISTXVAL + ASSETCHAINS_SUPPLY + nHeight * ASSETCHAINS_REWARD[0] / SATOSHIDEN; - else + //if ( (baseid = komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 ) + // cur_money = ASSETCHAINS_GENESISTXVAL + ASSETCHAINS_SUPPLY + nHeight * ASSETCHAINS_REWARD[0] / SATOSHIDEN; + //else { // figure out max_money by adding up supply to a maximum of 10,000,000 blocks cur_money = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff) + ASSETCHAINS_GENESISTXVAL; if ( ASSETCHAINS_LASTERA == 0 && ASSETCHAINS_REWARD[0] == 0 ) { - cur_money += (nHeight * 10000) / SATOSHIDEN; + cur_money += (nHeight * 10000);// / SATOSHIDEN; } else { @@ -152,6 +155,8 @@ int64_t komodo_current_supply(uint32_t nHeight) // add rewards from this era, up to nHeight int64_t reward = ASSETCHAINS_REWARD[j]; + + //fprintf(stderr,"last.%d reward %llu period %llu\n",(int32_t)ASSETCHAINS_LASTERA,(long long)reward,(long long)ASSETCHAINS_HALVING[j]); if ( reward > 0 ) { uint64_t lastEnd = j == 0 ? 0 : ASSETCHAINS_ENDSUBSIDY[j - 1]; @@ -163,10 +168,12 @@ int64_t komodo_current_supply(uint32_t nHeight) uint32_t modulo = (curEnd - lastEnd) % period; uint64_t decay = ASSETCHAINS_DECAY[j]; - if (!period) + //fprintf(stderr,"period.%llu cur_money %.8f += %.8f * %d\n",(long long)period,(double)cur_money/COIN,(double)reward/COIN,nHeight); + if ( ASSETCHAINS_HALVING[j] == 0 ) { // no halving, straight multiply cur_money += reward * (nHeight - 1); + //fprintf(stderr,"cur_money %.8f\n",(double)cur_money/COIN); } // if exactly SATOSHIDEN, linear decay to zero or to next era, same as: // (next_era_reward + (starting reward - next_era_reward) / 2) * num_blocks @@ -260,6 +267,18 @@ int64_t komodo_current_supply(uint32_t nHeight) } } } + } + if ( KOMODO_BIT63SET(cur_money) != 0 ) + return(KOMODO_MAXNVALUE); + if ( ASSETCHAINS_COMMISSION != 0 ) + { + uint64_t newval = (cur_money + (cur_money/COIN * ASSETCHAINS_COMMISSION)); + if ( KOMODO_BIT63SET(newval) != 0 ) + return(KOMODO_MAXNVALUE); + else if ( newval < cur_money ) // check for underflow + return(KOMODO_MAXNVALUE); + return(newval); } - return((int64_t)(cur_money + (cur_money * ASSETCHAINS_COMMISSION))); + //fprintf(stderr,"cur_money %.8f\n",(double)cur_money/COIN); + return(cur_money); } diff --git a/src/komodo_notary.h b/src/komodo_notary.h index fca7fd223..5cdbf237d 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -15,9 +15,10 @@ #include "komodo_defs.h" - #include "komodo_cJSON.h" +#include "notaries_staked.h" + #define KOMODO_MAINNET_START 178999 const char *Notaries_genesis[][2] = @@ -203,19 +204,25 @@ int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestam { 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; + if ( timestamp == 0 && ASSETCHAINS_SYMBOL[0] != 0 ) timestamp = komodo_heightstamp(height); else if ( ASSETCHAINS_SYMBOL[0] == 0 ) timestamp = 0; - if ( height >= KOMODO_NOTARIES_HARDCODED || ASSETCHAINS_SYMBOL[0] != 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 ( 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) ) { if ( did0 == 0 ) { n0 = (int32_t)(sizeof(Notaries_elected0)/sizeof(*Notaries_elected0)); - for (i=0; i= KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP ) htind = (KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP) - 1; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 469cbd21b..079ce1eea 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1366,7 +1366,8 @@ void komodo_statefname(char *fname,char *symbol,char *str) fname[len - n] = 0; else { - printf("unexpected fname.(%s) vs %s [%s] n.%d len.%d (%s)\n",fname,symbol,ASSETCHAINS_SYMBOL,n,len,&fname[len - n]); + if ( strcmp(symbol,"REGTEST") != 0 ) + printf("unexpected fname.(%s) vs %s [%s] n.%d len.%d (%s)\n",fname,symbol,ASSETCHAINS_SYMBOL,n,len,&fname[len - n]); return; } } @@ -1538,7 +1539,8 @@ uint16_t komodo_port(char *symbol,uint64_t supply,uint32_t *magicp,uint8_t *extr printf("ports\n"); }*/ -char *iguanafmtstr = (char *)"curl --url \"http://127.0.0.1:7776\" --data \"{\\\"conf\\\":\\\"%s.conf\\\",\\\"path\\\":\\\"${HOME#\"/\"}/.komodo/%s\\\",\\\"unitval\\\":\\\"20\\\",\\\"zcash\\\":1,\\\"RELAY\\\":-1,\\\"VALIDATE\\\":0,\\\"prefetchlag\\\":-1,\\\"poll\\\":100,\\\"active\\\":1,\\\"sapling\\\":1,\\\"agent\\\":\\\"iguana\\\",\\\"method\\\":\\\"addcoin\\\",\\\"startpend\\\":4,\\\"endpend\\\":4,\\\"services\\\":129,\\\"maxpeers\\\":8,\\\"newcoin\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\",\\\"hasheaders\\\":1,\\\"useaddmultisig\\\":0,\\\"netmagic\\\":\\\"%s\\\",\\\"p2p\\\":%u,\\\"rpc\\\":%u,\\\"pubval\\\":60,\\\"p2shval\\\":85,\\\"wifval\\\":188,\\\"txfee_satoshis\\\":\\\"10000\\\",\\\"isPoS\\\":0,\\\"minoutput\\\":10000,\\\"minconfirms\\\":2,\\\"genesishash\\\":\\\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\\\",\\\"protover\\\":170002,\\\"genesisblock\\\":\\\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\\\",\\\"debug\\\":0,\\\"seedipaddr\\\":\\\"%s\\\"}\""; +char *iguanafmtstr = (char *)"curl --url \"http://127.0.0.1:7776\" --data \"{\\\"conf\\\":\\\"%s.conf\\\",\\\"path\\\":\\\"${HOME#\"/\"}/.komodo/%s\\\",\\\"unitval\\\":\\\"20\\\",\\\"zcash\\\":1,\\\"RELAY\\\":-1,\\\"VALIDATE\\\":0,\\\"prefetchlag\\\":-1,\\\"poll\\\":100,\\\"active\\\":1,\\\"agent\\\":\\\"iguana\\\",\\\"method\\\":\\\"addcoin\\\",\\\"startpend\\\":4,\\\"endpend\\\":4,\\\"services\\\":129,\\\"maxpeers\\\":8,\\\"newcoin\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\",\\\"hasheaders\\\":1,\\\"useaddmultisig\\\":0,\\\"netmagic\\\":\\\"%s\\\",\\\"p2p\\\":%u,\\\"rpc\\\":%u,\\\"pubval\\\":60,\\\"p2shval\\\":85,\\\"wifval\\\":188,\\\"txfee_satoshis\\\":\\\"10000\\\",\\\"isPoS\\\":0,\\\"minoutput\\\":10000,\\\"minconfirms\\\":2,\\\"genesishash\\\":\\\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\\\",\\\"protover\\\":170002,\\\"genesisblock\\\":\\\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\\\",\\\"debug\\\":0,\\\"seedipaddr\\\":\\\"%s\\\",\\\"sapling\\\":1}\""; + int32_t komodo_whoami(char *pubkeystr,int32_t height,uint32_t timestamp) @@ -1561,7 +1563,7 @@ char *argv0names[] = (char *)"MNZ", (char *)"MNZ", (char *)"MNZ", (char *)"MNZ", (char *)"BTCH", (char *)"BTCH", (char *)"BTCH", (char *)"BTCH" }; -int64_t komodo_max_money() +uint64_t komodo_max_money() { return komodo_current_supply(10000000); } @@ -1638,14 +1640,26 @@ uint64_t komodo_ac_block_subsidy(int nHeight) } } } - if ( nHeight == 1 ) + uint32_t magicExtra = ASSETCHAINS_STAKED ? ASSETCHAINS_MAGIC : (ASSETCHAINS_MAGIC & 0xffffff); + if ( ASSETCHAINS_SUPPLY > 10000000000 ) // over 10 billion? + { + if ( nHeight <= ASSETCHAINS_SUPPLY/1000000000 ) + { + subsidy += (uint64_t)1000000000 * COIN; + if ( nHeight == 1 ) + subsidy += (ASSETCHAINS_SUPPLY % 1000000000)*COIN + magicExtra; + } + } + else if ( nHeight == 1 ) { - uint32_t magicExtra = ASSETCHAINS_STAKED ? ASSETCHAINS_MAGIC : (ASSETCHAINS_MAGIC & 0xffffff); if ( ASSETCHAINS_LASTERA == 0 ) subsidy = ASSETCHAINS_SUPPLY * SATOSHIDEN + magicExtra; else subsidy += ASSETCHAINS_SUPPLY * SATOSHIDEN + magicExtra; } + else if ( is_STAKED(ASSETCHAINS_SYMBOL) == 2 ) + return(0); + // LABS fungible chains, cannot have any block reward! return(subsidy); } @@ -1656,14 +1670,19 @@ void komodo_args(char *argv0) extern const char *Notaries_elected1[][2]; std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],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]; 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"); + exit(0); + } + MIN_RECV_SATS = GetArg("-mintxvalue",-1); + WHITELIST_ADDRESS = GetArg("-whitelistaddress",""); memset(ccenables,0,sizeof(ccenables)); memset(disablebits,0,sizeof(disablebits)); if ( GetBoolArg("-gen", false) != 0 ) { KOMODO_MININGTHREADS = GetArg("-genproclimit",-1); } - else KOMODO_MININGTHREADS = 0; - if ( (KOMODO_EXCHANGEWALLET= GetBoolArg("-exchange", false)) != 0 ) fprintf(stderr,"KOMODO_EXCHANGEWALLET mode active\n"); DONATION_PUBKEY = GetArg("-donation", ""); @@ -1681,13 +1700,13 @@ void komodo_args(char *argv0) 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]); break; } } - //KOMODO_PAX = 1; - } //else KOMODO_PAX = GetArg("-pax",0); - name = GetArg("-ac_name",""); + } + name = GetArg("-ac_name",""); if ( argv0 != 0 ) { len = (int32_t)strlen(argv0); @@ -1714,7 +1733,7 @@ void komodo_args(char *argv0) { printf("KOMODO_REWIND %d\n",KOMODO_REWIND); } - if ( name.c_str()[0] != 0 ) + if ( name.c_str()[0] != 0 ) { std::string selectedAlgo = GetArg("-ac_algo", std::string(ASSETCHAINS_ALGORITHMS[0])); @@ -1723,6 +1742,7 @@ void komodo_args(char *argv0) if (std::string(ASSETCHAINS_ALGORITHMS[i]) == selectedAlgo) { ASSETCHAINS_ALGO = i; + STAKING_MIN_DIFF = ASSETCHAINS_MINDIFF[i]; // only worth mentioning if it's not equihash if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH) printf("ASSETCHAINS_ALGO, algorithm set to %s\n", selectedAlgo.c_str()); @@ -1738,7 +1758,7 @@ void komodo_args(char *argv0) if ( ASSETCHAINS_LASTERA < 1 || ASSETCHAINS_LASTERA > ASSETCHAINS_MAX_ERAS ) { ASSETCHAINS_LASTERA = 1; - printf("ASSETCHAINS_LASTERA, if specified, must be between 1 and %u. ASSETCHAINS_LASTERA set to %u\n", ASSETCHAINS_MAX_ERAS, ASSETCHAINS_LASTERA); + printf("ASSETCHAINS_LASTERA, if specified, must be between 1 and %u. ASSETCHAINS_LASTERA set to %lu\n", ASSETCHAINS_MAX_ERAS, ASSETCHAINS_LASTERA); } ASSETCHAINS_LASTERA -= 1; @@ -1756,6 +1776,7 @@ void komodo_args(char *argv0) Split(GetArg("-ac_reward",""), ASSETCHAINS_REWARD, 0); Split(GetArg("-ac_halving",""), ASSETCHAINS_HALVING, 0); Split(GetArg("-ac_decay",""), ASSETCHAINS_DECAY, 0); + Split(GetArg("-ac_notarypay",""), ASSETCHAINS_NOTARY_PAY, 0); for ( int i = 0; i < ASSETCHAINS_MAX_ERAS; i++ ) { @@ -1774,13 +1795,26 @@ void komodo_args(char *argv0) MAX_BLOCK_SIGOPS = 60000; ASSETCHAINS_TXPOW = GetArg("-ac_txpow",0) & 3; ASSETCHAINS_FOUNDERS = GetArg("-ac_founders",0);// & 1; + ASSETCHAINS_FOUNDERS_REWARD = GetArg("-ac_founders_reward",0); ASSETCHAINS_SUPPLY = GetArg("-ac_supply",10); + if ( ASSETCHAINS_SUPPLY > (uint64_t)90*1000*1000000 ) + { + fprintf(stderr,"-ac_supply must be less than 90 billion\n"); + exit(0); + } + fprintf(stderr,"ASSETCHAINS_SUPPLY %llu\n",(long long)ASSETCHAINS_SUPPLY); + ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0); ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey",""); ASSETCHAINS_SCRIPTPUB = GetArg("-ac_script",""); ASSETCHAINS_BEAMPORT = GetArg("-ac_beam",0); ASSETCHAINS_CODAPORT = GetArg("-ac_coda",0); ASSETCHAINS_MARMARA = GetArg("-ac_marmara",0); + if ( ASSETCHAINS_COMMISSION != 0 && ASSETCHAINS_FOUNDERS_REWARD != 0 ) + { + fprintf(stderr,"cannot use founders reward and commission on the same chain.\n"); + exit(0); + } if ( ASSETCHAINS_CC != 0 ) { ASSETCHAINS_CCLIB = GetArg("-ac_cclib",""); @@ -1842,7 +1876,7 @@ void komodo_args(char *argv0) } // else it can be gateway coin - + if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 ) ASSETCHAINS_STAKED = 100; @@ -1863,18 +1897,32 @@ void komodo_args(char *argv0) } if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 || ASSETCHAINS_SCRIPTPUB.size() > 1 ) { + if ( ASSETCHAINS_SUPPLY > 10000000000 ) + { + printf("ac_pubkey or ac_script wont work with ac_supply over 10 billion\n"); + exit(0); + } + if ( ASSETCHAINS_NOTARY_PAY[0] != 0 ) + { + printf("Assetchains NOTARY PAY cannot be used with ac_pubkey or ac_script.\n"); + exit(0); + } if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 ) { decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str()); calc_rmd160_sha256(ASSETCHAINS_OVERRIDE_PUBKEYHASH,ASSETCHAINS_OVERRIDE_PUBKEY33,33); } - if ( ASSETCHAINS_COMMISSION == 0 ) + if ( ASSETCHAINS_COMMISSION == 0 && ASSETCHAINS_FOUNDERS != 0 ) { - if (ASSETCHAINS_FOUNDERS != 0 ) + if ( ASSETCHAINS_FOUNDERS_REWARD == 0 ) { ASSETCHAINS_COMMISSION = 53846154; // maps to 35% printf("ASSETCHAINS_COMMISSION defaulted to 35%% when founders reward active\n"); } + else + { + printf("ASSETCHAINS_FOUNDERS_REWARD set to %ld\n", ASSETCHAINS_FOUNDERS_REWARD); + } /*else if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) { //ASSETCHAINS_OVERRIDE_PUBKEY.clear(); @@ -1887,12 +1935,12 @@ void komodo_args(char *argv0) if ( ASSETCHAINS_COMMISSION != 0 ) { ASSETCHAINS_COMMISSION = 0; - printf("ASSETCHAINS_COMMISSION needs an ASETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n"); + printf("ASSETCHAINS_COMMISSION needs an ASSETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n"); } if ( ASSETCHAINS_FOUNDERS != 0 ) { ASSETCHAINS_FOUNDERS = 0; - printf("ASSETCHAINS_FOUNDERS needs an ASETCHAINS_OVERRIDE_PUBKEY\n"); + printf("ASSETCHAINS_FOUNDERS needs an ASSETCHAINS_OVERRIDE_PUBKEY or ASSETCHAINS_SCRIPTPUB\n"); } } if ( ASSETCHAINS_SCRIPTPUB.size() > 1 && ASSETCHAINS_MARMARA != 0 ) @@ -1900,7 +1948,7 @@ void komodo_args(char *argv0) fprintf(stderr,"-ac_script and -ac_marmara are mutually exclusive\n"); exit(0); } - if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_BLOCKTIME != 60 ) + if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 ) { fprintf(stderr,"perc %.4f%% ac_pub=[%02x%02x%02x...] acsize.%d\n",dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0],ASSETCHAINS_OVERRIDE_PUBKEY33[1],ASSETCHAINS_OVERRIDE_PUBKEY33[2],(int32_t)ASSETCHAINS_SCRIPTPUB.size()); extraptr = extrabuf; @@ -1909,17 +1957,20 @@ void komodo_args(char *argv0) // if we have one era, this should create the same data structure as it used to, same if we increase _MAX_ERAS for ( int i = 0; i <= ASSETCHAINS_LASTERA; i++ ) { - printf("ERA%u: end.%llu reward.%llu halving.%llu decay.%llu\n", i, + printf("ERA%u: end.%llu reward.%llu halving.%llu decay.%llu notarypay.%llu\n", i, (long long)ASSETCHAINS_ENDSUBSIDY[i], (long long)ASSETCHAINS_REWARD[i], (long long)ASSETCHAINS_HALVING[i], - (long long)ASSETCHAINS_DECAY[i]); + (long long)ASSETCHAINS_DECAY[i], + (long long)ASSETCHAINS_NOTARY_PAY[i]); // TODO: Verify that we don't overrun extrabuf here, which is a 256 byte buffer extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ENDSUBSIDY[i]),(void *)&ASSETCHAINS_ENDSUBSIDY[i]); extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_REWARD[i]),(void *)&ASSETCHAINS_REWARD[i]); extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_HALVING[i]),(void *)&ASSETCHAINS_HALVING[i]); extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_DECAY[i]),(void *)&ASSETCHAINS_DECAY[i]); + if ( ASSETCHAINS_NOTARY_PAY[0] != 0 ) + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_NOTARY_PAY[i]),(void *)&ASSETCHAINS_NOTARY_PAY[i]); } if (ASSETCHAINS_LASTERA > 0) @@ -1946,14 +1997,19 @@ void komodo_args(char *argv0) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_LWMAPOS),(void *)&ASSETCHAINS_LWMAPOS); } - val = ASSETCHAINS_COMMISSION | (((uint64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffff) << 40) | ((ASSETCHAINS_PUBLIC != 0) << 7) | ((ASSETCHAINS_PRIVATE != 0) << 6) | ASSETCHAINS_TXPOW; + val = ASSETCHAINS_COMMISSION | (((int64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffff) << 40) | ((ASSETCHAINS_PUBLIC != 0) << 7) | ((ASSETCHAINS_PRIVATE != 0) << 6) | ASSETCHAINS_TXPOW; extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val); + if ( ASSETCHAINS_FOUNDERS != 0 ) { uint8_t tmp = 1; extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(tmp),(void *)&tmp); if ( ASSETCHAINS_FOUNDERS > 1 ) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_FOUNDERS),(void *)&ASSETCHAINS_FOUNDERS); + if ( ASSETCHAINS_FOUNDERS_REWARD != 0 ) + { + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_FOUNDERS_REWARD),(void *)&ASSETCHAINS_FOUNDERS_REWARD); + } } if ( ASSETCHAINS_SCRIPTPUB.size() > 1 ) { @@ -2010,9 +2066,9 @@ void komodo_args(char *argv0) if ( ASSETCHAINS_CC >= KOMODO_FIRSTFUNGIBLEID && MAX_MONEY < 1000000LL*SATOSHIDEN ) MAX_MONEY = 1000000LL*SATOSHIDEN; - if ( MAX_MONEY <= 0 || MAX_MONEY > 10000100000LL*SATOSHIDEN ) - MAX_MONEY = 10000100000LL*SATOSHIDEN; - //fprintf(stderr,"MAX_MONEY %llu %.8f\n",(long long)MAX_MONEY,(double)MAX_MONEY/SATOSHIDEN); + if ( KOMODO_BIT63SET(MAX_MONEY) != 0 ) + MAX_MONEY = KOMODO_MAXNVALUE; + fprintf(stderr,"MAX_MONEY %llu %.8f\n",(long long)MAX_MONEY,(double)MAX_MONEY/SATOSHIDEN); //printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN); uint16_t tmpport = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen); if ( GetArg("-port",0) != 0 ) @@ -2043,7 +2099,7 @@ void komodo_args(char *argv0) if ( (port= komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL)) != 0 ) ASSETCHAINS_RPCPORT = port; else komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT + 1); - if (ASSETCHAINS_LASTERA == 0) + if (ASSETCHAINS_LASTERA == 0 || is_STAKED(ASSETCHAINS_SYMBOL) != 0) COINBASE_MATURITY = 1; //fprintf(stderr,"ASSETCHAINS_RPCPORT (%s) %u\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_RPCPORT); } @@ -2116,7 +2172,7 @@ void komodo_args(char *argv0) if ( strcmp("PIRATE",ASSETCHAINS_SYMBOL) == 0 && ASSETCHAINS_HALVING[0] == 77777 ) { ASSETCHAINS_HALVING[0] *= 5; - fprintf(stderr,"PIRATE halving changed to %d %.1f days ASSETCHAINS_LASTERA.%d\n",(int32_t)ASSETCHAINS_HALVING[0],(double)ASSETCHAINS_HALVING[0]/1440,ASSETCHAINS_LASTERA); + fprintf(stderr,"PIRATE halving changed to %d %.1f days ASSETCHAINS_LASTERA.%lu\n",(int32_t)ASSETCHAINS_HALVING[0],(double)ASSETCHAINS_HALVING[0]/1440,ASSETCHAINS_LASTERA); } else if ( strcmp("VRSC",ASSETCHAINS_SYMBOL) == 0 ) dpowconfs = 0; diff --git a/src/main.cpp b/src/main.cpp index f519cab9d..ce0760cf5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,7 +19,6 @@ ******************************************************************************/ #include "main.h" - #include "sodium.h" #include "addrman.h" @@ -48,6 +47,7 @@ #include "validationinterface.h" #include "wallet/asyncrpcoperation_sendmany.h" #include "wallet/asyncrpcoperation_shieldcoinbase.h" +#include "notaries_staked.h" #include #include @@ -186,6 +186,8 @@ namespace { std::vector vinfoBlockFile,tmpBlockFiles; int nLastBlockFile = 0; int nLastTmpFile = 0; + unsigned int maxTempFileSize0 = MAX_TEMPFILE_SIZE; + unsigned int maxTempFileSize1 = MAX_TEMPFILE_SIZE; /** Global flag to indicate we should check to see if there are * block/undo files that should be deleted. Set on startup * or if we allocate more file space when we're in prune mode @@ -1108,7 +1110,9 @@ bool ContextualCheckTransaction( if (IsExpiredTx(tx, nHeight)) { // Don't increase banscore if the transaction only just expired int expiredDosLevel = IsExpiredTx(tx, nHeight - 1) ? (dosLevel > 10 ? dosLevel : 10) : 0; - return state.DoS(expiredDosLevel, error("ContextualCheckTransaction(): transaction is expired"), REJECT_INVALID, "tx-overwinter-expired"); + string strHex = EncodeHexTx(tx); + //fprintf(stderr, "transaction exipred.%s\n",strHex.c_str()); + return state.DoS(expiredDosLevel, error("ContextualCheckTransaction(): transaction %s is expired, expiry block %i vs current block %i\n txhex.%s",tx.GetHash().ToString(),tx.nExpiryHeight,nHeight,strHex), REJECT_INVALID, "tx-overwinter-expired"); } } @@ -1257,6 +1261,9 @@ bool CheckTransaction(uint32_t tiptime,const CTransaction& tx, CValidationState } } +extern char NOTARYADDRS[64][36]; +extern uint8_t NUM_NOTARIES; + int32_t komodo_isnotaryvout(char *coinaddr) // from ac_private chains only { static int32_t didinit; static char notaryaddrs[sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) + 1][64]; @@ -1274,8 +1281,8 @@ int32_t komodo_isnotaryvout(char *coinaddr) // from ac_private chains only didinit = 1; } for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++) - if ( strcmp(coinaddr,notaryaddrs[i]) == 0 ) - return(1); + if ( strcmp(coinaddr,notaryaddrs[i]) == 0 ) + return(1); return(0); } @@ -1329,9 +1336,10 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio // Transactions containing empty `vin` must have either non-empty // `vjoinsplit` or non-empty `vShieldedSpend`. - if (tx.vin.empty() && tx.vjoinsplit.empty() && tx.vShieldedSpend.empty()) + if (tx.vin.empty() && tx.vjoinsplit.empty() && tx.vShieldedSpend.empty()) return state.DoS(10, error("CheckTransaction(): vin empty"), REJECT_INVALID, "bad-txns-vin-empty"); + // Transactions containing empty `vout` must have either non-empty // `vjoinsplit` or non-empty `vShieldedOutput`. if (tx.vout.empty() && tx.vjoinsplit.empty() && tx.vShieldedOutput.empty()) @@ -1588,7 +1596,6 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree) { - extern int32_t KOMODO_ON_DEMAND; { LOCK(mempool.cs); uint256 hash = tx.GetHash(); @@ -1801,7 +1808,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa CAmount nValueOut = tx.GetValueOut(); CAmount nFees = nValueIn-nValueOut; double dPriority = view.GetPriority(tx, chainActive.Height()); - + if ( nValueOut > 777777*COIN && KOMODO_VALUETOOBIG(nValueOut - 777777*COIN) != 0 ) // some room for blockreward and txfees + return state.DoS(100, error("AcceptToMemoryPool: GetValueOut too big"),REJECT_INVALID,"tx valueout is too big"); + // Keep track of transactions that spend a coinbase, which we re-scan // during reorgs to ensure COINBASE_MATURITY is still met. bool fSpendsCoinbase = false; @@ -1845,7 +1854,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Continuously rate-limit free (really, very-low-fee) transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize)) + if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.IsCoinImport()) { static CCriticalSection csFreeLimiter; static double dFreeCount; @@ -2076,14 +2085,14 @@ bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlo memset(&hashBlock,0,sizeof(hashBlock)); // need a GetTransaction without lock so the validation code for assets can run without deadlock { - //fprintf(stderr,"check mempool\n"); + //fprintf(stderr,"check mempool %s\n",hash.GetHex().c_str()); if (mempool.lookup(hash, txOut)) { //fprintf(stderr,"found in mempool\n"); return true; } } - //fprintf(stderr,"check disk\n"); + //fprintf(stderr,"check disk %s\n",hash.GetHex().c_str()); if (fTxIndex) { CDiskTxPos postx; @@ -2105,11 +2114,11 @@ bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlo hashBlock = header.GetHash(); if (txOut.GetHash() != hash) return error("%s: txid mismatch", __func__); - //fprintf(stderr,"found on disk\n"); + //fprintf(stderr,"found on disk %s\n",hash.GetHex().c_str()); return true; } } - //fprintf(stderr,"not found\n"); + //fprintf(stderr,"not found on disk %s\n",hash.GetHex().c_str()); return false; } @@ -2269,8 +2278,9 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW) extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS]; extern uint32_t ASSETCHAINS_MAGIC; -extern uint64_t ASSETCHAINS_STAKED,ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; +extern uint64_t ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; extern uint8_t ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE; +extern int32_t ASSETCHAINS_STAKED; CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) { @@ -2835,7 +2845,7 @@ namespace { hasher << hashBlock; hasher << blockundo; fileout << hasher.GetHash(); - +//fprintf(stderr,"hashBlock.%s hasher.%s\n",hashBlock.GetHex().c_str(),hasher.GetHash().GetHex().c_str()); return true; } @@ -2860,7 +2870,7 @@ namespace { hasher << hashBlock; hasher << blockundo; if (hashChecksum != hasher.GetHash()) - return error("%s: Checksum mismatch", __func__); + return error("%s: %s Checksum mismatch %s vs %s", __func__,hashBlock.GetHex().c_str(),hashChecksum.GetHex().c_str(),hasher.GetHash().GetHex().c_str()); return true; } @@ -3248,6 +3258,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin auto verifier = libzcash::ProofVerifier::Strict(); auto disabledVerifier = libzcash::ProofVerifier::Disabled(); int32_t futureblock; + CAmount blockReward = 0; // Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in if (!CheckBlock(&futureblock,pindex->GetHeight(),pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, fCheckPOW, !fJustCheck) || futureblock != 0 ) { @@ -3262,6 +3273,36 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return false; fprintf(stderr,"grandfathered exception, until jan 15th 2019\n"); } + // Do this here before the block is moved to the main block files. + if ( ASSETCHAINS_NOTARY_PAY[0] != 0 && pindex->GetHeight() > 10 ) + { + // 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); + // -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!"), + REJECT_INVALID, "bad-notarization-position"); + // 1 means this block contains a valid notarisation and its in position 1. + // its no longer possible for any attempted notarization to be in a block with a valid one! + // if notaries create a notarisation even if its not in this chain it will need to be mined inside its own block! + if ( notarisationTx == 1 ) + { + // Check if the notaries have been paid. + if ( block.vtx[0].vout.size() == 1 ) + return state.DoS(100, error("ConnectBlock(): Notaries have not been paid!"), + REJECT_INVALID, "bad-cb-amount"); + // calculate the notaries compensation and validate the amounts and pubkeys are correct. + uint64_t notarypaycheque = komodo_checknotarypay((CBlock *)&block,(int32_t)pindex->GetHeight()); + fprintf(stderr, "notarypaycheque.%lu\n", notarypaycheque); + if ( notarypaycheque > 0 ) + blockReward += notarypaycheque; + else + return state.DoS(100, error("ConnectBlock(): Notary pay validation failed!"), + REJECT_INVALID, "bad-cb-amount"); + } + } + // Move the block to the main block file, we need this to create the TxIndex in the following loop. if ( (pindex->nStatus & BLOCK_IN_TMPFILE) != 0 ) { unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); @@ -3275,7 +3316,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("AcceptBlock(): ReceivedBlockTransactions failed"); setDirtyFileInfo.insert(blockPos.nFile); - fprintf(stderr,"added ht.%d copy of tmpfile to %d.%d\n",pindex->GetHeight(),blockPos.nFile,blockPos.nPos); + //fprintf(stderr,"added ht.%d copy of tmpfile to %d.%d\n",pindex->GetHeight(),blockPos.nFile,blockPos.nPos); } // verify that the view's current state corresponds to the previous block uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); @@ -3332,7 +3373,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin int64_t nTimeStart = GetTimeMicros(); CAmount nFees = 0; int nInputs = 0; - int64_t interest,sum = 0; + uint64_t valueout; + int64_t voutsum = 0,prevsum=0,interest,sum = 0; unsigned int nSigOps = 0; CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector > vPos; @@ -3383,6 +3425,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin { if (!view.HaveInputs(tx)) { + fprintf(stderr, "Connect Block missing inputs tx_number.%d \nvin txid.%s vout.%d \n",i,tx.vin[0].prevout.hash.ToString().c_str(),tx.vin[0].prevout.n); return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), REJECT_INVALID, "bad-txns-inputs-missingorspent"); } @@ -3390,6 +3433,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!view.HaveJoinSplitRequirements(tx)) return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"), REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met"); + if (fAddressIndex || fSpentIndex) { for (size_t j = 0; j < tx.vin.size(); j++) { @@ -3449,9 +3493,25 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin txdata.emplace_back(tx); + valueout = tx.GetValueOut(); + if ( KOMODO_VALUETOOBIG(valueout) != 0 ) + { + fprintf(stderr,"valueout %.8f too big\n",(double)valueout/COIN); + return state.DoS(100, error("ConnectBlock(): GetValueOut too big"),REJECT_INVALID,"tx valueout is too big"); + } + prevsum = voutsum; + voutsum += valueout; + /*if ( KOMODO_VALUETOOBIG(voutsum) != 0 ) + { + fprintf(stderr,"voutsum %.8f too big\n",(double)voutsum/COIN); + return state.DoS(100, error("ConnectBlock(): voutsum too big"),REJECT_INVALID,"tx valueout is too big"); + } + else + if ( voutsum < prevsum ) // PRLPAY overflows this and it isnt a conclusive test anyway + return state.DoS(100, error("ConnectBlock(): voutsum less after adding valueout"),REJECT_INVALID,"tx valueout is too big");*/ if (!tx.IsCoinBase()) { - nFees += view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime) - tx.GetValueOut(); + nFees += view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime) - valueout; sum += interest; std::vector vChecks; @@ -3542,8 +3602,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart; LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); - CAmount blockReward = nFees + GetBlockSubsidy(pindex->GetHeight(), chainparams.GetConsensus()) + sum; - if ( ASSETCHAINS_COMMISSION != 0 ) //ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && + blockReward += nFees + GetBlockSubsidy(pindex->GetHeight(), chainparams.GetConsensus()) + sum; + if ( ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 ) //ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && { uint64_t checktoshis; if ( (checktoshis= komodo_commission((CBlock *)&block,(int32_t)pindex->GetHeight())) != 0 ) @@ -3563,6 +3623,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin { if ( ASSETCHAINS_SYMBOL[0] != 0 || pindex->GetHeight() >= KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) { + //fprintf(stderr, "coinbase pays too much\n"); + //sleepflag = true; return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), @@ -3579,9 +3641,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return true; // Write undo information to disk + //fprintf(stderr,"nFile.%d isNull %d vs isvalid %d nStatus %x\n",(int32_t)pindex->nFile,pindex->GetUndoPos().IsNull(),pindex->IsValid(BLOCK_VALID_SCRIPTS),(uint32_t)pindex->nStatus); if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) { - if (pindex->GetUndoPos().IsNull()) { + if (pindex->GetUndoPos().IsNull()) + { CDiskBlockPos pos; if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) return error("ConnectBlock(): FindUndoPos failed"); @@ -3589,12 +3653,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin fprintf(stderr,"ConnectBlock: unexpected null pprev\n"); if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) return AbortNode(state, "Failed to write undo data"); - // update nUndoPos in block index pindex->nUndoPos = pos.nPos; pindex->nStatus |= BLOCK_HAVE_UNDO; } - + // Now that all consensus rules have been validated, set nCachedBranchId. // Move this if BLOCK_VALID_CONSENSUS is ever altered. static_assert(BLOCK_VALID_CONSENSUS == BLOCK_VALID_SCRIPTS, @@ -3605,12 +3668,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } else if (pindex->pprev) { pindex->nCachedBranchId = pindex->pprev->nCachedBranchId; } - + pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); setDirtyBlockIndex.insert(pindex); } - ConnectNotarisations(block, pindex->GetHeight()); + ConnectNotarisations(block, pindex->GetHeight()); // MoMoM notarisation DB. if (fTxIndex) if (!pblocktree->WriteTxIndex(vPos)) @@ -3666,7 +3729,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeCallbacks * 0.000001); //FlushStateToDisk(); - komodo_connectblock(pindex,*(CBlock *)&block); + komodo_connectblock(false,pindex,*(CBlock *)&block); // dPoW state update. return true; } @@ -3736,7 +3799,8 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { std::vector > vFiles; vFiles.reserve(setDirtyFileInfo.size()); for (set::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) { - vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it])); + if ( *it < TMPFILE_START ) + vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it])); setDirtyFileInfo.erase(it++); } std::vector vBlocks; @@ -3854,8 +3918,8 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { return AbortNode(state, "Failed to read block"); //if ( ASSETCHAINS_SYMBOL[0] != 0 || pindexDelete->GetHeight() > 1400000 ) { - int32_t prevMoMheight; uint256 notarizedhash,txid; - komodo_notarized_height(&prevMoMheight,¬arizedhash,&txid); + int32_t notarizedht,prevMoMheight; uint256 notarizedhash,txid; + notarizedht = komodo_notarized_height(&prevMoMheight,¬arizedhash,&txid); if ( block.GetHash() == notarizedhash ) { fprintf(stderr,"DisconnectTip trying to disconnect notarized block at ht.%d\n",(int32_t)pindexDelete->GetHeight()); @@ -3921,13 +3985,17 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), newSaplingTree)); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: + std::vector TxToRemove; for (int i = 0; i < block.vtx.size(); i++) { 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))) { - EraseFromWallets(tx.GetHash()); +#ifdef ENABLE_WALLET + LOCK2(cs_main, pwalletMain->cs_wallet); + pwalletMain->EraseFromWallet(tx.GetHash()); +#endif } else { @@ -4209,6 +4277,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo ASSETCHAINS_SYMBOL,pindexFork->phashBlock->GetHex(), pindexFork->GetHeight()) + "\n\n" + _("Please help, human!"); LogPrintf("*** %s\nif you launch with -maxreorg=%d it might be able to resolve this automatically", msg,reorgLength+10); + fprintf(stderr,"*** %s\nif you launch with -maxreorg=%d it might be able to resolve this automatically", msg.c_str(),reorgLength+10); uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); StartShutdown(); return false; @@ -4578,12 +4647,20 @@ bool FindBlockPos(int32_t tmpflag,CValidationState &state, CDiskBlockPos &pos, u std::vector *ptr; int *lastfilep; LOCK(cs_LastBlockFile); - unsigned int nFile; + unsigned int nFile,maxTempFileSize; + if ( tmpflag != 0 ) { ptr = &tmpBlockFiles; nFile = nLastTmpFile; lastfilep = &nLastTmpFile; + if (tmpBlockFiles.size() <= nFile) { + tmpBlockFiles.resize(nFile + 1); + } + if ( nFile == 0 ) + maxTempFileSize = maxTempFileSize0; + else if ( nFile == 1 ) + maxTempFileSize = maxTempFileSize1; } else { @@ -4594,25 +4671,89 @@ bool FindBlockPos(int32_t tmpflag,CValidationState &state, CDiskBlockPos &pos, u vinfoBlockFile.resize(nFile + 1); } } + if (!fKnown) { - while ((*ptr)[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { + bool tmpfileflag = false; + while ( (*ptr)[nFile].nSize + nAddSize >= ((tmpflag != 0) ? maxTempFileSize : MAX_BLOCKFILE_SIZE) ) { + if ( tmpflag != 0 && tmpfileflag ) + break; nFile++; if ((*ptr).size() <= nFile) { (*ptr).resize(nFile + 1); } + tmpfileflag = true; } pos.nFile = nFile + tmpflag*TMPFILE_START; pos.nPos = (*ptr)[nFile].nSize; - if ( 0 && tmpflag != 0 ) - fprintf(stderr,"pos.nFile %d nPos %u\n",pos.nFile,pos.nPos); } - if (nFile != *lastfilep) { if (!fKnown) { LogPrintf("Leaving block file %i: %s\n", nFile, (*ptr)[nFile].ToString()); } FlushBlockFile(!fKnown); + //fprintf(stderr, "nFile = %i size.%li maxTempFileSize0.%u maxTempFileSize1.%u\n",nFile,tmpBlockFiles.size(),maxTempFileSize0,maxTempFileSize1); + if ( tmpflag != 0 && tmpBlockFiles.size() >= 3 ) + { + if ( nFile == 1 ) // Trying to get to second temp file. + { + if (!PruneOneBlockFile(true,TMPFILE_START+1)) + { + // file 1 is not ready to be used yet increase file 0's size. + fprintf(stderr, "Cant clear file 1!\n"); + // We will reset the position to the end of the first file, even if its over max size. + nFile = 0; + pos.nFile = TMPFILE_START; + pos.nPos = (*ptr)[0].nSize; + // Increase temp file one's max size by a chunk, so we wait a reasonable time to recheck the other file. + maxTempFileSize0 += BLOCKFILE_CHUNK_SIZE; + } + else + { + // The file 1 is able to be used now. Reset max size, and set nfile to use file 1. + fprintf(stderr, "CLEARED file 1!\n"); + maxTempFileSize0 = MAX_TEMPFILE_SIZE; + nFile = 1; + tmpBlockFiles[1].SetNull(); + pos.nFile = TMPFILE_START+1; + pos.nPos = (*ptr)[1].nSize; + boost::filesystem::remove(GetBlockPosFilename(pos, "blk")); + LogPrintf("Prune: deleted temp blk (%05u)\n",nFile); + } + if ( 0 && tmpflag != 0 ) + fprintf(stderr,"pos.nFile %d nPos %u\n",pos.nFile,pos.nPos); + } + else if ( nFile == 2 ) // Trying to get to third temp file. + { + if (!PruneOneBlockFile(true,TMPFILE_START)) + { + fprintf(stderr, "Cant clear file 0!\n"); + // We will reset the position to the end of the second block file, even if its over max size. + nFile = 1; + pos.nFile = TMPFILE_START+1; + pos.nPos = (*ptr)[1].nSize; + // Increase temp file one's max size by a chunk, so we wait a reasonable time to recheck the other file. + maxTempFileSize1 += BLOCKFILE_CHUNK_SIZE; + } + else + { + // The file 0 is able to be used now. Reset max size, and set nfile to use file 0. + fprintf(stderr, "CLEARED file 0!\n"); + maxTempFileSize1 = MAX_TEMPFILE_SIZE; + nFile = 0; + tmpBlockFiles[0].SetNull(); + pos.nFile = TMPFILE_START; + pos.nPos = (*ptr)[0].nSize; + boost::filesystem::remove(GetBlockPosFilename(pos, "blk")); + LogPrintf("Prune: deleted temp blk (%05u)\n",nFile); + } + if ( 0 && tmpflag != 0 ) + fprintf(stderr,"pos.nFile %d nPos %u\n",pos.nFile,pos.nPos); + } + //sleep(30); + } + //fprintf(stderr, "nFile = %i size.%li maxTempFileSize0.%u maxTempFileSize1.%u\n",nFile,tmpBlockFiles.size(),maxTempFileSize0,maxTempFileSize1); sleep(30); *lastfilep = nFile; + //fprintf(stderr, "*lastfilep = %i\n",*lastfilep); } (*ptr)[nFile].AddBlock(nHeight, nTime); @@ -4884,6 +5025,7 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C if (!CheckTransaction(tiptime,tx, state, verifier)) return error("CheckBlock: CheckTransaction failed"); } + unsigned int nSigOps = 0; BOOST_FOREACH(const CTransaction& tx, block.vtx) { @@ -5209,7 +5351,12 @@ bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, C } int nHeight = pindex->GetHeight(); + // Temp File fix. LABS has been using this for ages with no bad effects. + // Disabled here. Set use tmp to whatever you need to use this for. int32_t usetmp = 0; + if ( IsInitialBlockDownload() ) + usetmp = 0; + // Write block to history file try { unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); @@ -5344,6 +5491,27 @@ bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNo komodo_currentheight_set(chainActive.LastTip()->GetHeight()); checked = CheckBlock(&futureblock,height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier,0); bool fRequested = MarkBlockAsReceived(hash); + // Test thing on LABS to test viability of rejecting a node pushing a chain. + // Supposed to stop malicious forks being pushed. Untested. Disabled incase of problems it may cause. + if ( 0 && pfrom && !fRequested && vNodes.size() > 1 ) + { + pfrom->nBlocksinARow += 1; + if ( pfrom->nBlocksinARow >= 10 ) + { + pfrom->nBlocksinARow2 += 1; + if ( pfrom->nBlocksinARow2 > 5 ) + { + pfrom->nBlocksinARow = 0; + pfrom->nBlocksinARow2 = 0; + fprintf(stderr, "reset node.%i\n",(int32_t)pfrom->GetId()); + } + else + { + fprintf(stderr, "Requesting new peer node.%i blocksinrow.%i blocsinrow2.%i\n",(int32_t)pfrom->GetId(),pfrom->nBlocksinARow,pfrom->nBlocksinARow2); + return(false); + } + } + } fRequested |= fForceProcessing; if ( checked != 0 && komodo_checkPOW(0,pblock,height) < 0 ) //from_miner && ASSETCHAINS_STAKED == 0 { @@ -5440,35 +5608,63 @@ uint64_t CalculateCurrentUsage() } /* Prune a block file (modify associated database entries)*/ -void PruneOneBlockFile(const int fileNumber) +bool PruneOneBlockFile(bool tempfile, const int fileNumber) { - for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it) { + uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height; + notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); + //fprintf(stderr, "pruneblockfile.%i\n",fileNumber); sleep(15); + for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it) + { CBlockIndex* pindex = it->second; - if (pindex && pindex->nFile == fileNumber) { + if (pindex && pindex->nFile == fileNumber) + { + if ( tempfile && (pindex->nStatus & BLOCK_IN_TMPFILE != 0) ) + { + if ( chainActive.Contains(pindex) ) + { + // Block is in main chain so we cant clear this file! + return(false); + } + fprintf(stderr, "pindex height.%i notarized height.%i \n", pindex->GetHeight(), notarized_height); + if ( pindex->GetHeight() > notarized_height ) // Need to check this, does an invalid block have a height? + { + // This blocks height is not older than last notarization so it can be reorged into the main chain. + // We cant clear this file! + return(false); + } + else + { + // Block is not in main chain and is older than last notarised block so its safe for removal. + fprintf(stderr, "Block [%i] in tempfile.%i We can clear this block!\n",pindex->GetHeight(),fileNumber); + // Add index to list and remove after loop? + } + } pindex->nStatus &= ~BLOCK_HAVE_DATA; pindex->nStatus &= ~BLOCK_HAVE_UNDO; pindex->nFile = 0; pindex->nDataPos = 0; pindex->nUndoPos = 0; setDirtyBlockIndex.insert(pindex); - // Prune from mapBlocksUnlinked -- any block we prune would have // to be downloaded again in order to consider its chain, at which // point it would be considered as a candidate for // mapBlocksUnlinked or setBlockIndexCandidates. std::pair::iterator, std::multimap::iterator> range = mapBlocksUnlinked.equal_range(pindex->pprev); - while (range.first != range.second) { + while (range.first != range.second) + { std::multimap::iterator it = range.first; range.first++; - if (it->second == pindex) { + if (it->second == pindex) + { mapBlocksUnlinked.erase(it); } } } } - - vinfoBlockFile[fileNumber].SetNull(); + if (!tempfile) + vinfoBlockFile[fileNumber].SetNull(); setDirtyFileInfo.insert(fileNumber); + return(true); } @@ -5515,7 +5711,7 @@ void FindFilesToPrune(std::set& setFilesToPrune) if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) continue; - PruneOneBlockFile(fileNumber); + PruneOneBlockFile(false, fileNumber); // Queue up the files for removal setFilesToPrune.insert(fileNumber); nCurrentUsage -= nBytesToPrune; @@ -6689,7 +6885,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } -//fprintf(stderr,"netmsg: %s\n", strCommand.c_str()); + //fprintf(stderr,"netmsg: %s\n", strCommand.c_str()); if (strCommand == "version") { @@ -6706,16 +6902,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CAddress addrFrom; uint64_t nNonce = 1; int nVersion; // use temporary for version, don't set version number until validated as connected + int minVersion = MIN_PEER_PROTO_VERSION; + if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 ) + minVersion = STAKEDMIN_PEER_PROTO_VERSION; vRecv >> nVersion >> pfrom->nServices >> nTime >> addrMe; if (nVersion == 10300) nVersion = 300; - - if (nVersion < MIN_PEER_PROTO_VERSION) + if (nVersion < minVersion) { // disconnect from peers older than this proto version LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)); + strprintf("Version must be %d or greater", minVersion)); pfrom->fDisconnect = true; return false; } diff --git a/src/main.h b/src/main.h index d19e3aa17..f12bcb8cd 100644 --- a/src/main.h +++ b/src/main.h @@ -90,7 +90,8 @@ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; /** Default for -txexpirydelta, in number of blocks */ static const unsigned int DEFAULT_TX_EXPIRY_DELTA = 20; /** The maximum size of a blk?????.dat file (since 0.8) */ -static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB +static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB +static const unsigned int MAX_TEMPFILE_SIZE = 0x1000000; // 16 MiB 0x8000000 /** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB /** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ @@ -807,6 +808,7 @@ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHea bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos,bool checkPOW); bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW); bool RemoveOrphanedBlocks(int32_t notarized_height); +bool PruneOneBlockFile(bool tempfile, const int fileNumber); /** Functions for validating blocks and updating the block tree */ diff --git a/src/metrics.cpp b/src/metrics.cpp index 6b387f7dc..1fa8ebfb5 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -136,7 +136,7 @@ int64_t GetUptime() double GetLocalSolPS() { - if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH) + if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH || ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASHV1_1) { return miningTimer.rate(nHashCount); } diff --git a/src/miner.cpp b/src/miner.cpp index 7ffcaebc2..2069e5a8c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -55,6 +55,8 @@ #include "sodium.h" +#include "notaries_staked.h" + #include #include #ifdef ENABLE_MINING @@ -128,8 +130,8 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams); } } - #include "komodo_defs.h" +#include "cc/CCinclude.h" extern CCriticalSection cs_metrics; void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len); @@ -147,9 +149,12 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig, CPubKey &pk); int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33); int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); +int32_t komodo_is_notarytx(const CTransaction& tx); CScript Marmara_scriptPubKey(int32_t height,CPubKey pk); CScript MarmaraCoinbaseOpret(uint8_t funcid,int32_t height,CPubKey pk); -bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey); +uint64_t komodo_notarypay(CMutableTransaction &txNew, std::vector &NotarisationNotaries, uint32_t timestamp, int32_t height, uint8_t *script, int32_t len); +int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); +int32_t komodo_getnotarizedheight(uint32_t timestamp,int32_t height, uint8_t *script, int32_t len); CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake) { @@ -168,7 +173,9 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 } } else pk = _pk; - uint64_t deposits; int32_t isrealtime,kmdheight; uint32_t blocktime; const CChainParams& chainparams = Params(); + uint64_t deposits,voutsum=0; int32_t isrealtime,kmdheight; uint32_t blocktime; const CChainParams& chainparams = Params(); + bool fNotarisationBlock = false; std::vector NotarisationNotaries; + //fprintf(stderr,"create new block\n"); // Create new block if ( gpucount < 0 ) @@ -211,7 +218,8 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 // we will attempt to spend any cheats we see CTransaction cheatTx; boost::optional cheatSpend; - uint256 cbHash; + + uint256 cbHash; CBlockIndex* pindexPrev = 0; { @@ -225,6 +233,8 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); uint32_t proposedTime = GetAdjustedTime(); + voutsum = GetBlockSubsidy(nHeight,consensusParams) + 10000*COIN; // approx fees + if (proposedTime == nMedianTimePast) { // too fast or stuck, this addresses the too fast issue, while moving @@ -237,6 +247,13 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 } } pblock->nTime = GetAdjustedTime(); + // Now we have the block time + height, we can get the active notaries. + int8_t numSN = 0; uint8_t notarypubkeys[64][33] = {0}; + if ( ASSETCHAINS_NOTARY_PAY[0] != 0 ) + { + // Only use speical miner for notary pay chains. + numSN = komodo_notaries(notarypubkeys, nHeight, pblock->nTime); + } CCoinsViewCache view(pcoinsTip); uint32_t expired; uint64_t commission; @@ -254,6 +271,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 vecPriority.reserve(mempool.mapTx.size() + 1); // now add transactions from the mem pool + int32_t Notarisations = 0; uint64_t txvalue; for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { @@ -268,7 +286,12 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 //fprintf(stderr,"coinbase.%d finaltx.%d expired.%d\n",tx.IsCoinBase(),IsFinalTx(tx, nHeight, nLockTimeCutoff),IsExpiredTx(tx, nHeight)); continue; } - + txvalue = tx.GetValueOut(); + if ( KOMODO_VALUETOOBIG(txvalue) != 0 ) + continue; + if ( KOMODO_VALUETOOBIG(txvalue + voutsum) != 0 ) + continue; + voutsum += txvalue; if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,0) < 0 ) { //fprintf(stderr,"CreateNewBlock: komodo_validate_interest failure nHeight.%d nTime.%u vs locktime.%u\n",nHeight,(uint32_t)pblock->nTime,(uint32_t)tx.nLockTime); @@ -280,12 +303,18 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 CAmount nTotalIn = 0; bool fMissingInputs = false; bool fNotarisation = false; + std::vector TMP_NotarisationNotaries; if (tx.IsCoinImport()) { - CAmount nValueIn = GetCoinImportValue(tx); + CAmount nValueIn = GetCoinImportValue(tx); // burn amount nTotalIn += nValueIn; - dPriority += (double)nValueIn * 1000; // flat multiplier + dPriority += (double)nValueIn * 1000; // flat multiplier... max = 1e16. } else { + TMP_NotarisationNotaries.clear(); + bool fToCryptoAddress = false; + if ( numSN != 0 && notarypubkeys[0][0] != 0 && komodo_is_notarytx(tx) == 1 ) + fToCryptoAddress = true; + BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Read prev transaction @@ -323,9 +352,33 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 nTotalIn += nValueIn; int nConf = nHeight - coins->nHeight; - + + uint8_t *script; int32_t scriptlen; uint256 hash; CTransaction tx1; + // loop over notaries array and extract index of signers. + if ( fToCryptoAddress && GetTransaction(txin.prevout.hash,tx1,hash,false) ) + { + for (int8_t i = 0; i < numSN; i++) + { + script = (uint8_t *)&tx1.vout[txin.prevout.n].scriptPubKey[0]; + scriptlen = (int32_t)tx1.vout[txin.prevout.n].scriptPubKey.size(); + if ( scriptlen == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && memcmp(script+1,notarypubkeys[i],33) == 0 ) + { + // We can add the index of each notary to vector, and clear it if this notarisation is not valid later on. + TMP_NotarisationNotaries.push_back(i); + } + } + } dPriority += (double)nValueIn * nConf; } + if ( numSN != 0 && TMP_NotarisationNotaries.size() >= numSN / 5 ) + { + // check a notary didnt sign twice (this would be an invalid notarisation later on and cause problems) + std::set checkdupes( TMP_NotarisationNotaries.begin(), TMP_NotarisationNotaries.end() ); + if ( checkdupes.size() != TMP_NotarisationNotaries.size() ) + { + fprintf(stderr, "possible notarisation is signed multiple times by same notary, passed as normal transaction.\n"); + } else fNotarisation = true; + } nTotalIn += tx.GetShieldedValueIn(); } @@ -340,6 +393,40 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize); + if ( fNotarisation ) + { + // Special miner for notary pay chains. Can only enter this if numSN/notarypubkeys is set higher up. + if ( tx.vout.size() == 2 && tx.vout[1].nValue == 0 ) + { + // Get the OP_RETURN for the notarisation + uint8_t *script = (uint8_t *)&tx.vout[1].scriptPubKey[0]; + int32_t scriptlen = (int32_t)tx.vout[1].scriptPubKey.size(); + if ( script[0] == OP_RETURN ) + { + Notarisations++; + if ( Notarisations > 1 ) + { + fprintf(stderr, "skipping notarization.%d\n",Notarisations); + // Any attempted notarization needs to be in its own block! + continue; + } + int32_t notarizedheight = komodo_getnotarizedheight(pblock->nTime, nHeight, script, scriptlen); + if ( notarizedheight != 0 ) + { + // this is the first one we see, add it to the block as TX1 + NotarisationNotaries = TMP_NotarisationNotaries; + dPriority = 1e16; + fNotarisationBlock = true; + fprintf(stderr, "Notarisation %s set to maximum priority\n",hash.ToString().c_str()); + } + } + } + } + else if ( dPriority == 1e16 ) + { + dPriority -= 10; + // make sure notarisation is tx[1] in block. + } if (porphan) { porphan->dPriority = dPriority; @@ -473,7 +560,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 int32_t stakeHeight = chainActive.Height() + 1; - //LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits); + //LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x stake.%i\n", nBlockSize,blocktime,pblock->nBits,isStake); if ( ASSETCHAINS_SYMBOL[0] != 0 && isStake ) { LEAVE_CRITICAL_SECTION(cs_main); @@ -499,6 +586,21 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 //if ( blocktime > pindexPrev->GetMedianTimePast()+60 ) // blocktime = pindexPrev->GetMedianTimePast() + 60; siglen = komodo_staked(txStaked, pblock->nBits, &blocktime, &txtime, &utxotxid, &utxovout, &utxovalue, utxosig); + // if you skip this check it will create a block too far into the future and not pass ProcessBlock or AcceptBlock. + // This has been moved from the mining loop to save CPU, and to also make ac_staked work with the verus miner. + while ( blocktime-57 > GetAdjustedTime() ) + { + sleep(1); + if ( (rand() % 100) < 1 ) + fprintf(stderr, "%u seconds until elegible, waiting.\n", blocktime-((uint32_t)GetAdjustedTime()+57)); + if ( chainActive.LastTip()->GetHeight() >= stakeHeight ) + { + fprintf(stderr, "Block Arrived, reset staking loop.\n"); + return(0); + } + if( !GetBoolArg("-gen",false) ) + return(0); + } } if ( siglen > 0 ) @@ -512,9 +614,10 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked)); nFees += txfees; pblock->nTime = blocktime; -printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeight()+1,blocktime,(uint32_t)(GetAdjustedTime() - (blocktime-13))); - } else return(0); //fprintf(stderr,"no utxos eligible for staking\n"); + //printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeight()+1,blocktime,(uint32_t)(GetAdjustedTime() - (blocktime-13))); + } else return(0); //fprintf(stderr,"no utxos eligible for staking\n"); } + // Create coinbase tx CMutableTransaction txNew = CreateNewContextualCMutableTransaction(consensusParams, nHeight); txNew.vin.resize(1); @@ -524,7 +627,7 @@ printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeigh txNew.vout.resize(1); txNew.vout[0].scriptPubKey = scriptPubKeyIn; txNew.vout[0].nValue = GetBlockSubsidy(nHeight,consensusParams) + nFees; - + //fprintf(stderr,"mine ht.%d with %.8f\n",nHeight,(double)txNew.vout[0].nValue/COIN); txNew.nExpiryHeight = 0; txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); @@ -541,7 +644,7 @@ printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeigh txNew.vout[1].nValue = 0; txNew.vout[1].scriptPubKey = MarmaraCoinbaseOpret('C',nHeight,pk); } - else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0 ) + else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0 ) { int32_t i; uint8_t *ptr; txNew.vout.resize(2); @@ -584,6 +687,11 @@ printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeigh if (scriptPubKeyIn.IsPayToScriptHash() || scriptPubKeyIn.IsPayToCryptoCondition()) { fprintf(stderr,"CreateNewBlock: attempt to add timelock to pay2sh or pay2cc\n"); + if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) ) + { + LEAVE_CRITICAL_SECTION(cs_main); + LEAVE_CRITICAL_SECTION(mempool.cs); + } return 0; } @@ -592,7 +700,29 @@ printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeigh txNew.vout[0].scriptPubKey = CScriptExt().PayToScriptHash(CScriptID(opretScript)); txNew.vout[1].scriptPubKey = CScriptExt().OpReturnScript(opretScript, OPRETTYPE_TIMELOCK); txNew.vout[1].nValue = 0; - } // timelocks and commissions are currently incompatible due to validation complexity of the combination + // timelocks and commissions are currently incompatible due to validation complexity of the combination + } + else if ( fNotarisationBlock && ASSETCHAINS_NOTARY_PAY[0] != 0 && pblock->vtx[1].vout.size() == 2 && pblock->vtx[1].vout[1].nValue == 0 ) + { + // Get the OP_RETURN for the notarisation + uint8_t *script = (uint8_t *)&pblock->vtx[1].vout[1].scriptPubKey[0]; + int32_t scriptlen = (int32_t)pblock->vtx[1].vout[1].scriptPubKey.size(); + if ( script[0] == OP_RETURN ) + { + uint64_t totalsats = komodo_notarypay(txNew, NotarisationNotaries, pblock->nTime, nHeight, script, scriptlen); + if ( totalsats == 0 ) + { + fprintf(stderr, "Could not create notary payment, trying again.\n"); + if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) ) + { + LEAVE_CRITICAL_SECTION(cs_main); + LEAVE_CRITICAL_SECTION(mempool.cs); + } + return(0); + } + fprintf(stderr, "Created notary payment coinbase totalsat.%lu\n",totalsats); + } else fprintf(stderr, "vout 2 of notarisation is not OP_RETURN scriptlen.%i\n", scriptlen); + } pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; @@ -790,17 +920,15 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, scriptPubKey.resize(35); ptr = (uint8_t *)pubkey.begin(); scriptPubKey[0] = 33; - for (i=0; i<33; i++) + for (i=0; i<33; i++) { scriptPubKey[i+1] = ptr[i]; + } scriptPubKey[34] = OP_CHECKSIG; - //scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; } } if ( ASSETCHAINS_MARMARA != 0 && nHeight > 0 && (nHeight & 1) == 0 ) scriptPubKey = Marmara_scriptPubKey(nHeight,pubkey); - if ( ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0 ) - isStake = true; - return CreateNewBlock(pubkey,scriptPubKey, gpucount, isStake); + return CreateNewBlock(pubkey, scriptPubKey, gpucount, isStake); } void komodo_broadcast(CBlock *pblock,int32_t limit) @@ -1196,14 +1324,14 @@ void static BitcoinMiner_noeq() miningTimer.start(); #ifdef ENABLE_WALLET - CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, Mining_height, ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0); + CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, Mining_height, 0, ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0); #else CBlockTemplate *ptr = CreateNewBlockWithKey(); #endif if ( ptr == 0 ) { static uint32_t counter; - if ( counter++ < 10 ) + if ( ASSETCHAINS_STAKED == 0 && counter++ < 10 ) fprintf(stderr,"created illegal block, retry\n"); continue; } @@ -1246,6 +1374,7 @@ void static BitcoinMiner_noeq() pblock->nSolution = solnPlaceholder; savebits = pblock->nBits; arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); + HASHTarget = arith_uint256().SetCompact(savebits); arith_uint256 mask(ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO]); Mining_start = 0; @@ -1263,31 +1392,53 @@ void static BitcoinMiner_noeq() if ( ASSETCHAINS_STAKED != 0 ) { - int32_t percPoS,z; - hashTarget = komodo_PoWtarget(&percPoS,hashTarget,Mining_height,ASSETCHAINS_STAKED); - for (z=31; z>=0; z--) - fprintf(stderr,"%02x",((uint8_t *)&hashTarget)[z]); - fprintf(stderr," PoW for staked coin PoS %d%% vs target %d%%\n",percPoS,(int32_t)ASSETCHAINS_STAKED); + int32_t percPoS,z; bool fNegative,fOverflow; + HASHTarget_POW = komodo_PoWtarget(&percPoS,HASHTarget,Mining_height,ASSETCHAINS_STAKED); + HASHTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + LogPrintf("Block %d : PoS %d%% vs target %d%%\n", Mining_height, percPoS, (int32_t)ASSETCHAINS_STAKED); } while (true) { arith_uint256 arNonce = UintToArith256(pblock->nNonce); - + int64_t *extraPtr; + + // This seems to be a really bad way to do this, but its better than copy pasting the entire miner function at this stage. CVerusHashWriter ss = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); ss << *((CBlockHeader *)pblock); - int64_t *extraPtr = ss.xI64p(); + if ( ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH ) + extraPtr = ss.xI64p(); CVerusHash &vh = ss.GetState(); uint256 hashResult = uint256(); vh.ClearExtra(); + + CVerusHashV2Writer ss2 = CVerusHashV2Writer(SER_GETHASH, PROTOCOL_VERSION); + ss2 << *((CBlockHeader *)pblock); + if ( ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASHV1_1 ) + extraPtr = ss2.xI64p(); + CVerusHashV2 &vh2 = ss2.GetState(); + vh2.ClearExtra(); + int64_t i, count = ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] + 1; int64_t hashesToGo = ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO]; - + if ( ASSETCHAINS_STAKED > 0 && ASSETCHAINS_STAKED < 100 ) + { + if ( KOMODO_MININGTHREADS > 0 ) + hashTarget = HASHTarget_POW; + else + hashTarget = HASHTarget; + } + else if ( ASSETCHAINS_STAKED == 100 && Mining_height > 100 ) + hashTarget = HASHTarget; + // for speed check NONCEMASK at a time for (i = 0; i < count; i++) { *extraPtr = i; - vh.ExtraHash((unsigned char *)&hashResult); + if ( ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH ) + vh.ExtraHash((unsigned char *)&hashResult); + else if ( ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASHV1_1 ) + vh2.ExtraHash((unsigned char *)&hashResult); if ( UintToArith256(hashResult) <= hashTarget ) { @@ -1376,8 +1527,8 @@ void static BitcoinMiner_noeq() #else printf("%lu mega hashes complete - working\n", (ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] + 1) / 1048576); #endif + pblock->nBits = savebits; break; - } } } @@ -1499,6 +1650,13 @@ void static BitcoinMiner() #endif if ( ptr == 0 ) { + if ( !GetBoolArg("-gen",false)) + { + miningTimer.stop(); + c.disconnect(); + LogPrintf("KomodoMiner terminated\n"); + return; + } static uint32_t counter; if ( counter++ < 10 && ASSETCHAINS_STAKED == 0 ) fprintf(stderr,"created illegal blockB, retry\n"); @@ -1594,17 +1752,14 @@ void static BitcoinMiner() } //else fprintf(stderr,"duplicate at j.%d\n",j); } else Mining_start = 0; } else Mining_start = 0; - if ( ASSETCHAINS_STAKED != 0 ) + + if ( ASSETCHAINS_STAKED > 0 ) { int32_t percPoS,z; bool fNegative,fOverflow; HASHTarget_POW = komodo_PoWtarget(&percPoS,HASHTarget,Mining_height,ASSETCHAINS_STAKED); HASHTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); - if ( ASSETCHAINS_STAKED < 100 && KOMODO_MININGTHREADS == 0 ) - { - for (z=31; z>=0; z--) - fprintf(stderr,"%02x",((uint8_t *)&HASHTarget_POW)[z]); - fprintf(stderr," PoW for staked coin PoS %d%% vs target %d%% ht.%d\n",percPoS,(int32_t)ASSETCHAINS_STAKED,Mining_height); - } + if ( ASSETCHAINS_STAKED < 100 ) + LogPrintf("Block %d : PoS %d%% vs target %d%% \n",Mining_height,percPoS,(int32_t)ASSETCHAINS_STAKED); } gotinvalid = 0; while (true) @@ -1660,7 +1815,7 @@ void static BitcoinMiner() if ( h > hashTarget ) { //if ( ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0 ) - // sleep(1); + // MilliSleep(30); return false; } if ( IS_KOMODO_NOTARY != 0 && B.nTime > GetAdjustedTime() ) @@ -1687,12 +1842,6 @@ void static BitcoinMiner() } else { - while ( B.nTime-57 > GetAdjustedTime() ) - { - sleep(1); - if ( chainActive.LastTip()->GetHeight() >= Mining_height ) - return(false); - } uint256 tmp = B.GetHash(); int32_t z; for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&tmp)[z]); @@ -1736,7 +1885,6 @@ void static BitcoinMiner() std::lock_guard lock{m_cs}; return cancelSolver; }; - // TODO: factor this out into a function with the same API for each solver. if (solver == "tromp" ) { //&& notaryid >= 0 ) { // Create solver and initialize it. @@ -1903,12 +2051,12 @@ void static BitcoinMiner() for (int i = 0; i < nThreads; i++) { #ifdef ENABLE_WALLET - if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH || (ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0) ) + if ( ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH ) minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); else minerThreads->create_thread(boost::bind(&BitcoinMiner_noeq, pwallet)); #else - if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH || (ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0) ) + if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH ) minerThreads->create_thread(&BitcoinMiner); else minerThreads->create_thread(&BitcoinMiner_noeq); diff --git a/src/net.cpp b/src/net.cpp index d403660b6..83dc0782e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -78,6 +78,8 @@ namespace { // Global state variables // extern uint16_t ASSETCHAINS_P2PPORT; +extern int8_t is_STAKED(const char *chain_name); +extern char ASSETCHAINS_SYMBOL[65]; bool fDiscover = true; bool fListen = true; @@ -1275,7 +1277,6 @@ void ThreadSocketHandler() } } - void ThreadDNSAddressSeed() { // goal: only query DNS seeds if address need is acute @@ -1390,13 +1391,17 @@ void ThreadOpenConnections() if (GetTime() - nStart > 60) { static bool done = false; if (!done) { - //LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); - LogPrintf("Adding fixed seed nodes.\n"); - addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1")); + // skip DNS seeds for staked chains. + if ( is_STAKED(ASSETCHAINS_SYMBOL) == 0 ) { + //LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); + LogPrintf("Adding fixed seed nodes.\n"); + addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1")); + } done = true; } } + // // Choose an address to connect to based on most recently seen // @@ -1803,6 +1808,12 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) Discover(threadGroup); + // skip DNS seeds for staked chains. + extern int8_t is_STAKED(const char *chain_name); + extern char ASSETCHAINS_SYMBOL[65]; + if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 ) + SoftSetBoolArg("-dnsseed", false); + // // Start threads // diff --git a/src/net.h b/src/net.h index 3e06e9831..b7975bfec 100644 --- a/src/net.h +++ b/src/net.h @@ -293,6 +293,9 @@ public: bool fNetworkNode; bool fSuccessfullyConnected; bool fDisconnect; + // count blocks seen. + int8_t nBlocksinARow; + int8_t nBlocksinARow2; // We use fRelayTxes for two purposes - // a) it allows us to not relay tx invs before receiving the peer's version message // b) the peer may tell us in its version message that we should not relay tx invs diff --git a/src/netbase.cpp b/src/netbase.cpp index 88439f446..5ad6353e9 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -526,7 +526,8 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe else #endif { - LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); + if ( NetworkErrorString(WSAGetLastError()) != "Network is unreachable (101)") + LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); CloseSocket(hSocket); return false; } diff --git a/src/notaries_staked.cpp b/src/notaries_staked.cpp new file mode 100644 index 000000000..a3278ac12 --- /dev/null +++ b/src/notaries_staked.cpp @@ -0,0 +1,141 @@ + +#include "notaries_staked.h" +#include "crosschain.h" +#include "cc/CCinclude.h" +#include + +extern char NOTARYADDRS[64][36]; +extern std::string NOTARY_ADDRESS,NOTARY_PUBKEY; +extern int32_t STAKED_ERA,IS_STAKED_NOTARY,IS_KOMODO_NOTARY; +extern pthread_mutex_t staked_mutex; +extern uint8_t NOTARY_PUBKEY33[33],NUM_NOTARIES; + +int8_t is_STAKED(const char *chain_name) +{ + static int8_t STAKED,doneinit; + if ( chain_name[0] == 0 ) + return(0); + if (doneinit == 1 && ASSETCHAINS_SYMBOL[0] != 0) + return(STAKED); + else STAKED = 0; + if ( (strcmp(chain_name, "LABS") == 0) || (strcmp(chain_name, "LABSTH") == 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. + else if ( (strcmp(chain_name, "CFEK") == 0) || (strncmp(chain_name, "CFEK", 4) == 0) ) + STAKED = 3; // These chains have no speical rules at all. + else if ( (strcmp(chain_name, "TEST") == 0) || (strncmp(chain_name, "TEST", 4) == 0) ) + STAKED = 4; // These chains are for testing consensus to create a chain etc. Not meant to be actually used for anything important. + else if ( (strcmp(chain_name, "THIS_CHAIN_IS_BANNED") == 0) ) + STAKED = 255; // Any chain added to this group is banned, no notarisations are valid, as a consensus rule. Can be used to remove a chain from cluster if needed. + doneinit = 1; + return(STAKED); +}; + +int32_t STAKED_era(int timestamp) +{ + int8_t era = 0; + if (timestamp <= STAKED_NOTARIES_TIMESTAMP[0]) + return(1); + for (int32_t i = 1; i < NUM_STAKED_ERAS; i++) + { + if (timestamp <= STAKED_NOTARIES_TIMESTAMP[i] && timestamp >= (STAKED_NOTARIES_TIMESTAMP[i-1] + STAKED_ERA_GAP)) + return(i+1); + } + // if we are in a gap, return era 0, this allows to invalidate notarizations when in GAP. + return(0); +}; + +int8_t updateStakedNotary() { + std::string notaryname; + char Raddress[18]; uint8_t pubkey33[33]; + decode_hex(pubkey33,33,(char *)NOTARY_PUBKEY.c_str()); + pubkey2addr((char *)Raddress,(uint8_t *)pubkey33); + NOTARY_ADDRESS.clear(); + NOTARY_ADDRESS.assign(Raddress); + return(StakedNotaryID(notaryname,Raddress)); +} + +int8_t StakedNotaryID(std::string ¬aryname, char *Raddress) { + if ( STAKED_ERA != 0 ) + { + for (int8_t i = 0; i < num_notaries_STAKED[STAKED_ERA-1]; i++) { + if ( strcmp(Raddress,NOTARYADDRS[i]) == 0 ) { + notaryname.assign(notaries_STAKED[STAKED_ERA-1][i][0]); + return(i); + } + } + } + return(-1); +} + +int8_t numStakedNotaries(uint8_t pubkeys[64][33],int8_t era) { + int i; int8_t retval = 0; + static uint8_t staked_pubkeys[NUM_STAKED_ERAS][64][33],didinit[NUM_STAKED_ERAS]; + static char ChainName[65]; + + if ( ChainName[0] == 0 ) + { + if ( ASSETCHAINS_SYMBOL[0] == 0 ) + strcpy(ChainName,"KMD"); + else + strcpy(ChainName,ASSETCHAINS_SYMBOL); + } + + if ( era == 0 ) + { + // era is zero so we need to null out the pubkeys. + memset(pubkeys,0,64 * 33); + printf("%s is a STAKED chain and is in an ERA GAP.\n",ChainName); + return(64); + } + else + { + if ( didinit[era-1] == 0 ) + { + for (i=0; i @@ -17,31 +19,50 @@ NotarisationsInBlock ScanBlockNotarisations(const CBlock &block, int nHeight) { EvalRef eval; NotarisationsInBlock vNotarisations; + CrosschainAuthority auth_STAKED; + int timestamp = block.nTime; for (unsigned int i = 0; i < block.vtx.size(); i++) { CTransaction tx = block.vtx[i]; - // Special case for TXSCL. Should prob be removed at some point. - bool isTxscl = 0; - { - NotarisationData data; - if (ParseNotarisationOpReturn(tx, data)) - if (IsTXSCL(data.symbol)) - isTxscl = 1; + NotarisationData data; + bool parsed = ParseNotarisationOpReturn(tx, data); + if (!parsed) data = NotarisationData(); + if (strlen(data.symbol) == 0) + continue; + + //printf("Checked notarisation data for %s \n",data.symbol); + int authority = GetSymbolAuthority(data.symbol); + + if (authority == CROSSCHAIN_KOMODO) { + if (!eval->CheckNotaryInputs(tx, nHeight, block.nTime)) + continue; + //printf("Authorised notarisation data for %s \n",data.symbol); + } else if (authority == CROSSCHAIN_STAKED) { + // We need to create auth_STAKED dynamically here based on timestamp + int32_t staked_era = STAKED_era(timestamp); + if (staked_era == 0) { + // this is an ERA GAP, so we will ignore this notarization + continue; + if ( is_STAKED(data.symbol) == 255 ) + // this chain is banned... we will discard its notarisation. + continue; + } else { + // pass era slection off to notaries_staked.cpp file + auth_STAKED = Choose_auth_STAKED(staked_era); + } + if (!CheckTxAuthority(tx, auth_STAKED)) + continue; } - if (isTxscl || eval->CheckNotaryInputs(tx, nHeight, block.nTime)) { - NotarisationData data; - if (ParseNotarisationOpReturn(tx, data)) { - vNotarisations.push_back(std::make_pair(tx.GetHash(), data)); - //printf("Parsed a notarisation for: %s, txid:%s, ccid:%i, momdepth:%i\n", - // data.symbol, tx.GetHash().GetHex().data(), data.ccId, data.MoMDepth); - //if (!data.MoMoM.IsNull()) printf("MoMoM:%s\n", data.MoMoM.GetHex().data()); - } - else - LogPrintf("WARNING: Couldn't parse notarisation for tx: %s at height %i\n", - tx.GetHash().GetHex().data(), nHeight); - } + if (parsed) { + vNotarisations.push_back(std::make_pair(tx.GetHash(), data)); + //printf("Parsed a notarisation for: %s, txid:%s, ccid:%i, momdepth:%i\n", + // data.symbol, tx.GetHash().GetHex().data(), data.ccId, data.MoMDepth); + //if (!data.MoMoM.IsNull()) printf("MoMoM:%s\n", data.MoMoM.GetHex().data()); + } else + LogPrintf("WARNING: Couldn't parse notarisation for tx: %s at height %i\n", + tx.GetHash().GetHex().data(), nHeight); } return vNotarisations; } diff --git a/src/pow.cpp b/src/pow.cpp index cc2b0b7c2..1716099ee 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -44,10 +44,15 @@ unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { - if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH) + if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH && ASSETCHAINS_STAKED == 0) return lwmaGetNextWorkRequired(pindexLast, pblock, params); - unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); + arith_uint256 bnLimit; + if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH) + bnLimit = UintToArith256(params.powLimit); + else + bnLimit = UintToArith256(params.powAlternate); + unsigned int nProofOfWorkLimit = bnLimit.GetCompact(); // Genesis block if (pindexLast == NULL ) return nProofOfWorkLimit; @@ -102,7 +107,13 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, nActualTimespan = params.MaxActualTimespan(); // Retarget - const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); + arith_uint256 bnLimit; + if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH) + bnLimit = UintToArith256(params.powLimit); + else + bnLimit = UintToArith256(params.powAlternate); + + const arith_uint256 bnPowLimit = bnLimit; //UintToArith256(params.powLimit); arith_uint256 bnNew {bnAvg}; bnNew /= params.AveragingWindowTimespan(); bnNew *= nActualTimespan; @@ -133,6 +144,8 @@ unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const bnLimit = UintToArith256(params.powAlternate); unsigned int nProofOfWorkLimit = bnLimit.GetCompact(); + + //printf("PoWLimit: %u\n", nProofOfWorkLimit); // Find the first block in the averaging interval as we total the linearly weighted average const CBlockIndex* pindexFirst = pindexLast; diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index bb3314760..a7ec8d162 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -46,8 +46,11 @@ uint256 CBlockHeader::GetVerusHash() const uint256 CBlockHeader::GetVerusV2Hash() const { - // no check for genesis block and use the optimized hash - return SerializeVerusHashV2(*this); + if (hashPrevBlock.IsNull()) + // always use SHA256D for genesis block + return SerializeHash(*this); + else + return SerializeVerusHashV2(*this); } void CBlockHeader::SetSHA256DHash() @@ -60,6 +63,11 @@ void CBlockHeader::SetVerusHash() CBlockHeader::hashFunction = &CBlockHeader::GetVerusHash; } +void CBlockHeader::SetVerusHashV2() +{ + CBlockHeader::hashFunction = &CBlockHeader::GetVerusV2Hash; +} + // returns false if unable to fast calculate the VerusPOSHash from the header. // if it returns false, value is set to 0, but it can still be calculated from the full block // in that case. the only difference between this and the POS hash for the contest is that it is not divided by the value out diff --git a/src/primitives/block.h b/src/primitives/block.h index 5cd0a72fe..6ef8e0633 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -106,6 +106,7 @@ public: uint256 GetVerusEntropyHash(int32_t nHeight) const; uint256 GetVerusV2Hash() const; + static void SetVerusHashV2(); int64_t GetBlockTime() const { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index cf324d1f1..6dac120e4 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -49,6 +49,7 @@ extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); int32_t komodo_longestchain(); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); +extern int8_t komodo_segid(int32_t nocache,int32_t height); extern int32_t KOMODO_LONGESTCHAIN; double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty) @@ -147,7 +148,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->chainPower.chainWork.GetHex())); - result.push_back(Pair("segid", (int64_t)blockindex->segid)); + result.push_back(Pair("segid", (int)komodo_segid(0,blockindex->GetHeight()))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); @@ -174,7 +175,7 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex) result.push_back(Pair("height", blockindex->GetHeight())); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); - result.push_back(Pair("segid", (int64_t)blockindex->segid)); + result.push_back(Pair("segid", (int)komodo_segid(0,blockindex->GetHeight()))); UniValue deltas(UniValue::VARR); @@ -292,7 +293,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("height", blockindex->GetHeight())); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); - result.push_back(Pair("segid", (int64_t)blockindex->segid)); + result.push_back(Pair("segid", (int)komodo_segid(0,blockindex->GetHeight()))); result.push_back(Pair("finalsaplingroot", block.hashFinalSaplingRoot.GetHex())); UniValue txs(UniValue::VARR); BOOST_FOREACH(const CTransaction&tx, block.vtx) @@ -627,7 +628,7 @@ UniValue getblockhash(const UniValue& params, bool fHelp) return pblockindex->GetBlockHash().GetHex(); } -extern uint64_t ASSETCHAINS_STAKED; +extern int32_t ASSETCHAINS_STAKED; UniValue getlastsegidstakes(const UniValue& params, bool fHelp) { @@ -653,22 +654,39 @@ UniValue getlastsegidstakes(const UniValue& params, bool fHelp) LOCK(cs_main); int depth = params[0].get_int(); + if ( depth > chainActive.Height() ) + throw runtime_error("Not enough blocks to scan back that far.\n"); + int32_t segids[64] = {0}; + int32_t pow = 0; + int32_t notset = 0; for (int64_t i = chainActive.Height(); i > chainActive.Height()-depth; i--) { - CBlockIndex* pblockindex = chainActive[i]; - if ( pblockindex->segid >= 0 ) - segids[pblockindex->segid] += 1; + int8_t segid = komodo_segid(0,i); + //CBlockIndex* pblockindex = chainActive[i]; + if ( segid >= 0 ) + segids[segid] += 1; + else if ( segid == -1 ) + pow++; + else + notset++; } - + + int8_t posperc = 100*(depth-pow)/depth; + UniValue ret(UniValue::VOBJ); + UniValue objsegids(UniValue::VOBJ); for (int8_t i = 0; i < 64; i++) { char str[4]; sprintf(str, "%d", i); - ret.push_back(Pair(str,segids[i])); + objsegids.push_back(Pair(str,segids[i])); } + ret.push_back(Pair("NotSet",notset)); + ret.push_back(Pair("PoW",pow)); + ret.push_back(Pair("PoSPerc",posperc)); + ret.push_back(Pair("SegIds",objsegids)); return ret; } @@ -1637,6 +1655,87 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp) return mempoolInfoToJSON(); } +inline CBlockIndex* LookupBlockIndex(const uint256& hash) +{ + AssertLockHeld(cs_main); + BlockMap::const_iterator it = mapBlockIndex.find(hash); + return it == mapBlockIndex.end() ? nullptr : it->second; +} + +UniValue getchaintxstats(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "getchaintxstats\n" + "\nCompute statistics about the total number and rate of transactions in the chain.\n" + "\nArguments:\n" + "1. nblocks (numeric, optional) Number of blocks in averaging window.\n" + "2. blockhash (string, optional) The hash of the block which ends the window.\n" + "\nResult:\n" + "{\n" + " \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n" + " \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n" + " \"window_final_block_hash\": \"...\", (string) The hash of the final block in the window.\n" + " \"window_block_count\": xxxxx, (numeric) Size of the window in number of blocks.\n" + " \"window_tx_count\": xxxxx, (numeric) The number of transactions in the window. Only returned if \"window_block_count\" is > 0.\n" + " \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n" + " \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0.\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getchaintxstats", "") + + HelpExampleRpc("getchaintxstats", "2016") + ); + + const CBlockIndex* pindex; + int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month + + if (params[1].isNull()) { + LOCK(cs_main); + pindex = chainActive.Tip(); + } else { + uint256 hash(ParseHashV(params[1], "blockhash")); + LOCK(cs_main); + pindex = LookupBlockIndex(hash); + if (!pindex) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } + if (!chainActive.Contains(pindex)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain"); + } + } + + assert(pindex != nullptr); + + if (params[0].isNull()) { + blockcount = std::max(0, std::min(blockcount, pindex->GetHeight() - 1)); + } else { + blockcount = params[0].get_int(); + + if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->GetHeight())) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1"); + } + } + + const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->GetHeight() - blockcount); + int nTimeDiff = pindex->GetMedianTimePast() - pindexPast->GetMedianTimePast(); + int nTxDiff = pindex->nChainTx - pindexPast->nChainTx; + + UniValue ret(UniValue::VOBJ); + ret.pushKV("time", (int64_t)pindex->nTime); + ret.pushKV("txcount", (int64_t)pindex->nChainTx); + ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex()); + ret.pushKV("window_block_count", blockcount); + if (blockcount > 0) { + ret.pushKV("window_tx_count", nTxDiff); + ret.pushKV("window_interval", nTimeDiff); + if (nTimeDiff > 0) { + ret.pushKV("txrate", ((double)nTxDiff) / nTimeDiff); + } + } + + return ret; +} + UniValue invalidateblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -1724,6 +1823,7 @@ static const CRPCCommand commands[] = { "blockchain", "getblockhash", &getblockhash, true }, { "blockchain", "getblockheader", &getblockheader, true }, { "blockchain", "getchaintips", &getchaintips, true }, + { "blockchain", "getchaintxstats", &getchaintxstats, true }, { "blockchain", "getdifficulty", &getdifficulty, true }, { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, { "blockchain", "getrawmempool", &getrawmempool, true }, diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index ac45cd107..19910b25c 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -51,6 +51,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "sendtoaddress", 1 }, { "sendtoaddress", 4 }, { "settxfee", 0 }, + { "getnotarysendmany", 0 }, + { "getnotarysendmany", 1 }, { "getreceivedbyaddress", 1 }, { "getreceivedbyaccount", 1 }, { "listreceivedbyaddress", 0 }, @@ -87,6 +89,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listunspent", 2 }, { "getblock", 1 }, { "getblockheader", 1 }, + { "getchaintxstats", 0 }, + { "getlastsegidstakes", 0 }, { "gettransaction", 1 }, { "getrawtransaction", 1 }, { "getlastsegidstakes", 0 }, diff --git a/src/rpc/crosschain.cpp b/src/rpc/crosschain.cpp index 1a6dc41ea..710f99f09 100644 --- a/src/rpc/crosschain.cpp +++ b/src/rpc/crosschain.cpp @@ -116,7 +116,7 @@ UniValue height_MoM(const UniValue& params, bool fHelp) ret.push_back(Pair("kmdendi",kmdendi)); } } else ret.push_back(Pair("error",(char *)"no MoM for height")); - + return ret; } @@ -169,10 +169,10 @@ UniValue calc_MoM(const UniValue& params, bool fHelp) UniValue migrate_converttoexport(const UniValue& params, bool fHelp) { - std::vector rawproof; uint8_t *ptr; int32_t i; uint32_t ccid = ASSETCHAINS_CC; - if (fHelp || params.size() != 3) + std::vector rawproof; uint8_t *ptr; uint8_t i; uint32_t ccid = ASSETCHAINS_CC; uint64_t txfee = 10000; + if (fHelp || params.size() != 2) throw runtime_error( - "migrate_converttoexport rawTx dest_symbol export_amount\n" + "migrate_converttoexport rawTx dest_symbol\n" "\nConvert a raw transaction to a cross-chain export.\n" "If neccesary, the transaction should be funded using fundrawtransaction.\n" "Finally, the transaction should be signed using signrawtransaction\n" @@ -196,22 +196,22 @@ UniValue migrate_converttoexport(const UniValue& params, bool fHelp) if (targetSymbol.size() == 0 || targetSymbol.size() > 32) throw runtime_error("targetSymbol length must be >0 and <=32"); - CAmount burnAmount = AmountFromValue(params[2]); + if (strcmp(ASSETCHAINS_SYMBOL,targetSymbol.c_str()) == 0) + throw runtime_error("cant send a coin to the same chain"); + + CAmount burnAmount = 0; + + for (int i=0; i 0 ) - // throw runtime_error("self-import chains cant be fungible"); + throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export a negative or zero value."); + if (burnAmount > 1000000LL*COIN) + throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export more than 1 million coins per export."); + rawproof.resize(strlen(ASSETCHAINS_SYMBOL)); ptr = rawproof.data(); for (i=0; i> burnTx)) throw runtime_error("Couldn't parse burnTx"); - - + + vector payouts; if (!E_UNMARSHAL(ParseHexV(params[1], "argument 2"), ss >> payouts)) throw runtime_error("Couldn't parse payouts"); @@ -273,7 +273,7 @@ UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp) throw runtime_error("migrate_completeimporttransaction importTx\n\n" "Takes a cross chain import tx with proof generated on assetchain " "and extends proof to target chain proof root"); - + if (ASSETCHAINS_SYMBOL[0] != 0) throw runtime_error("Must be called on KMD"); @@ -446,7 +446,7 @@ UniValue scanNotarisationsDB(const UniValue& params, bool fHelp) if (height == 0) { height = chainActive.Height(); } - + Notarisation nota; int matchedHeight = ScanNotarisationsDB(height, symbol, limit, nota); if (!matchedHeight) return NullUniValue; @@ -456,3 +456,116 @@ UniValue scanNotarisationsDB(const UniValue& params, bool fHelp) out.pushKV("opreturn", HexStr(E_MARSHAL(ss << nota.second))); return out; } + +UniValue getimports(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getimports \"hash|height\"\n" + "\n\n" + "\nResult:\n" + "{\n" + " \"imports\" : [ (json array)\n" + " \"transactionid\" : { (json object)\n" + " \"value\" : (numeric)\n" + " \"address\" : (string)\n" + " \"export\" { (json object)\n" + " \"txid\" : (string)\n" + " \"value\" : (numeric)\n" + " \"chain\" : (string)\n" + " }\n" + " }" + " ]\n" + " \"TotalImported\" : (numeric)\n" + " \"time\" : (numeric)\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getimports", "\"00000000febc373a1da2bd9f887b105ad79ddc26ac26c2b28652d64e5207c5b5\"") + + HelpExampleRpc("getimports", "\"00000000febc373a1da2bd9f887b105ad79ddc26ac26c2b28652d64e5207c5b5\"") + + HelpExampleCli("getimports", "12800") + + HelpExampleRpc("getimports", "12800") + ); + + LOCK(cs_main); + + std::string strHash = params[0].get_str(); + + // If height is supplied, find the hash + if (strHash.size() < (2 * sizeof(uint256))) { + // std::stoi allows characters, whereas we want to be strict + regex r("[[:digit:]]+"); + if (!regex_match(strHash, r)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter"); + } + + int nHeight = -1; + try { + nHeight = std::stoi(strHash); + } + catch (const std::exception &e) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter"); + } + + if (nHeight < 0 || nHeight > chainActive.Height()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); + } + strHash = chainActive[nHeight]->GetBlockHash().GetHex(); + } + + uint256 hash(uint256S(strHash)); + + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hash]; + + if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); + + if(!ReadBlockFromDisk(block, pblockindex,1)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + + UniValue result(UniValue::VOBJ); + CAmount TotalImported = 0; + UniValue imports(UniValue::VARR); + BOOST_FOREACH(const CTransaction&tx, block.vtx) + { + if(tx.IsCoinImport()) + { + UniValue objTx(UniValue::VOBJ); + objTx.push_back(Pair("txid",tx.GetHash().ToString())); + TxProof proof; CTransaction burnTx; std::vector payouts; CTxDestination importaddress; + TotalImported += tx.vout[1].nValue; + objTx.push_back(Pair("amount", ValueFromAmount(tx.vout[1].nValue))); + if (ExtractDestination(tx.vout[1].scriptPubKey, importaddress)) + { + objTx.push_back(Pair("address", CBitcoinAddress(importaddress).ToString())); + } + UniValue objBurnTx(UniValue::VOBJ); + if (UnmarshalImportTx(tx, proof, burnTx, payouts)) + { + if (burnTx.vout.size() == 0) + continue; + objBurnTx.push_back(Pair("txid", burnTx.GetHash().ToString())); + objBurnTx.push_back(Pair("amount", ValueFromAmount(burnTx.vout.back().nValue))); + // extract op_return to get burn source chain. + std::vector burnOpret; std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; std::vectorrawproof; + if (UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) + { + if (rawproof.size() > 0) + { + std::string sourceSymbol(rawproof.begin(), rawproof.end()); + objBurnTx.push_back(Pair("source", sourceSymbol)); + } + } + } + objTx.push_back(Pair("export", objBurnTx)); + imports.push_back(objTx); + } + } + result.push_back(Pair("imports", imports)); + result.push_back(Pair("TotalImported", TotalImported > 0 ? ValueFromAmount(TotalImported) : 0 )); + result.push_back(Pair("time", block.GetBlockTime())); + return result; +} diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index ff9b1b4c4..2efe8d694 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -49,6 +49,7 @@ using namespace std; #include "komodo_defs.h" +extern int32_t ASSETCHAINS_FOUNDERS; arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc); @@ -180,8 +181,11 @@ UniValue getgenerate(const UniValue& params, bool fHelp) LOCK(cs_main); UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("staking", VERUS_MINTBLOCKS)); - obj.push_back(Pair("generate", GetBoolArg("-gen", false))); + bool staking = VERUS_MINTBLOCKS; + if ( ASSETCHAINS_STAKED != 0 && GetBoolArg("-gen", false) && GetBoolArg("-genproclimit", -1) == 0 ) + staking = true; + obj.push_back(Pair("staking", staking)); + obj.push_back(Pair("generate", GetBoolArg("-gen", false) && GetBoolArg("-genproclimit", -1) != 0 )); obj.push_back(Pair("numthreads", (int64_t)KOMODO_MININGTHREADS)); return obj; } @@ -215,7 +219,18 @@ UniValue generate(const UniValue& params, bool fHelp) #endif } if (!Params().MineBlocksOnDemand()) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); + { + if ( params[0].get_int() == 1 ) + { + mapArgs["disablemining"] = "1"; + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Mining Disabled"); + } + else + { + mapArgs["disablemining"] = "0"; + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Mining Enabled"); + } + } int nHeightStart = 0; int nHeightEnd = 0; @@ -345,7 +360,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp) if (params.size() > 0) fGenerate = params[0].get_bool(); - int nGenProcLimit = GetArg("-genproclimit", -1);; + int nGenProcLimit = GetArg("-genproclimit", 0);; if (params.size() > 1) { nGenProcLimit = params[1].get_int(); @@ -436,8 +451,11 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); obj.push_back(Pair("chain", Params().NetworkIDString())); #ifdef ENABLE_MINING - obj.push_back(Pair("staking", VERUS_MINTBLOCKS)); - obj.push_back(Pair("generate", GetBoolArg("-gen", false))); + bool staking = VERUS_MINTBLOCKS; + if ( ASSETCHAINS_STAKED != 0 && GetBoolArg("-gen", false) && GetBoolArg("-genproclimit", -1) == 0 ) + staking = true; + obj.push_back(Pair("staking", staking)); + obj.push_back(Pair("generate", GetBoolArg("-gen", false) && GetBoolArg("-genproclimit", -1) != 0 )); obj.push_back(Pair("numthreads", (int64_t)KOMODO_MININGTHREADS)); #endif return obj; @@ -570,6 +588,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "komodod compiled without wallet and -mineraddress not set"); #endif } + + if ( GetArg("disablemining",false) ) + throw JSONRPCError(RPC_TYPE_ERROR, "Mining is Disabled"); UniValue lpval = NullUniValue; // TODO: Re-enable coinbasevalue once a specification has been written @@ -714,10 +735,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) } #ifdef ENABLE_WALLET CReserveKey reservekey(pwalletMain); - pblocktemplate = CreateNewBlockWithKey(reservekey,chainActive.LastTip()->GetHeight()+1,KOMODO_MAXGPUCOUNT); + LEAVE_CRITICAL_SECTION(cs_main); + pblocktemplate = CreateNewBlockWithKey(reservekey,pindexPrevNew->GetHeight()+1,KOMODO_MAXGPUCOUNT,false); #else pblocktemplate = CreateNewBlockWithKey(); #endif + ENTER_CRITICAL_SECTION(cs_main); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory or no available utxo for staking"); @@ -763,10 +786,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (tx.IsCoinBase() && coinbasetxn == true ) { // Show founders' reward if it is required - //if (pblock->vtx[0].vout.size() > 1) { + if (ASSETCHAINS_FOUNDERS && pblock->vtx[0].vout.size() > 1) { // Correct this if GetBlockTemplate changes the order - // entry.push_back(Pair("foundersreward", (int64_t)tx.vout[1].nValue)); - //} + entry.push_back(Pair("foundersreward", (int64_t)tx.vout[1].nValue)); + } CAmount nReward = GetBlockSubsidy(chainActive.LastTip()->GetHeight()+1, Params().GetConsensus()); entry.push_back(Pair("coinbasevalue", nReward)); entry.push_back(Pair("required", true)); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 1b522293e..814f7b9b8 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -28,6 +28,7 @@ #include "timedata.h" #include "txmempool.h" #include "util.h" +#include "notaries_staked.h" #include "cc/eval.h" #include "cc/CCinclude.h" #ifdef ENABLE_WALLET @@ -63,26 +64,131 @@ int32_t Jumblr_depositaddradd(char *depositaddr); int32_t Jumblr_secretaddradd(char *secretaddr); uint64_t komodo_interestsum(); int32_t komodo_longestchain(); -int32_t komodo_notarized_height(int32_t *prevhtp,uint256 *hashp,uint256 *txidp); +int32_t komodo_notarized_height(int32_t *prevMoMheightp,uint256 *hashp,uint256 *txidp); 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; +extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN,IS_STAKED_NOTARY,IS_KOMODO_NOTARY,STAKED_ERA; 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); int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp); +int8_t StakedNotaryID(std::string ¬aryname, char *Raddress); + #define KOMODO_VERSION "0.3.3b" #define VERUS_VERSION "0.4.0g" extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; extern uint32_t ASSETCHAINS_CC; -extern uint32_t ASSETCHAINS_MAGIC; -extern uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY; -extern uint32_t ASSETCHAINS_LASTERA; -extern int32_t ASSETCHAINS_LWMAPOS,ASSETCHAINS_SAPLING; -extern uint64_t ASSETCHAINS_ENDSUBSIDY[],ASSETCHAINS_REWARD[],ASSETCHAINS_HALVING[],ASSETCHAINS_DECAY[]; -extern std::string NOTARY_PUBKEY; extern uint8_t NOTARY_PUBKEY33[]; +extern uint32_t ASSETCHAINS_MAGIC,ASSETCHAINS_ALGO; +extern uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; +extern int32_t ASSETCHAINS_LWMAPOS,ASSETCHAINS_SAPLING,ASSETCHAINS_STAKED; +extern uint64_t ASSETCHAINS_ENDSUBSIDY[],ASSETCHAINS_REWARD[],ASSETCHAINS_HALVING[],ASSETCHAINS_DECAY[],ASSETCHAINS_NOTARY_PAY[]; +extern std::string NOTARY_PUBKEY,NOTARY_ADDRESS; extern uint8_t NOTARY_PUBKEY33[]; + +int32_t getera(int timestamp) +{ + for (int32_t i = 0; i < NUM_STAKED_ERAS; i++) { + if ( timestamp <= STAKED_NOTARIES_TIMESTAMP[i] ) { + return(i); + } + } + return(0); +} + +UniValue getiguanajson(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error("getiguanajson\nreturns json for iguana, for the current ERA."); + + UniValue json(UniValue::VOBJ); + UniValue seeds(UniValue::VARR); + UniValue notaries(UniValue::VARR); + // get the current era, use local time for now. + // should ideally take blocktime of last known block? + int now = time(NULL); + int32_t era = getera(now); + + // loop over seeds array and push back to json array for seeds + for (int8_t i = 0; i < 8; i++) { + seeds.push_back(iguanaSeeds[i][0]); + } + + // loop over era's notaries and push back each pair to the notary array + for (int8_t i = 0; i < num_notaries_STAKED[era]; i++) { + UniValue notary(UniValue::VOBJ); + notary.push_back(Pair(notaries_STAKED[era][i][0],notaries_STAKED[era][i][1])); + notaries.push_back(notary); + } + + // get the min sigs .. this always rounds UP so min sigs in iguana is +1 min sigs in komodod, due to some rounding error. + int minsigs; + if ( num_notaries_STAKED[era]/5 > overrideMinSigs ) + minsigs = (num_notaries_STAKED[era] / 5) + 1; + else + minsigs = overrideMinSigs; + + json.push_back(Pair("port",iguanaPort)); + json.push_back(Pair("BTCminsigs",BTCminsigs)); + json.push_back(Pair("minsigs",minsigs)); + json.push_back(Pair("seeds",seeds)); + json.push_back(Pair("notaries",notaries)); + return json; +} + +UniValue getnotarysendmany(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getnotarysendmany\n" + "Returns a sendmany JSON array with all current notaries Raddress's.\n" + "\nExamples:\n" + + HelpExampleCli("getnotarysendmany", "10") + + HelpExampleRpc("getnotarysendmany", "10") + ); + int amount = 0; + if ( params.size() == 1 ) { + amount = params[0].get_int(); + } + + int era = getera(time(NULL)); + + UniValue ret(UniValue::VOBJ); + for (int i = 0; iGetHeight(); i++) + { + pindex = chainActive[i]; + era = getera(pindex->nTime)+1; + if ( era > lastera ) + { + char str[16]; + sprintf(str, "%d", era); + ret.push_back(Pair(str,(int64_t)i)); + lastera = era; + } + } + + return(ret); +} UniValue getinfo(const UniValue& params, bool fHelp) { @@ -180,17 +286,17 @@ UniValue getinfo(const UniValue& params, bool fHelp) #endif obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); obj.push_back(Pair("errors", GetWarnings("statusbar"))); - { - char pubkeystr[65]; int32_t notaryid; - if ( (notaryid= komodo_whoami(pubkeystr,(int32_t)chainActive.LastTip()->GetHeight(),komodo_chainactive_timestamp())) >= 0 ) - { + if ( NOTARY_PUBKEY33[0] != 0 ) { + char pubkeystr[65]; int32_t notaryid; std::string notaryname; + if ( (notaryid= StakedNotaryID(notaryname, (char *)NOTARY_ADDRESS.c_str())) != -1 ) { + obj.push_back(Pair("notaryid", notaryid)); + obj.push_back(Pair("notaryname", notaryname)); + } else if( (notaryid= komodo_whoami(pubkeystr,(int32_t)chainActive.LastTip()->GetHeight(),komodo_chainactive_timestamp())) >= 0 ) { obj.push_back(Pair("notaryid", notaryid)); - obj.push_back(Pair("pubkey", pubkeystr)); if ( KOMODO_LASTMINED != 0 ) - obj.push_back(Pair("lastmined", KOMODO_LASTMINED)); - } else if ( NOTARY_PUBKEY33[0] != 0 ) { - obj.push_back(Pair("pubkey", NOTARY_PUBKEY)); + obj.push_back(Pair("lastmined", KOMODO_LASTMINED)); } + obj.push_back(Pair("pubkey", NOTARY_PUBKEY)); } if ( ASSETCHAINS_CC != 0 ) obj.push_back(Pair("CCid", (int)ASSETCHAINS_CC)); @@ -201,13 +307,15 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("rpcport", ASSETCHAINS_RPCPORT)); if ( ASSETCHAINS_SYMBOL[0] != 0 ) { + if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 ) + obj.push_back(Pair("StakedEra", STAKED_ERA)); //obj.push_back(Pair("name", ASSETCHAINS_SYMBOL)); obj.push_back(Pair("magic", (int)ASSETCHAINS_MAGIC)); obj.push_back(Pair("premine", ASSETCHAINS_SUPPLY)); if ( ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_LASTERA > 0 ) { - std::string acReward = "", acHalving = "", acDecay = "", acEndSubsidy = ""; + std::string acReward = "", acHalving = "", acDecay = "", acEndSubsidy = "", acNotaryPay = ""; for (int i = 0; i <= ASSETCHAINS_LASTERA; i++) { if (i == 0) @@ -216,6 +324,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) acHalving = std::to_string(ASSETCHAINS_HALVING[i]); acDecay = std::to_string(ASSETCHAINS_DECAY[i]); acEndSubsidy = std::to_string(ASSETCHAINS_ENDSUBSIDY[i]); + acNotaryPay = std::to_string(ASSETCHAINS_NOTARY_PAY[i]); } else { @@ -223,6 +332,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) acHalving += "," + std::to_string(ASSETCHAINS_HALVING[i]); acDecay += "," + std::to_string(ASSETCHAINS_DECAY[i]); acEndSubsidy += "," + std::to_string(ASSETCHAINS_ENDSUBSIDY[i]); + acNotaryPay += "," + std::to_string(ASSETCHAINS_NOTARY_PAY[i]); } } if (ASSETCHAINS_LASTERA > 0) @@ -231,6 +341,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("halving", acHalving)); obj.push_back(Pair("decay", acDecay)); obj.push_back(Pair("endsubsidy", acEndSubsidy)); + obj.push_back(Pair("notarypay", acNotaryPay)); } if ( ASSETCHAINS_COMMISSION != 0 ) @@ -239,6 +350,8 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("staked", ASSETCHAINS_STAKED)); if ( ASSETCHAINS_LWMAPOS != 0 ) obj.push_back(Pair("veruspos", ASSETCHAINS_LWMAPOS)); + if ( ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH ) + obj.push_back(Pair("algo",ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO])); } return obj; } @@ -1323,15 +1436,15 @@ UniValue txnotarizedconfirmed(const UniValue& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 1) { string msg = "txnotarizedconfirmed txid\n" - "\nReturns true if transaction is notarized on chain that has dPoW or if confirmation number is greater than 60 on chain taht does not have dPoW.\n" + "\nReturns true if transaction is notarized on chain that has dPoW or if confirmation number is greater than 60 on chain taht does not have dPoW.\n" "\nArguments:\n" - "1. txid (string, required) Transaction id.\n" + "1. txid (string, required) Transaction id.\n" "\nResult:\n" "{\n" - " true, (bool) The value the check.\n" - "}\n" + " true, (bool) The value the check.\n" + "}\n" ; throw runtime_error(msg); } @@ -1366,8 +1479,11 @@ UniValue decodeccopret(const UniValue& params, bool fHelp) } std::vector hex(ParseHex(params[0].get_str())); CScript scripthex(hex.begin(),hex.end()); - if (DecodeTokenOpRet(scripthex,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + std::vector> oprets; + if (DecodeTokenOpRet(scripthex,tokenevalcode,tokenid,pubkeys, oprets)!=0 && tokenevalcode==EVAL_TOKENS && oprets.size()>0) { + // seems we need a loop here + vOpretExtra = oprets[0].second; UniValue obj(UniValue::VOBJ); GetOpReturnData(scripthex,vopret); script = (uint8_t *)vopret.data(); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 5ab040711..6e90c4db5 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -35,6 +35,7 @@ #include "script/sign.h" #include "script/standard.h" #include "uint256.h" +#include "importcoin.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" #endif @@ -202,6 +203,25 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); else if (tx.IsCoinImport()) { in.push_back(Pair("is_import", "1")); + TxProof proof; CTransaction burnTx; std::vector payouts; CTxDestination importaddress; + if (UnmarshalImportTx(tx, proof, burnTx, payouts)) + { + if (burnTx.vout.size() == 0) + continue; + in.push_back(Pair("txid", burnTx.GetHash().ToString())); + in.push_back(Pair("value", ValueFromAmount(burnTx.vout.back().nValue))); + in.push_back(Pair("valueSat", burnTx.vout.back().nValue)); + // extract op_return to get burn source chain. + std::vector burnOpret; std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; std::vectorrawproof; + if (UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) + { + if (rawproof.size() > 0) + { + std::string sourceSymbol(rawproof.begin(), rawproof.end()); + in.push_back(Pair("address", "IMP-" + sourceSymbol + "-" + burnTx.GetHash().ToString())); + } + } + } } else { in.push_back(Pair("txid", txin.prevout.hash.GetHex())); @@ -256,6 +276,14 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& out.push_back(Pair("n", (int64_t)i)); UniValue o(UniValue::VOBJ); ScriptPubKeyToJSON(txout.scriptPubKey, o, true); + if (txout.scriptPubKey.IsOpReturn() && txout.nValue != 0) + { + std::vector burnOpret; std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; std::vectorrawproof; + if (UnmarshalBurnTx(tx, targetSymbol, &targetCCid, payoutsHash, rawproof)) + { + out.push_back(Pair("target", "EXPORT->" + targetSymbol)); + } + } out.push_back(Pair("scriptPubKey", o)); // Add spent information if spentindex is enabled @@ -565,7 +593,7 @@ int32_t gettxout_scriptPubKey(uint8_t *scriptPubKey,int32_t maxsize,uint256 txid uint256 hashBlock; if ( GetTransaction(txid,tx,hashBlock,false) == 0 ) return(-1); - else if ( n < tx.vout.size() ) + else if ( n < tx.vout.size() ) { ptr = (uint8_t *)&tx.vout[n].scriptPubKey[0]; m = tx.vout[n].scriptPubKey.size(); @@ -1304,7 +1332,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) } } else if (fHaveChain) { throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); - } + } RelayTransaction(tx); return hashTx.GetHex(); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 19ac60525..a44304ff0 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -291,6 +291,9 @@ static const CRPCCommand vRPCCommands[] = // --------------------- ------------------------ ----------------------- ---------- /* Overall control/query calls */ { "control", "help", &help, true }, + { "control", "getiguanajson", &getiguanajson, true }, + { "control", "getnotarysendmany", &getnotarysendmany, true }, + { "control", "geterablockheights", &geterablockheights, true }, { "control", "stop", &stop, true }, /* P2P networking */ @@ -346,6 +349,7 @@ static const CRPCCommand vRPCCommands[] = { "crosschain", "crosschainproof", &crosschainproof, true }, { "crosschain", "getNotarisationsForBlock", &getNotarisationsForBlock, true }, { "crosschain", "scanNotarisationsDB", &scanNotarisationsDB, true }, + { "crosschain", "getimports", &getimports, true }, { "crosschain", "migrate_converttoexport", &migrate_converttoexport, true }, { "crosschain", "migrate_createimporttransaction", &migrate_createimporttransaction, true }, { "crosschain", "migrate_completeimporttransaction", &migrate_completeimporttransaction, true }, @@ -462,6 +466,12 @@ static const CRPCCommand vRPCCommands[] = // Payments { "payments", "paymentsaddress", &paymentsaddress, true }, + { "payments", "paymentstxidopret", &payments_txidopret, true }, + { "payments", "paymentscreate", &payments_create, true }, + { "payments", "paymentslist", &payments_list, true }, + { "payments", "paymentsinfo", &payments_info, true }, + { "payments", "paymentsfund", &payments_fund, true }, + { "payments", "paymentsrelease", &payments_release, true }, { "CClib", "cclibaddress", &cclibaddress, true }, { "CClib", "cclibinfo", &cclibinfo, true }, @@ -557,6 +567,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "getaccountaddress", &getaccountaddress, true }, { "wallet", "getaccount", &getaccount, true }, { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true }, + { "wallet", "cleanwallettransactions", &cleanwallettransactions, false }, { "wallet", "getbalance", &getbalance, false }, { "wallet", "getbalance64", &getbalance64, false }, { "wallet", "getnewaddress", &getnewaddress, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index b41203df9..4eee49da3 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -288,6 +288,13 @@ extern UniValue marmara_creditloop(const UniValue& params, bool fHelp); extern UniValue marmara_settlement(const UniValue& params, bool fHelp); extern UniValue marmara_lock(const UniValue& params, bool fHelp); extern UniValue paymentsaddress(const UniValue& params, bool fHelp); +extern UniValue payments_release(const UniValue& params, bool fHelp); +extern UniValue payments_fund(const UniValue& params, bool fHelp); +extern UniValue payments_txidopret(const UniValue& params, bool fHelp); +extern UniValue payments_create(const UniValue& params, bool fHelp); +extern UniValue payments_info(const UniValue& params, bool fHelp); +extern UniValue payments_list(const UniValue& params, bool fHelp); + extern UniValue cclibaddress(const UniValue& params, bool fHelp); extern UniValue cclibinfo(const UniValue& params, bool fHelp); extern UniValue cclib(const UniValue& params, bool fHelp); @@ -353,6 +360,7 @@ extern UniValue signmessage(const UniValue& params, bool fHelp); extern UniValue verifymessage(const UniValue& params, bool fHelp); extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp); extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp); +extern UniValue cleanwallettransactions(const UniValue& params, bool fHelp); extern UniValue getbalance(const UniValue& params, bool fHelp); extern UniValue getbalance64(const UniValue& params, bool fHelp); extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp); @@ -378,6 +386,9 @@ extern UniValue validateaddress(const UniValue& params, bool fHelp); extern UniValue txnotarizedconfirmed(const UniValue& params, bool fHelp); extern UniValue decodeccopret(const UniValue& params, bool fHelp); extern UniValue getinfo(const UniValue& params, bool fHelp); +extern UniValue getiguanajson(const UniValue& params, bool fHelp); +extern UniValue getnotarysendmany(const UniValue& params, bool fHelp); +extern UniValue geterablockheights(const UniValue& params, bool fHelp); extern UniValue setpubkey(const UniValue& params, bool fHelp); extern UniValue getwalletinfo(const UniValue& params, bool fHelp); extern UniValue getblockchaininfo(const UniValue& params, bool fHelp); @@ -460,6 +471,7 @@ extern UniValue assetchainproof(const UniValue& params, bool fHelp); extern UniValue crosschainproof(const UniValue& params, bool fHelp); extern UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp); extern UniValue scanNotarisationsDB(const UniValue& params, bool fHelp); +extern UniValue getimports(const UniValue& params, bool fHelp); extern UniValue migrate_converttoexport(const UniValue& params, bool fHelp); extern UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp); extern UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp); diff --git a/src/rpcblockchain.old b/src/rpcblockchain.old index 359df15ce..a91f73a63 100644 --- a/src/rpcblockchain.old +++ b/src/rpcblockchain.old @@ -836,7 +836,7 @@ UniValue kvsearch(const UniValue& params, bool fHelp) " \"currentheight\": xxxxx, (numeric) current height of the chain\n" " \"key\": \"xxxxx\", (string) key\n" " \"keylen\": xxxxx, (string) length of the key \n" - " \"owner\": \"xxxxx\" (string) hex string representing the owner of the key \n" + " \"owner\": \"xxxxx\" (string) hex string representing the owner of the key \n" " \"height\": xxxxx, (numeric) height the key was stored at\n" " \"expiration\": xxxxx, (numeric) height the key will expire\n" " \"flags\": x (numeric) 1 if the key was created with a password; 0 otherwise.\n" diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 2b81abdc8..d38c0a351 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -407,7 +407,7 @@ bool ExtractDestination(const CScript& _scriptPubKey, CTxDestination& addressRet addressRet = CScriptID(uint160(vSolutions[0])); return true; } - + else if (IsCryptoConditionsEnabled() != 0 && whichType == TX_CRYPTOCONDITION) { if (vSolutions.size() > 1) diff --git a/src/txdb.cpp b/src/txdb.cpp index c86ee9bfa..0588d52de 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -60,7 +60,7 @@ static const char DB_LAST_BLOCK = 'l'; CCoinsViewDB::CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe) { } -CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) +CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) { } @@ -122,7 +122,7 @@ uint256 CCoinsViewDB::GetBestBlock() const { uint256 CCoinsViewDB::GetBestAnchor(ShieldedType type) const { uint256 hashBestAnchor; - + switch (type) { case SPROUT: if (!db.Read(DB_BEST_SPROUT_ANCHOR, hashBestAnchor)) @@ -436,11 +436,12 @@ bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type, } bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address); +uint32_t komodo_segid32(char *coinaddr); UniValue CBlockTreeDB::Snapshot(int top) { int64_t total = 0; int64_t totalAddresses = 0; std::string address; - int64_t utxos = 0; int64_t ignoredAddresses; + int64_t utxos = 0; int64_t ignoredAddresses = 0; boost::scoped_ptr iter(NewIterator()); std::map addressAmounts; std::vector > vaddr; @@ -448,23 +449,23 @@ UniValue CBlockTreeDB::Snapshot(int top) result.push_back(Pair("start_time", (int) time(NULL))); std::map ignoredMap = { - {"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1}, - {"RMUF3UDmzWFLSKV82iFbMaqzJpUnrWjcT4", 1}, - {"RA5imhVyJa7yHhggmBytWuDr923j2P1bxx", 1}, - {"RBM5LofZFodMeewUzoMWcxedm3L3hYRaWg", 1}, - {"RAdcko2d94TQUcJhtFHZZjMyWBKEVfgn4J", 1}, - {"RLzUaZ934k2EFCsAiVjrJqM8uU1vmMRFzk", 1}, - {"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, - {"RUDrX1v5toCsJMUgtvBmScKjwCB5NaR8py", 1}, - {"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, - {"RRvwmbkxR5YRzPGL5kMFHMe1AH33MeD8rN", 1}, - {"RQLQvSgpPAJNPgnpc8MrYsbBhep95nCS8L", 1}, - {"RK8JtBV78HdvEPvtV5ckeMPSTojZPzHUTe", 1}, - {"RHVs2KaCTGUMNv3cyWiG1jkEvZjigbCnD2", 1}, - {"RE3SVaDgdjkRPYA6TRobbthsfCmxQedVgF", 1}, - {"RW6S5Lw5ZCCvDyq4QV9vVy7jDHfnynr5mn", 1}, - {"RTkJwAYtdXXhVsS3JXBAJPnKaBfMDEswF8", 1}, - {"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} //Burnaddress for null privkey + {"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1}, + {"RMUF3UDmzWFLSKV82iFbMaqzJpUnrWjcT4", 1}, + {"RA5imhVyJa7yHhggmBytWuDr923j2P1bxx", 1}, + {"RBM5LofZFodMeewUzoMWcxedm3L3hYRaWg", 1}, + {"RAdcko2d94TQUcJhtFHZZjMyWBKEVfgn4J", 1}, + {"RLzUaZ934k2EFCsAiVjrJqM8uU1vmMRFzk", 1}, + {"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, + {"RUDrX1v5toCsJMUgtvBmScKjwCB5NaR8py", 1}, + {"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, + {"RRvwmbkxR5YRzPGL5kMFHMe1AH33MeD8rN", 1}, + {"RQLQvSgpPAJNPgnpc8MrYsbBhep95nCS8L", 1}, + {"RK8JtBV78HdvEPvtV5ckeMPSTojZPzHUTe", 1}, + {"RHVs2KaCTGUMNv3cyWiG1jkEvZjigbCnD2", 1}, + {"RE3SVaDgdjkRPYA6TRobbthsfCmxQedVgF", 1}, + {"RW6S5Lw5ZCCvDyq4QV9vVy7jDHfnynr5mn", 1}, + {"RTkJwAYtdXXhVsS3JXBAJPnKaBfMDEswF8", 1}, + {"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} //Burnaddress for null privkey }; int64_t startingHeight = chainActive.Height(); @@ -490,27 +491,31 @@ UniValue CBlockTreeDB::Snapshot(int top) getAddressFromIndex(indexKey.type, indexKey.hashBytes, address); - std::map ::iterator ignored = ignoredMap.find(address); - if (ignored != ignoredMap.end()) { - fprintf(stderr,"ignoring %s\n", address.c_str()); - ignoredAddresses++; - continue; - } + if (nValue > 0) { + std::map ::iterator ignored = ignoredMap.find(address); + if (ignored != ignoredMap.end()) { + fprintf(stderr,"ignoring %s\n", address.c_str()); + ignoredAddresses++; + continue; + } - std::map ::iterator pos = addressAmounts.find(address); - if (pos == addressAmounts.end()) { - // insert new address + utxo amount - //fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue); - addressAmounts[address] = nValue; - totalAddresses++; + std::map ::iterator pos = addressAmounts.find(address); + if (pos == addressAmounts.end()) { + // insert new address + utxo amount + //fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue); + addressAmounts[address] = nValue; + totalAddresses++; + } else { + // update unspent tally for this address + //fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue); + addressAmounts[address] += nValue; + } + //fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN); + // total += nValue; + utxos++; } else { - // update unspent tally for this address - //fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue); - addressAmounts[address] += nValue; + fprintf(stderr,"ignoring amount=0 UTXO for %s\n", address.c_str()); } - //fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN); - // total += nValue; - utxos++; } catch (const std::exception& e) { fprintf(stderr, "DONE %s: LevelDB addressindex exception! - %s\n", __func__, e.what()); break; @@ -526,29 +531,31 @@ UniValue CBlockTreeDB::Snapshot(int top) //fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses); for (std::pair element : addressAmounts) { - vaddr.push_back( make_pair(element.second, element.first) ); + vaddr.push_back( make_pair(element.second, element.first) ); } std::sort(vaddr.rbegin(), vaddr.rend()); UniValue obj(UniValue::VOBJ); UniValue addressesSorted(UniValue::VARR); int topN = 0; - for (std::vector>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) { - UniValue obj(UniValue::VOBJ); - obj.push_back( make_pair("addr", it->second.c_str() ) ); - char amount[32]; - sprintf(amount, "%.8f", (double) it->first / COIN); - obj.push_back( make_pair("amount", amount) ); - total += it->first; - addressesSorted.push_back(obj); - topN++; - // If requested, only show top N addresses in output JSON - if (top == topN) - break; + for (std::vector>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) + { + UniValue obj(UniValue::VOBJ); + obj.push_back( make_pair("addr", it->second.c_str() ) ); + char amount[32]; + sprintf(amount, "%.8f", (double) it->first / COIN); + obj.push_back( make_pair("amount", amount) ); + obj.push_back( make_pair("segid",(int32_t)komodo_segid32((char *)it->second.c_str()) & 0x3f) ); + total += it->first; + addressesSorted.push_back(obj); + topN++; + // If requested, only show top N addresses in output JSON + if (top == topN) + break; } if (top) - totalAddresses = top; + totalAddresses = top; if (totalAddresses > 0) { // Array of all addreses with balances diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index ece2ec73e..d4bba72ee 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -419,10 +419,26 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) int mantissa_tzeros = 0; bool mantissa_sign = false; bool exponent_sign = false; - int ptr = 0; + int i,n,ptr = 0; char *str = (char *)val.c_str(); int end = val.size(); int point_ofs = 0; - + n = val.size(); + if ( n == 11 && (val[0] < '9' || val[1] < '3') ) + { + uint64_t val64 = 0; + for (i=0; i '9' ) + break; + val64 = (val64 * 10) + (val[i] - '0'); + } + if ( i == n ) // 90000000000 + { + *amount_out = val64 * 100000000; + //fprintf(stderr,"special case: %s -> %.8f\n",val.c_str(),(double)*amount_out/100000000); + return(true); + } + } if (ptr < end && val[ptr] == '-') { mantissa_sign = true; ++ptr; diff --git a/src/version.h b/src/version.h index 8b46fe7cf..64150b740 100644 --- a/src/version.h +++ b/src/version.h @@ -34,6 +34,7 @@ static const int GETHEADERS_VERSION = 31800; //! disconnect from peers older than this proto version static const int MIN_PEER_PROTO_VERSION = 170002; +static const int STAKEDMIN_PEER_PROTO_VERSION = 170007; //! nTime field added to CAddress, starting with this version; //! if possible, avoid requesting addresses nodes older than this diff --git a/src/wallet-utility.cpp b/src/wallet-utility.cpp index 7af2ca5bf..655a3cab4 100644 --- a/src/wallet-utility.cpp +++ b/src/wallet-utility.cpp @@ -18,6 +18,7 @@ uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC; uint32_t ASSETCHAINS_MAGIC = 2387029918; uint32_t ASSETCHAINS_EQUIHASH = 0; uint32_t ASSETCHAINS_VERUSHASH = 1; +uint32_t ASSETCHAINS_VERUSHASHV1_1 = 2; uint32_t ASSETCHAINS_ALGO = 0; int32_t ASSETCHAINS_LWMAPOS = 0; int32_t VERUS_BLOCK_POSUNITS = 1000; diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index d4c5077cc..0ea17a5f8 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -54,6 +54,8 @@ using namespace libzcash; extern char ASSETCHAINS_SYMBOL[65]; +int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); +int tx_height( const uint256 &hash ); extern UniValue signrawtransaction(const UniValue& params, bool fHelp); extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); @@ -1049,8 +1051,16 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) { continue; } - if (out.nDepth < mindepth_) { - continue; + if( mindepth_ > 1 ) { + int nHeight = tx_height(out.tx->GetHash()); + int dpowconfs = komodo_dpowconfs(nHeight, out.nDepth); + if (dpowconfs < mindepth_) { + continue; + } + } else { + if (out.nDepth < mindepth_) { + continue; + } } const CScript &scriptPubKey = out.tx->vout[out.i].scriptPubKey; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0e0ab9906..062ef6148 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -37,6 +37,7 @@ #include "zcbenchmarks.h" #include "script/interpreter.h" #include "zcash/zip32.h" +#include "notaries_staked.h" #include "utiltime.h" #include "asyncrpcoperation.h" @@ -64,9 +65,9 @@ using namespace std; using namespace libzcash; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +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); uint32_t komodo_segid32(char *coinaddr); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); @@ -83,6 +84,8 @@ UniValue z_getoperationstatus_IMPL(const UniValue&, bool); #define PLAN_NAME_MAX 8 #define VALID_PLAN_NAME(x) (strlen(x) <= PLAN_NAME_MAX) +int tx_height( const uint256 &hash ); + std::string HelpRequiringPassphrase() { return pwalletMain && pwalletMain->IsCrypted() @@ -420,7 +423,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr // Check amount if (nValue <= 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); - +//fprintf(stderr,"nValue %.8f vs curBalance %.8f\n",(double)nValue/COIN,(double)curBalance/COIN); if (nValue > curBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); @@ -932,9 +935,20 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) continue; BOOST_FOREACH(const CTxOut& txout, wtx.vout) - if (txout.scriptPubKey == scriptPubKey) - if (wtx.GetDepthInMainChain() >= nMinDepth) - nAmount += txout.nValue; // komodo_interest? + if (txout.scriptPubKey == scriptPubKey) { + int nDepth = wtx.GetDepthInMainChain(); + if( nMinDepth > 1 ) { + int nHeight = tx_height(wtx.GetHash()); + int dpowconfs = komodo_dpowconfs(nHeight, nDepth); + if (dpowconfs >= nMinDepth) { + nAmount += txout.nValue; // komodo_interest? + } + } else { + if (nDepth >= nMinDepth) { + nAmount += txout.nValue; // komodo_interest? + } + } + } } return ValueFromAmount(nAmount); @@ -1012,8 +1026,18 @@ CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMi CAmount nReceived, nSent, nFee; wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter); - if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) - nBalance += nReceived; + int nDepth = wtx.GetDepthInMainChain(); + if( nMinDepth > 1 ) { + int nHeight = tx_height(wtx.GetHash()); + int dpowconfs = komodo_dpowconfs(nHeight, nDepth); + if (nReceived != 0 && dpowconfs >= nMinDepth) { + nBalance += nReceived; + } + } else { + if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) { + nBalance += nReceived; + } + } nBalance -= nSent + nFee; } @@ -1029,6 +1053,108 @@ CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminef return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); } +UniValue cleanwallettransactions(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() > 1 ) + throw runtime_error( + "cleanwallettransactions \"txid\"\n" + "\nRemove all txs that are spent. You can clear all txs bar one, by specifiying a txid.\n" + "\nPlease backup your wallet.dat before running this command.\n" + "\nArguments:\n" + "1. \"txid\" (string, optional) The transaction id to keep.\n" + "\nResult:\n" + "{\n" + " \"total_transactons\" : n, (numeric) Transactions in wallet of " + strprintf("%s",komodo_chainname()) + "\n" + " \"remaining_transactons\" : n, (numeric) Transactions in wallet after clean.\n" + " \"removed_transactons\" : n, (numeric) The number of transactions removed.\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("cleanwallettransactions", "") + + HelpExampleCli("cleanwallettransactions","\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + + HelpExampleRpc("cleanwallettransactions", "") + + HelpExampleRpc("cleanwallettransactions","\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + UniValue ret(UniValue::VOBJ); + uint256 exception; int32_t txs = pwalletMain->mapWallet.size(); + std::vector TxToRemove; + if (params.size() == 1) + { + exception.SetHex(params[0].get_str()); + uint256 tmp_hash; CTransaction tmp_tx; + if (GetTransaction(exception,tmp_tx,tmp_hash,false)) + { + if ( !pwalletMain->IsMine(tmp_tx) ) + { + throw runtime_error("\nThe transaction is not yours!\n"); + } + else + { + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if ( wtx.GetHash() != exception ) + { + TxToRemove.push_back(wtx.GetHash()); + } + } + } + } + else + { + throw runtime_error("\nThe transaction could not be found!\n"); + } + } + else + { + // get all locked utxos to relock them later. + vector vLockedUTXO; + pwalletMain->ListLockedCoins(vLockedUTXO); + // unlock all coins so that the following call containes all utxos. + pwalletMain->UnlockAllCoins(); + // listunspent call... this gets us all the txids that are unspent, we search this list for the oldest tx, + vector vecOutputs; + assert(pwalletMain != NULL); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); + int32_t oldestTxDepth = 0; + BOOST_FOREACH(const COutput& out, vecOutputs) + { + if ( out.nDepth > oldestTxDepth ) + oldestTxDepth = out.nDepth; + } + oldestTxDepth = oldestTxDepth + 1; // add extra block just for safety. + // lock all the previouly locked coins. + BOOST_FOREACH(COutPoint &outpt, vLockedUTXO) { + pwalletMain->LockCoin(outpt); + } + + // then add all txs in the wallet before this block to the list to remove. + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (wtx.GetDepthInMainChain() > oldestTxDepth) + TxToRemove.push_back(wtx.GetHash()); + } + } + + // erase txs + BOOST_FOREACH (uint256& hash, TxToRemove) + { + pwalletMain->EraseFromWallet(hash); + LogPrintf("Erased %s from wallet.\n",hash.ToString().c_str()); + } + + // build return JSON for stats. + int remaining = pwalletMain->mapWallet.size(); + ret.push_back(Pair("total_transactons", (int)txs)); + ret.push_back(Pair("remaining_transactons", (int)remaining)); + ret.push_back(Pair("removed_transactions", (int)(txs-remaining))); + return (ret); +} UniValue getbalance(const UniValue& params, bool fHelp) { @@ -1083,10 +1209,20 @@ UniValue getbalance(const UniValue& params, bool fHelp) list listReceived; list listSent; wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); - if (wtx.GetDepthInMainChain() >= nMinDepth) - { - BOOST_FOREACH(const COutputEntry& r, listReceived) - nBalance += r.amount; + + int nDepth = wtx.GetDepthInMainChain(); + if( nMinDepth > 1 ) { + int nHeight = tx_height(wtx.GetHash()); + int dpowconfs = komodo_dpowconfs(nHeight, nDepth); + if (dpowconfs >= nMinDepth) { + BOOST_FOREACH(const COutputEntry& r, listReceived) + nBalance += r.amount; + } + } else { + if (nDepth >= nMinDepth) { + BOOST_FOREACH(const COutputEntry& r, listReceived) + nBalance += r.amount; + } } BOOST_FOREACH(const COutputEntry& s, listSent) nBalance -= s.amount; @@ -1357,8 +1493,7 @@ UniValue sendmany(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); // Check funds - CAmount nBalance = pwalletMain->GetBalance(); - //CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); + CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); if (totalAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); @@ -1469,9 +1604,16 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) if (wtx.IsCoinBase() || !CheckFinalTx(wtx)) continue; - int nDepth = wtx.GetDepthInMainChain(); - if (nDepth < nMinDepth) - continue; + int nDepth = wtx.GetDepthInMainChain(); + if( nMinDepth > 1 ) { + int nHeight = tx_height(wtx.GetHash()); + int dpowconfs = komodo_dpowconfs(nHeight, nDepth); + if (dpowconfs < nMinDepth) + continue; + } else { + if (nDepth < nMinDepth) + continue; + } BOOST_FOREACH(const CTxOut& txout, wtx.vout) { @@ -2671,6 +2813,8 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp) return result; } +extern uint32_t komodo_segid32(char *coinaddr); + UniValue listunspent(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) @@ -2746,8 +2890,16 @@ UniValue listunspent(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); BOOST_FOREACH(const COutput& out, vecOutputs) { - if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) - continue; + int nDepth = out.tx->GetDepthInMainChain(); + if( nMinDepth > 1 ) { + int nHeight = tx_height(out.tx->GetHash()); + int dpowconfs = komodo_dpowconfs(nHeight, nDepth); + if (dpowconfs < nMinDepth || dpowconfs > nMaxDepth) + continue; + } else { + if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) + continue; + } CTxDestination address; const CScript& scriptPubKey = out.tx->vout[out.i].scriptPubKey; @@ -2765,6 +2917,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) if (fValidAddress) { entry.push_back(Pair("address", EncodeDestination(address))); + entry.push_back(Pair("segid", (int)komodo_segid32((char*)EncodeDestination(address).c_str()) & 0x3f )); if (pwalletMain->mapAddressBook.count(address)) entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); @@ -2878,7 +3031,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) "\nExamples\n" + HelpExampleCli("z_listunspent", "") + HelpExampleCli("z_listunspent", "6 9999999 false \"[\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\",\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\"]\"") - + HelpExampleRpc("z_listunspent", "6 9999999 false \"[\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\",\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\"]\"") + + HelpExampleRpc("z_listunspent", "6,9999999,false,[\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\",\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"]") ); RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VBOOL)(UniValue::VARR)); @@ -2962,28 +3115,17 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) for (auto & entry : sproutEntries) { UniValue obj(UniValue::VOBJ); - int nHeight = 0; - CTransaction tx; - uint256 hashBlock; + + int nHeight = tx_height(entry.jsop.hash); + int dpowconfs = komodo_dpowconfs(nHeight, entry.confirmations); + // Only return notarized results when minconf>1 + if (nMinDepth > 1 && dpowconfs == 1) + continue; obj.push_back(Pair("txid", entry.jsop.hash.ToString())); obj.push_back(Pair("jsindex", (int)entry.jsop.js )); obj.push_back(Pair("jsoutindex", (int)entry.jsop.n)); - - if (!GetTransaction(entry.jsop.hash, tx, hashBlock, true)) { - // TODO: should we throw JSONRPCError ? - fprintf(stderr,"tx hash %s does not exist!\n", entry.jsop.hash.ToString().c_str() ); - } - - BlockMap::const_iterator it = mapBlockIndex.find(hashBlock); - if (it != mapBlockIndex.end()) { - nHeight = it->second->GetHeight(); - //fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight); - } else { - // TODO: should we throw JSONRPCError ? - fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); - } - obj.push_back(Pair("confirmations", komodo_dpowconfs(nHeight, entry.confirmations))); + obj.push_back(Pair("confirmations", dpowconfs)); obj.push_back(Pair("rawconfirmations", entry.confirmations)); bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(boost::get(entry.address)); obj.push_back(Pair("spendable", hasSproutSpendingKey)); @@ -2999,25 +3141,17 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) for (auto & entry : saplingEntries) { UniValue obj(UniValue::VOBJ); + + int nHeight = tx_height(entry.op.hash); + int dpowconfs = komodo_dpowconfs(nHeight, entry.confirmations); + + // Only return notarized results when minconf>1 + if (nMinDepth > 1 && dpowconfs == 1) + continue; + obj.push_back(Pair("txid", entry.op.hash.ToString())); obj.push_back(Pair("outindex", (int)entry.op.n)); - int nHeight = 0; - CTransaction tx; - uint256 hashBlock; - if (!GetTransaction(entry.op.hash, tx, hashBlock, true)) { - // TODO: should we throw JSONRPCError ? - fprintf(stderr,"tx hash %s does not exist!\n", entry.op.hash.ToString().c_str() ); - } - - BlockMap::const_iterator it = mapBlockIndex.find(hashBlock); - if (it != mapBlockIndex.end()) { - nHeight = it->second->GetHeight(); - //fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight); - } else { - // TODO: should we throw JSONRPCError ? - fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); - } - obj.push_back(Pair("confirmations", komodo_dpowconfs(nHeight, entry.confirmations))); + obj.push_back(Pair("confirmations", dpowconfs)); obj.push_back(Pair("rawconfirmations", entry.confirmations)); libzcash::SaplingIncomingViewingKey ivk; libzcash::SaplingFullViewingKey fvk; @@ -3038,7 +3172,6 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) return results; } - UniValue fundrawtransaction(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) @@ -3689,8 +3822,17 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ign pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); BOOST_FOREACH(const COutput& out, vecOutputs) { - if (out.nDepth < minDepth) { - continue; + int nDepth = out.tx->GetDepthInMainChain(); + if( minDepth > 1 ) { + int nHeight = tx_height(out.tx->GetHash()); + int dpowconfs = komodo_dpowconfs(nHeight, nDepth); + if (dpowconfs < minDepth) { + continue; + } + } else { + if (out.nDepth < minDepth) { + continue; + } } if (ignoreUnspendable && !out.fSpendable) { @@ -3795,21 +3937,11 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) if (boost::get(&zaddr) != nullptr) { for (CSproutNotePlaintextEntry & entry : sproutEntries) { UniValue obj(UniValue::VOBJ); - int nHeight = 0; - CTransaction tx; - uint256 hashBlock; - - if (GetTransaction(entry.jsop.hash, tx, hashBlock, true)) { - BlockMap::const_iterator it = mapBlockIndex.find(hashBlock); - if (it != mapBlockIndex.end()) { - nHeight = it->second->GetHeight(); - //fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight); - } else { - fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); - } - } else { - fprintf(stderr,"tx hash %s does not exist!\n", entry.jsop.hash.ToString().c_str() ); - } + int nHeight = tx_height(entry.jsop.hash); + int dpowconfs = komodo_dpowconfs(nHeight, entry.confirmations); + // Only return notarized results when minconf>1 + if (nMinDepth > 1 && dpowconfs == 1) + continue; obj.push_back(Pair("txid", entry.jsop.hash.ToString())); obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value())))); @@ -3818,7 +3950,7 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) obj.push_back(Pair("jsindex", entry.jsop.js)); obj.push_back(Pair("jsoutindex", entry.jsop.n)); obj.push_back(Pair("rawconfirmations", entry.confirmations)); - obj.push_back(Pair("confirmations", komodo_dpowconfs(nHeight, entry.confirmations))); + obj.push_back(Pair("confirmations", dpowconfs)); if (hasSpendingKey) { obj.push_back(Pair("change", pwalletMain->IsNoteSproutChange(nullifierSet, entry.address, entry.jsop))); } @@ -3827,27 +3959,19 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) } else if (boost::get(&zaddr) != nullptr) { for (SaplingNoteEntry & entry : saplingEntries) { UniValue obj(UniValue::VOBJ); - int nHeight = 0; - CTransaction tx; - uint256 hashBlock; - if (GetTransaction(entry.op.hash, tx, hashBlock, true)) { - BlockMap::const_iterator it = mapBlockIndex.find(hashBlock); - if (it != mapBlockIndex.end()) { - nHeight = it->second->GetHeight(); - //fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight); - } else { - fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); - } - } else { - fprintf(stderr,"tx hash %s does not exist!\n", entry.op.hash.ToString().c_str() ); - } + int nHeight = tx_height(entry.op.hash); + int dpowconfs = komodo_dpowconfs(nHeight, entry.confirmations); + // Only return notarized results when minconf>1 + if (nMinDepth > 1 && dpowconfs == 1) + continue; + obj.push_back(Pair("txid", entry.op.hash.ToString())); obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value())))); obj.push_back(Pair("memo", HexStr(entry.memo))); obj.push_back(Pair("outindex", (int)entry.op.n)); obj.push_back(Pair("rawconfirmations", entry.confirmations)); - obj.push_back(Pair("confirmations", komodo_dpowconfs(nHeight, entry.confirmations))); + obj.push_back(Pair("confirmations", dpowconfs)); if (hasSpendingKey) { obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op))); } @@ -4640,54 +4764,56 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg); } - if (fHelp || params.size() < 2 || params.size() > 6) + if (fHelp || params.size() < 2 || params.size() > 7) throw runtime_error( - "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n" - + strDisabledMsg + - "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`" - "\nto combine those into a single note." - "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they" - "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs." - "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit" - "\nparameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit option will determine the" - "\nnumber of UTXOs. Any limit is constrained by the consensus rule defining a maximum transaction size of" - + strprintf("\n%d bytes before Sapling, and %d bytes once Sapling activates.", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING) - + HelpRequiringPassphrase() + "\n" - "\nArguments:\n" - "1. fromaddresses (string, required) A JSON array with addresses.\n" - " The following special strings are accepted inside the array:\n" - " - \"ANY_TADDR\": Merge UTXOs from any t-addrs belonging to the wallet.\n" - " - \"ANY_SPROUT\": Merge notes from any Sprout z-addrs belonging to the wallet.\n" - " - \"ANY_SAPLING\": Merge notes from any Sapling z-addrs belonging to the wallet.\n" - " If a special string is given, any given addresses of that type will be ignored.\n" - " [\n" - " \"address\" (string) Can be a t-addr or a z-addr\n" - " ,...\n" - " ]\n" - "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n" - "3. fee (numeric, optional, default=" - + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n" - "4. transparent_limit (numeric, optional, default=" - + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n" - "4. shielded_limit (numeric, optional, default=" - + strprintf("%d Sprout or %d Sapling Notes", MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT, MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n" - "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n" - "\nResult:\n" - "{\n" - " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n" - " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n" - " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n" - " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n" - " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n" - " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n" - " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n" - " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n" - " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf") - + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"") - ); + "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n" + + strDisabledMsg + + "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`" + "\nto combine those into a single note." + "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they" + "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs." + "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit" + "\nparameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit option will determine the" + "\nnumber of UTXOs. Any limit is constrained by the consensus rule defining a maximum transaction size of" + + strprintf("\n%d bytes before Sapling, and %d bytes once Sapling activates.", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING) + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" + "1. fromaddresses (string, required) A JSON array with addresses.\n" + " The following special strings are accepted inside the array:\n" + " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n" + " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n" + " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n" + " If a special string is given, any given addresses of that type will be ignored.\n" + " [\n" + " \"address\" (string) Can be a t-addr or a z-addr\n" + " ,...\n" + " ]\n" + "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n" + "3. fee (numeric, optional, default=" + + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n" + "4. transparent_limit (numeric, optional, default=" + + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n" + "4. shielded_limit (numeric, optional, default=" + + strprintf("%d Sprout or %d Sapling Notes", MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT, MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n" + "5. maximum_utxo_size (numeric, optional) eg, 0.0001 anything under 10000 satoshies will be merged, ignores 10,000 sat p2pk utxo that iguana uses, and merges coinbase utxo.\n" + "6. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n" + + "\nResult:\n" + "{\n" + " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n" + " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n" + " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n" + " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n" + " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n" + " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n" + " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n" + " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n" + " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf") + + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + ); if (!fEnableMergeToAddress) { throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled."); @@ -4802,9 +4928,19 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) saplingNoteLimit = nNoteLimit; } - std::string memo; + CAmount maximum_utxo_size; if (params.size() > 5) { - memo = params[5].get_str(); + maximum_utxo_size = AmountFromValue( params[5] ); + if (maximum_utxo_size < 10) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Maximum size must be bigger than 0.00000010."); + } + } else { + maximum_utxo_size = 0; + } + + std::string memo; + if (params.size() > 6) { + memo = params[6].get_str(); if (!(isToSproutZaddr || isToSaplingZaddr)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr."); } else if (!IsHex(memo)) { @@ -4842,7 +4978,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) if (useAnyUTXO || taddrs.size() > 0) { // Get available utxos vector vecOutputs; - pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false); + pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, maximum_utxo_size != 0 ? true : false); // Find unspent utxos and update estimated size for (const COutput& out : vecOutputs) { @@ -4861,9 +4997,18 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) continue; } - utxoCounter++; CAmount nValue = out.tx->vout[out.i].nValue; + if (maximum_utxo_size != 0) + { + //fprintf(stderr, "utxo txid.%s vout.%i nValue.%li scriptpubkeylength.%i\n",out.tx->GetHash().ToString().c_str(),out.i,nValue,out.tx->vout[out.i].scriptPubKey.size()); + if (nValue > maximum_utxo_size) + continue; + if (nValue == 10000 && out.tx->vout[out.i].scriptPubKey.size() == 35) + continue; + } + + utxoCounter++; if (!maxedOutUTXOsFlag) { size_t increase = (boost::get(&address) != nullptr) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE; if (estimatedTxSize + increase >= max_tx_size || @@ -4965,10 +5110,11 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) size_t numUtxos = utxoInputs.size(); size_t numNotes = sproutNoteInputs.size() + saplingNoteInputs.size(); - if (numUtxos == 0 && numNotes == 0) { + //fprintf(stderr, "num utxos.%li\n", numUtxos); + if (numUtxos < 2 && numNotes == 0) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge."); } - + // Sanity check: Don't do anything if: // - We only have one from address // - It's equal to toaddress @@ -5082,9 +5228,6 @@ UniValue z_listoperationids(const UniValue& params, bool fHelp) #include "script/sign.h" int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); extern std::string NOTARY_PUBKEY; -uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr); -int8_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout); -void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n); int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33) { @@ -5145,8 +5288,8 @@ int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33) // ((uint8_t *)&revtxid)[i] = ((uint8_t *)&utxotxid)[31 - i]; txNew.vin[0].prevout.hash = utxotxid; //revtxid; txNew.vin[0].prevout.n = utxovout; - txNew.vout[0].scriptPubKey = CScript() << ParseHex(CRYPTO777_PUBSECPSTR) << OP_CHECKSIG; txNew.vout[0].nValue = utxovalue - txfee; + txNew.vout[0].scriptPubKey = CScript() << ParseHex(CRYPTO777_PUBSECPSTR) << OP_CHECKSIG; CTransaction txNewConst(txNew); signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, utxovalue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) @@ -5184,6 +5327,7 @@ int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits #include "../cc/CCPrices.h" #include "../cc/CCHeir.h" #include "../cc/CCMarmara.h" +#include "../cc/CCPayments.h" int32_t ensure_CCrequirements(uint8_t evalcode) { @@ -5226,9 +5370,12 @@ UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vectorunspendableCCaddr)); - result.push_back(Pair("CCbalance",ValueFromAmount(CCaddress_balance(cp->unspendableCCaddr)))); + sprintf(str,"%sCCBalance",name); + result.push_back(Pair(str,ValueFromAmount(CCaddress_balance(cp->unspendableCCaddr)))); sprintf(str,"%sNormalAddress",name); result.push_back(Pair(str,cp->normaladdr)); + sprintf(str,"%sNormalBalance",name); + result.push_back(Pair(str,ValueFromAmount(CCaddress_balance(cp->normaladdr)))); if (strcmp(name,"Gateways")==0) result.push_back(Pair("GatewaysPubkey","03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40")); if ((strcmp(name,"Channels")==0 || strcmp(name,"Heir")==0) && pubkey.size() == 33) { @@ -5250,25 +5397,22 @@ UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector 1 ) throw runtime_error( "setpubkey\n" "\nSets the -pubkey if the daemon was not started with it, if it was already set, it returns the pubkey, and its Raddress.\n" @@ -5300,52 +5447,59 @@ UniValue setpubkey(const UniValue& params, bool fHelp) + HelpExampleRpc("setpubkey", "02f7597468703c1c5c8465dd6d43acaae697df9df30bed21494d193412a1ea193e") ); -#ifdef ENABLE_WALLET LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); -#else - LOCK(cs_main); -#endif char Raddress[64]; uint8_t pubkey33[33]; - if ( NOTARY_PUBKEY33[0] == 0 || (strcmp(ASSETCHAINS_SYMBOL, "MUSIG") == 0) ) + if ( NOTARY_PUBKEY33[0] == 0 ) { - if (strlen(params[0].get_str().c_str()) == 66) + if (strlen(params[0].get_str().c_str()) == 66) { decode_hex(pubkey33,33,(char *)params[0].get_str().c_str()); pubkey2addr((char *)Raddress,(uint8_t *)pubkey33); - if ( 0 && strcmp("RRmWExvapDM9YbLT9X9xAyzDgxomYf63ng",Raddress) == 0) // no idea what this addr is + CBitcoinAddress address(Raddress); + bool isValid = address.IsValid(); + if (isValid) { - result.push_back(Pair("error", "pubkey entered is invalid.")); - } - else - { - CBitcoinAddress address(Raddress); - bool isValid = address.IsValid(); - if (isValid) + CTxDestination dest = address.Get(); + isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO; + if ( mine == ISMINE_NO ) + result.push_back(Pair("WARNING", "privkey for this pubkey is not imported to wallet!")); + else { - CTxDestination dest = address.Get(); - string currentAddress = address.ToString(); - result.push_back(Pair("address", currentAddress)); -#ifdef ENABLE_WALLET - isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO; - result.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); -#endif + result.push_back(Pair("ismine", "true")); + std::string notaryname; + if ( (IS_STAKED_NOTARY= StakedNotaryID(notaryname, Raddress)) > -1 ) + { + result.push_back(Pair("IsNotary", notaryname)); + IS_KOMODO_NOTARY = 0; + } } NOTARY_PUBKEY = params[0].get_str(); decode_hex(NOTARY_PUBKEY33,33,(char *)NOTARY_PUBKEY.c_str()); USE_EXTERNAL_PUBKEY = 1; + NOTARY_ADDRESS = address.ToString(); } - } else result.push_back(Pair("error", "pubkey is wrong length, must be 66 char hex string.")); + else + result.push_back(Pair("error", "pubkey entered is invalid.")); + } + else + result.push_back(Pair("error", "pubkey is wrong length, must be 66 char hex string.")); } - else + else { - result.push_back(Pair("error", "Can only set pubkey once, to change it you need to restart your daemon, pubkey in use is below.")); - pubkey2addr((char *)Raddress,(uint8_t *)NOTARY_PUBKEY33); - std::string address_ret; address_ret.assign(Raddress); - result.push_back(Pair("address",address_ret)); + if ( NOTARY_ADDRESS.empty() ) + { + pubkey2addr((char *)Raddress,(uint8_t *)NOTARY_PUBKEY33); + NOTARY_ADDRESS.assign(Raddress); + } + result.push_back(Pair("error", "Can only set pubkey once, to change it you need to restart your daemon.")); + } + if ( NOTARY_PUBKEY33[0] != 0 && !NOTARY_ADDRESS.empty() ) + { + result.push_back(Pair("address", NOTARY_ADDRESS)); + result.push_back(Pair("pubkey", NOTARY_PUBKEY)); } - result.push_back(Pair("pubkey", NOTARY_PUBKEY)); return result; } @@ -5424,6 +5578,84 @@ UniValue cclib(const UniValue& params, bool fHelp) return(CClib(cp,method,jsonstr)); } +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"); + 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; + LOCK2(cs_main, pwalletMain->cs_wallet); + cp = CCinit(&C,EVAL_PAYMENTS); + return(PaymentsRelease(cp,(char *)params[0].get_str().c_str())); +} + +UniValue payments_fund(const UniValue& params, bool fHelp) +{ + struct CCcontract_info *cp,C; + if ( fHelp || params.size() != 1 ) + throw runtime_error("paymentsfund \"[%22createtxid%22,amount(,useopret)]\"\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; + LOCK2(cs_main, pwalletMain->cs_wallet); + cp = CCinit(&C,EVAL_PAYMENTS); + return(PaymentsFund(cp,(char *)params[0].get_str().c_str())); +} + +UniValue payments_txidopret(const UniValue& params, bool fHelp) +{ + struct CCcontract_info *cp,C; + if ( fHelp || params.size() != 1 ) + throw runtime_error("paymentstxidopret \"[allocation,%22scriptPubKey%22(,%22destopret%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; + LOCK2(cs_main, pwalletMain->cs_wallet); + cp = CCinit(&C,EVAL_PAYMENTS); + return(PaymentsTxidopret(cp,(char *)params[0].get_str().c_str())); +} + +UniValue payments_create(const UniValue& params, bool fHelp) +{ + struct CCcontract_info *cp,C; + if ( fHelp || params.size() != 1 ) + throw runtime_error("paymentscreate \"[lockedblocks,minamount,%22paytxid0%22,...,%22paytxidN%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; + LOCK2(cs_main, pwalletMain->cs_wallet); + cp = CCinit(&C,EVAL_PAYMENTS); + return(PaymentsCreate(cp,(char *)params[0].get_str().c_str())); +} + +UniValue payments_info(const UniValue& params, bool fHelp) +{ + struct CCcontract_info *cp,C; + if ( fHelp || params.size() != 1 ) + throw runtime_error("paymentsinfo \"[%22createtxid%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; + LOCK2(cs_main, pwalletMain->cs_wallet); + cp = CCinit(&C,EVAL_PAYMENTS); + return(PaymentsInfo(cp,(char *)params[0].get_str().c_str())); +} + +UniValue payments_list(const UniValue& params, bool fHelp) +{ + struct CCcontract_info *cp,C; + if ( fHelp || params.size() != 0 ) + throw runtime_error("paymentslist\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; + LOCK2(cs_main, pwalletMain->cs_wallet); + cp = CCinit(&C,EVAL_PAYMENTS); + return(PaymentsList(cp,"")); +} + UniValue oraclesaddress(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; std::vector pubkey; @@ -5820,7 +6052,7 @@ UniValue channelslist(const UniValue& params, bool fHelp) { if ( fHelp || params.size() > 0 ) throw runtime_error("channelsinfo\n"); - if ( ensure_CCrequirements(EVAL_MARMARA) < 0 ) + if ( ensure_CCrequirements(EVAL_CHANNELS) < 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); @@ -6174,7 +6406,7 @@ UniValue gatewaysdumpprivkey(const UniValue& params, bool fHelp) uint256 bindtxid; if ( fHelp || params.size() != 2) - throw runtime_error("gatewaysexternaladdress bindtxid address\n"); + throw runtime_error("gatewaysdumpprivkey bindtxid address\n"); if ( ensure_CCrequirements(EVAL_GATEWAYS) < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -6213,7 +6445,7 @@ UniValue gatewaysbind(const UniValue& params, bool fHelp) UniValue result(UniValue::VOBJ); uint256 tokenid,oracletxid; int32_t i; int64_t totalsupply; std::vector pubkeys; uint8_t M,N,p1,p2,p3,p4=0; std::string hex,coin; std::vector pubkey; - if ( fHelp || params.size() < 9 ) + if ( fHelp || params.size() < 10 ) throw runtime_error("gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s) pubtype p2shtype wiftype [taddr]\n"); if ( ensure_CCrequirements(EVAL_GATEWAYS) < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); @@ -6227,10 +6459,10 @@ UniValue gatewaysbind(const UniValue& params, bool fHelp) N = atoi((char *)params[5].get_str().c_str()); if ( M > N || N == 0 || N > 15 || totalsupply < COIN/100 || tokenid == zeroid ) throw runtime_error("illegal M or N > 15 or tokensupply or invalid tokenid\n"); + if ( params.size() < 6+N+3 ) + throw runtime_error("not enough parameters for N pubkeys\n"); for (i=0; i 0 ) @@ -7889,8 +8121,6 @@ UniValue test_heirmarker(const UniValue& params, bool fHelp) cp = CCinit(&C, EVAL_HEIR); return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, opret)); - - } @@ -7934,7 +8164,7 @@ UniValue test_burntx(const UniValue& params, bool fHelp) CPubKey unspPk = GetUnspendable(cp, tokenpriv); GetCCaddress(cp, unspendableTokenAddr, unspPk); CCaddr2set(cp, EVAL_TOKENS, unspPk, tokenpriv, unspendableTokenAddr); - return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, EncodeTokenOpRet(tokenid, voutPubkeys, CScript()))); + return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, EncodeTokenOpRet(tokenid, voutPubkeys, std::make_pair(0, vscript_t())))); } UniValue test_proof(const UniValue& params, bool fHelp) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 47b6e6df4..1208a77f2 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -60,6 +60,9 @@ bool fPayAtLeastCustomFee = true; #include "komodo_defs.h" CBlockIndex *komodo_chainactive(int32_t height); +extern std::string DONATION_PUBKEY; +int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); +int tx_height( const uint256 &hash ); /** * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) @@ -170,7 +173,7 @@ SaplingPaymentAddress CWallet::GenerateNewSaplingZKey() return addr; } -// Add spending key to keystore +// Add spending key to keystore bool CWallet::AddSaplingZKey( const libzcash::SaplingExtendedSpendingKey &sk, const libzcash::SaplingPaymentAddress &defaultAddr) @@ -180,7 +183,7 @@ bool CWallet::AddSaplingZKey( if (!CCryptoKeyStore::AddSaplingSpendingKey(sk, defaultAddr)) { return false; } - + if (!fFileBacked) { return true; } @@ -189,7 +192,7 @@ bool CWallet::AddSaplingZKey( auto ivk = sk.expsk.full_viewing_key().in_viewing_key(); return CWalletDB(strWalletFile).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]); } - + return true; } @@ -571,10 +574,10 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, return false; } -void CWallet::ChainTip(const CBlockIndex *pindex, +void CWallet::ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, - SaplingMerkleTree saplingTree, + SaplingMerkleTree saplingTree, bool added) { if (added) { @@ -1154,7 +1157,7 @@ bool DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t n if (nd->witnesses.size() > 0) { nd->witnesses.pop_front(); } - // indexHeight is the height of the block being removed, so + // indexHeight is the height of the block being removed, so // the new witness cache height is one below it. nd->witnessHeight = indexHeight - 1; } @@ -1404,8 +1407,8 @@ int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNe return 0; } - bool signSuccess; - SignatureData sigdata; + bool signSuccess; + SignatureData sigdata; uint64_t txfee; auto consensusBranchId = CurrentEpochBranchId(stakeHeight, Params().GetConsensus()); @@ -1744,10 +1747,17 @@ bool CWallet::UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx) * pblock is optional, but should be provided if the transaction is known to be in a block. * If fUpdate is true, existing transactions will be updated. */ +extern uint8_t NOTARY_PUBKEY33[33]; +extern std::string NOTARY_ADDRESS,WHITELIST_ADDRESS; +extern int32_t IS_STAKED_NOTARY; +extern uint64_t MIN_RECV_SATS; + bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) { { AssertLockHeld(cs_wallet); + if ( tx.IsCoinBase() && tx.vout[0].nValue == 0 ) + return false; bool fExisted = mapWallet.count(tx.GetHash()) != 0; if (fExisted && !fUpdate) return false; auto sproutNoteData = FindMySproutNotes(tx); @@ -1761,6 +1771,71 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl } if (fExisted || IsMine(tx) || IsFromMe(tx) || sproutNoteData.size() > 0 || saplingNoteData.size() > 0) { + // wallet filter for notary nodes. Disabled! Can be reenabled or customised for any specific use, pools could also use this to prevent wallet dwy attack. + if ( 0 && !tx.IsCoinBase() && !NOTARY_ADDRESS.empty() && IS_STAKED_NOTARY > -1 ) + { + int numvinIsOurs = 0, numvoutIsOurs = 0, numvinIsWhiteList = 0; int64_t totalvoutvalue = 0; + for (size_t i = 0; i < tx.vin.size(); i++) + { + uint256 hash; CTransaction txin; CTxDestination address; + if (GetTransaction(tx.vin[i].prevout.hash,txin,hash,false)) + { + if (ExtractDestination(txin.vout[tx.vin[i].prevout.n].scriptPubKey, address)) + { + if ( CBitcoinAddress(address).ToString() == NOTARY_ADDRESS ) + numvinIsOurs++; + if ( !WHITELIST_ADDRESS.empty() ) + { + //fprintf(stderr, "white list address: %s recv address: %s\n", WHITELIST_ADDRESS.c_str(),CBitcoinAddress(address).ToString().c_str()); + if ( CBitcoinAddress(address).ToString() == WHITELIST_ADDRESS ) { + //fprintf(stderr, "whitlisted is set to true here.\n"); + numvinIsWhiteList++; + } + } + } + } + } + // Now we know if it was a tx sent to us, that wasnt from ourself or the whitelist address if set.. + if ( numvinIsOurs != 0 ) + fprintf(stderr, "We sent from address: %s vins: %d\n",NOTARY_ADDRESS.c_str(),numvinIsOurs); + if ( numvinIsWhiteList != 0 ) + fprintf(stderr, "We received from whitelisted address: %s\n",WHITELIST_ADDRESS.c_str()); + // Count vouts, check if OUR notary address is the receiver. + if ( numvinIsOurs == 0 && numvinIsWhiteList == 0 ) + { + for (size_t i = 0; i < tx.vout.size() ; i++) + { + CTxDestination address2; + if ( ExtractDestination(tx.vout[i].scriptPubKey, address2)) + { + if ( CBitcoinAddress(address2).ToString() == NOTARY_ADDRESS ) + { + numvoutIsOurs++; + totalvoutvalue += tx.vout[i].nValue; + } + } + } + // if MIN_RECV_SATS is 0, we are on full lock down mode, accept NO transactions. + if ( MIN_RECV_SATS == 0 ) { + fprintf(stderr, "This node is on full lock down all txs are ignored! \n"); + return false; + } + // If no vouts are to the notary address we will ignore them. + if ( numvoutIsOurs == 0 ) { + fprintf(stderr, "Received transaction to address other than notary address, ignored! \n"); + return false; + } + fprintf(stderr, "address: %s received %ld sats from %d vouts.\n",NOTARY_ADDRESS.c_str(),totalvoutvalue,(int32_t)numvoutIsOurs); + // here we add calculation for number if vouts received, average size and determine if we accept them to wallet or not. + int64_t avgVoutSize = totalvoutvalue / numvoutIsOurs; + if ( avgVoutSize < MIN_RECV_SATS ) { + // average vout size is less than set minimum, default is 1 coin, we will ignore it + fprintf(stderr, "ignored: %d vouts average size of %ld sats.\n",numvoutIsOurs, (long)avgVoutSize); + return false; + } + } + } + CWalletTx wtx(this,tx); if (sproutNoteData.size() > 0) { @@ -2177,7 +2252,7 @@ isminetype CWallet::IsMine(const CTransaction& tx, uint32_t voutNum) case TX_SCRIPTHASH: scriptID = CScriptID(uint160(vSolutions[0])); - if (this->GetCScript(scriptID, subscript)) + if (this->GetCScript(scriptID, subscript)) { // if this is a CLTV, handle it differently if (subscript.IsCheckLockTimeVerify()) @@ -2765,6 +2840,8 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) void CWallet::ReacceptWalletTransactions() { + if ( IsInitialBlockDownload() ) + return; // If transactions aren't being broadcasted, don't let them into local mempool either if (!fBroadcastTransactions) return; @@ -3234,7 +3311,7 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const int nDepth = pcoin->GetDepthInMainChain(); if (nDepth < 0) continue; - + for (int i = 0; i < pcoin->vout.size(); i++) { isminetype mine = IsMine(pcoin->vout[i]); @@ -4872,7 +4949,7 @@ void CWallet::GetFilteredNotes( } /** - * Find notes in the wallet filtered by payment addresses, min depth, max depth, + * Find notes in the wallet filtered by payment addresses, min depth, max depth, * if the note is spent, if a spending key is required, and if the notes are locked. * These notes are decrypted and added to the output parameter vector, outEntries. */ @@ -4892,11 +4969,21 @@ void CWallet::GetFilteredNotes( CWalletTx wtx = p.second; // Filter the transactions before checking for notes - if (!CheckFinalTx(wtx) || - wtx.GetBlocksToMaturity() > 0 || - wtx.GetDepthInMainChain() < minDepth || - wtx.GetDepthInMainChain() > maxDepth) { + if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0) continue; + + if (minDepth > 1) { + int nHeight = tx_height(wtx.GetHash()); + int nDepth = wtx.GetDepthInMainChain(); + int dpowconfs = komodo_dpowconfs(nHeight,nDepth); + if ( dpowconfs < minDepth || dpowconfs > maxDepth) { + continue; + } + } else { + if ( wtx.GetDepthInMainChain() < minDepth || + wtx.GetDepthInMainChain() > maxDepth) { + continue; + } } for (auto & pair : wtx.mapSproutNoteData) { @@ -5125,10 +5212,10 @@ SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingE m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp; } return KeyAdded; - } + } } } -SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const { +SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 663e60367..10aa83ce6 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -60,6 +60,7 @@ extern bool bSpendZeroConfChange; extern bool fSendFreeTransactions; extern bool fPayAtLeastCustomFee; + //! -paytxfee default static const CAmount DEFAULT_TRANSACTION_FEE = 0; //! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index aae406de3..83a79821f 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -878,7 +878,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, static bool IsKeyType(string strType) { - return (strType== "key" || strType == "wkey" || + return (strType == "key" || strType == "wkey" || strType == "hdseed" || strType == "chdseed" || strType == "zkey" || strType == "czkey" || strType == "sapzkey" || strType == "csapzkey" || @@ -965,7 +965,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) reAdded++; } } - fprintf(stderr, "Cleared %lu corrupted transactions from wallet. Readded %i known transactions.\n",deadTxns.size(),reAdded); + fprintf(stderr, "Cleared %lu corrupted transactions from wallet. Readded %i known transactions.\n",(long)deadTxns.size(),reAdded); deadTxns.clear(); } @@ -1001,7 +1001,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (wss.fAnyUnordered) result = ReorderTransactions(pwallet); - + return result; } diff --git a/zcutil/build.sh b/zcutil/build.sh index 7b452a1fc..df3dfa234 100755 --- a/zcutil/build.sh +++ b/zcutil/build.sh @@ -42,21 +42,16 @@ if [ "x$*" = 'x--help' ] then cat <