Merge pull request #153 from jl777/dev

sync dev
This commit is contained in:
ca333
2019-04-18 23:07:26 +02:00
committed by GitHub
303 changed files with 81214 additions and 4493 deletions

33
.gitignore vendored
View File

@@ -11,7 +11,7 @@ src/test/test_bitcoin
*zcashTest.vk
# autoreconf
Makefile.in
#Makefile.in
aclocal.m4
autom4te.cache/
build-aux/config.guess
@@ -29,7 +29,7 @@ build-aux/compile
build-aux/test-driver
config.log
config.status
configure
#configure
libtool
src/config/bitcoin-config.h
src/config/bitcoin-config.h.in
@@ -126,3 +126,32 @@ src/komodo-tx.exe
src/cryptoconditions/compile
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
src/rogue.530623577502174316.pack
src/rogue.530623577502174316.player
src/cc/rogue/config.h
src/cc/rogue/config.h
src/ROGUE.conf
src/rogue.scr
src/cc/rogue/confdefs.h
src/cc/rogue/x64

View File

@@ -32,9 +32,9 @@ build:ubuntu:
variables:
DOCKER_DRIVER: overlay2
cache:
key: "${CI_JOB_NAME}${CI_COMMIT_REF_NAME}"
key: ${CI_COMMIT_REF_SLUG}
paths:
- depends/built
- depends/
script:
- zcutil/build.sh -j$(nproc)
- mkdir ${PACKAGE_DIR_LINUX}
@@ -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}

View File

@@ -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

View File

@@ -884,6 +884,7 @@ fi
AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin])
AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin])
AM_CONDITIONAL([TARGET_LINUX], [test x$TARGET_OS = xlinux])
AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows])
AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes])
AM_CONDITIONAL([ENABLE_MINING],[test x$enable_mining = xyes])

View File

@@ -1,9 +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

View File

@@ -1,12 +1,3 @@
ifeq ($(build_os),darwin)
package=libsodium
$(package)_version=1.0.11
$(package)_download_path=https://supernetorg.bintray.com/misc
$(package)_file_name=libsodium-1.0.11.tar.gz
$(package)_sha256_hash=a14549db3c49f6ae2170cbbf4664bd48ace50681045e8dbea7c8d9fb96f9c765
$(package)_dependencies=
$(package)_config_opts=
else
package=libsodium
$(package)_version=1.0.15
$(package)_download_path=https://download.libsodium.org/libsodium/releases/old
@@ -14,6 +5,13 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=fb6a9e879a2f674592e4328c5d9f79f082405ee4bb05cb6e679b90afe9e178f4
$(package)_dependencies=
$(package)_config_opts=
ifeq ($(build_os),darwin)
define $(package)_set_vars
$(package)_build_env=MACOSX_DEPLOYMENT_TARGET="10.11"
$(package)_cc=clang
$(package)_cxx=clang++
endef
endif
define $(package)_preprocess_cmds

View File

@@ -1,8 +1,8 @@
package=openssl
$(package)_version=1.1.0h
$(package)_version=1.1.1a
$(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=5835626cde9e99656585fc7aaa2302a73a7e1340bf8c14fd635a62c66802a517
$(package)_sha256_hash=fc20130f8b7cbd2fb918b2f14e2f429e109c31ddd0fb38fc5d71d9ffed3f9f41
define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
@@ -92,7 +92,7 @@ $(package)_config_opts_i686_mingw32=mingw
endef
define $(package)_preprocess_cmds
sed -i.old "/define DATE/d" util/mkbuildinf.pl && \
sed -i.old 's/built on: $date/built on: not available/' util/mkbuildinf.pl && \
sed -i.old "s|\"engines\", \"apps\", \"test\"|\"engines\"|" Configure
endef

View File

@@ -1,13 +1,13 @@
package=rust
$(package)_version=1.28.0
$(package)_version=1.32.0
$(package)_download_path=https://static.rust-lang.org/dist
$(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz
$(package)_sha256_hash_linux=2a1390340db1d24a9498036884e6b2748e9b4b057fc5219694e298bdaa37b810
$(package)_sha256_hash_linux=e024698320d76b74daf0e6e71be3681a1e7923122e3ebd03673fcac3ecc23810
$(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz
$(package)_sha256_hash_darwin=5d7a70ed4701fe9410041c1eea025c95cad97e5b3d8acc46426f9ac4f9f02393
$(package)_sha256_hash_darwin=f0dfba507192f9b5c330b5984ba71d57d434475f3d62bd44a39201e36fa76304
$(package)_file_name_mingw32=rust-$($(package)_version)-x86_64-pc-windows-gnu.tar.gz
$(package)_sha256_hash_mingw32=55c07426f791c51c8a2b6934b35784175c4abb4e03f123f3e847109c4dc1ad8b
$(package)_sha256_hash_mingw32=358e1435347c67dbf33aa9cad6fe501a833d6633ed5d5aa1863d5dffa0349be9
ifeq ($(build_os),darwin)
$(package)_file_name=$($(package)_file_name_darwin)

View File

@@ -1,23 +1,23 @@
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.2.1
$(package)_version=4.3.1
$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=27d1e82a099228ee85a7ddb2260f40830212402c605a4a10b5e5498a7e0e9d03
$(package)_sha256_hash=bcbabe1e2c7d0eec4ed612e10b94b112dd5f06fcefa994a0c79a45d835cd21eb
define $(package)_set_vars
$(package)_config_opts=--without-documentation --disable-shared --disable-curve

View File

@@ -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

View File

@@ -11,6 +11,8 @@ export BITCOIND=${REAL_BITCOIND}
#Run the tests
testScripts=(
'dpow.py'
'dpowconfs.py'
'ac_private.py'
'verushash.py'
'paymentdisclosure.py'

49
qa/rpc-tests/cryptoconditions.py Executable file → Normal file
View File

@@ -3,7 +3,6 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, assert_greater_than, \
@@ -25,7 +24,6 @@ def generate_random_string(length):
random_string = ''.join(choice(ascii_uppercase) for i in range(length))
return random_string
class CryptoConditionsTest (BitcoinTestFramework):
def setup_chain(self):
@@ -105,13 +103,13 @@ class CryptoConditionsTest (BitcoinTestFramework):
faucet = rpc.faucetaddress()
assert_equal(faucet['result'], 'success')
# verify all keys look like valid AC addrs, could be better
for x in ['myCCaddress', 'FaucetCCaddress', 'Faucetmarker', 'myaddress']:
for x in ['myCCAddress(Faucet)', 'FaucetCCAddress', 'FaucetCCTokensAddress', 'myaddress', 'FaucetNormalAddress']:
assert_equal(faucet[x][0], 'R')
result = rpc.faucetaddress(self.pubkey)
assert_success(result)
# test that additional CCaddress key is returned
for x in ['myCCaddress', 'FaucetCCaddress', 'Faucetmarker', 'myaddress', 'CCaddress']:
for x in ['myCCAddress(Faucet)', 'FaucetCCAddress', 'FaucetCCTokensAddress', 'myaddress', 'FaucetNormalAddress']:
assert_equal(result[x][0], 'R')
# no funds in the faucet yet
@@ -179,12 +177,12 @@ class CryptoConditionsTest (BitcoinTestFramework):
dice = rpc.diceaddress()
assert_equal(dice['result'], 'success')
for x in ['myCCaddress', 'DiceCCaddress', 'Dicemarker', 'myaddress']:
for x in ['myCCAddress(Dice)', 'DiceCCAddress', 'DiceCCTokensAddress', 'myaddress', 'DiceNormalAddress']:
assert_equal(dice[x][0], 'R')
dice = rpc.diceaddress(self.pubkey)
assert_equal(dice['result'], 'success')
for x in ['myCCaddress', 'DiceCCaddress', 'Dicemarker', 'myaddress', 'CCaddress']:
for x in ['myCCAddress(Dice)', 'DiceCCAddress', 'DiceCCTokensAddress', 'myaddress', 'DiceNormalAddress']:
assert_equal(dice[x][0], 'R')
# no dice created yet
@@ -333,12 +331,12 @@ class CryptoConditionsTest (BitcoinTestFramework):
rpc = self.nodes[0]
result = rpc.tokenaddress()
assert_success(result)
for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress']:
for x in ['myCCAddress(Tokens)', 'TokensNormalAddress', 'TokensNormalAddress', 'myaddress','TokensCCAddress']:
assert_equal(result[x][0], 'R')
result = rpc.tokenaddress(self.pubkey)
assert_success(result)
for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress', 'CCaddress']:
for x in ['myCCAddress(Tokens)', 'TokensNormalAddress', 'TokensNormalAddress', 'myaddress','TokensCCAddress']:
assert_equal(result[x][0], 'R')
# there are no tokens created yet
result = rpc.tokenlist()
@@ -361,17 +359,6 @@ class CryptoConditionsTest (BitcoinTestFramework):
result = rpc.tokenlist()
assert_equal(result[0], tokenid)
# there are no token orders yet
result = rpc.tokenorders()
assert_equal(result, [])
# getting token balance for pubkey
result = rpc.tokenbalance(self.pubkey)
assert_success(result)
assert_equal(result['balance'], 0)
assert_equal(result['CCaddress'], 'RCRsm3VBXz8kKTsYaXKpy7pSEzrtNNQGJC')
assert_equal(result['tokenid'], self.pubkey)
# get token balance for token with pubkey
result = rpc.tokenbalance(tokenid, self.pubkey)
assert_success(result)
@@ -421,7 +408,7 @@ class CryptoConditionsTest (BitcoinTestFramework):
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"
@@ -440,7 +427,7 @@ class CryptoConditionsTest (BitcoinTestFramework):
assert txid, "found txid"
# should be no token orders
result = rpc.tokenorders()
result = rpc.tokenorders(tokenid)
assert_equal(result, [])
# checking ask cancellation
@@ -448,7 +435,7 @@ class CryptoConditionsTest (BitcoinTestFramework):
testorderid = self.send_and_mine(testorder['hex'], rpc)
cancel = rpc.tokencancelask(tokenid, testorderid)
self.send_and_mine(cancel["hex"], rpc)
result = rpc.tokenorders()
result = rpc.tokenorders(tokenid)
assert_equal(result, [])
# invalid numtokens bid
@@ -474,7 +461,7 @@ class CryptoConditionsTest (BitcoinTestFramework):
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"
@@ -493,7 +480,7 @@ class CryptoConditionsTest (BitcoinTestFramework):
assert txid, "found txid"
# should be no token orders
result = rpc.tokenorders()
result = rpc.tokenorders(tokenid)
assert_equal(result, [])
# checking bid cancellation
@@ -501,7 +488,7 @@ class CryptoConditionsTest (BitcoinTestFramework):
testorderid = self.send_and_mine(testorder['hex'], rpc)
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!)
@@ -522,11 +509,11 @@ class CryptoConditionsTest (BitcoinTestFramework):
def run_rewards_tests(self):
rpc = self.nodes[0]
result = rpc.rewardsaddress()
for x in ['RewardsCCaddress', 'myCCaddress', 'Rewardsmarker', 'myaddress']:
for x in ['myCCAddress(Rewards)', '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(Rewards)', 'myaddress', 'RewardsCCAddress', 'RewardsCCTokensAddress', 'RewardsNormalAddress']:
assert_equal(result[x][0], 'R')
# no rewards yet
@@ -637,12 +624,13 @@ class CryptoConditionsTest (BitcoinTestFramework):
result = rpc.oraclesaddress()
assert_success(result)
for x in ['OraclesCCaddress', 'Oraclesmarker', 'myCCaddress', 'myaddress']:
for x in ['OraclesCCAddress', 'OraclesNormalAddress', 'myCCAddress(Oracles)','OraclesCCTokensAddress', 'myaddress']:
assert_equal(result[x][0], 'R')
result = rpc.oraclesaddress(self.pubkey)
assert_success(result)
for x in ['OraclesCCaddress', 'Oraclesmarker', 'myCCaddress', 'myaddress']:
for x in ['OraclesCCAddress', 'OraclesNormalAddress', 'myCCAddress(Oracles)','OraclesCCTokensAddress', 'myaddress']:
assert_equal(result[x][0], 'R')
# there are no oracles created yet
@@ -674,7 +662,6 @@ class CryptoConditionsTest (BitcoinTestFramework):
# assert_success(result)
# globals()["oracle_{}".format(f)] = self.send_and_mine(result['hex'], rpc)
def run_test (self):
print("Mining blocks...")
rpc = self.nodes[0]

View File

@@ -26,6 +26,16 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework):
rpc = self.nodes[0]
rpc1 = self.nodes[1]
# checking channelsaddress call
result = rpc.channelsaddress(self.pubkey)
assert_success(result)
# test that additional CCaddress key is returned
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
# getting empty channels list
result = rpc.channelslist()
assert_equal(len(result), 2)
@@ -71,7 +81,7 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework):
# now in channelinfo payment information should appear
result = rpc.channelsinfo(channel_txid)
assert_equal(result["Transactions"][1]["Payment"], payment_tx_id)
# number of payments should be equal 1 (one denomination used)
result = rpc.channelsinfo(channel_txid)["Transactions"][1]["Number of payments"]
assert_equal(result, 1)
@@ -143,7 +153,7 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework):
refund_txid = self.send_and_mine(result["hex"], rpc)
assert refund_txid, "got txid"
# TODO: check if it refunded to opener address
# checking if it refunded to opener address
raw_transaction = rpc.getrawtransaction(refund_txid, 1)
result = raw_transaction["vout"][2]["valueSat"]

View File

@@ -24,15 +24,21 @@ 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()
assert_equal(result['result'], 'success')
dice = rpc.diceaddress(self.pubkey)
assert_equal(dice['result'], 'success')
for x in ['myCCaddress', 'DiceCCaddress', 'Dicemarker', 'myaddress', 'CCaddress']:
assert_equal(dice[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[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 result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
# no dice created yet
result = rpc.dicelist()

View File

@@ -24,17 +24,23 @@ 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')
# 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 result.keys():
if x.find('ddress') > 0:
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']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
# no funds in the faucet yet
result = rpc.faucetget()

View File

@@ -20,8 +20,10 @@ class CryptoconditionsGatewaysTest(CryptoconditionsTestFramework):
result = rpc.gatewaysaddress()
assert_success(result)
for x in ['GatewaysCCaddress', 'myCCaddress', 'Gatewaysmarker', 'myaddress']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
assert_equal("03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40", result["GatewaysPubkey"])

View File

@@ -20,35 +20,36 @@ 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']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
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']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
# getting empty heir list
result = rpc.heirlist()
assert_equal(len(result), 1)
assert_success(result)
assert_equal(result, [])
# valid heirfund case with coins
result = rpc.heirfund("0", "1000", "UNITHEIR", self.pubkey1, "10")
result = rpc.heirfund("0", "1000", "UNITHEIR", self.pubkey1, "10", "TESTMEMO")
assert_success(result)
heir_fund_txid = self.send_and_mine(result["hextx"], rpc)
heir_fund_txid = self.send_and_mine(result["hex"], rpc)
assert heir_fund_txid, "got heir funding txid"
# heir fund txid should be in heirlist now
result = rpc.heirlist()
assert_equal(len(result), 2)
assert_success(result)
assert_equal(result["fundingtxid"], heir_fund_txid)
assert_equal(result, [heir_fund_txid])
# checking heirinfo
result = rpc.heirinfo(heir_fund_txid)
@@ -57,20 +58,20 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework):
assert_equal(result["name"], "UNITHEIR")
assert_equal(result["owner"], self.pubkey)
assert_equal(result["heir"], self.pubkey1)
assert_equal(result["funding total in coins"], "1000.00000000")
assert_equal(result["funding available in coins"], "1000.00000000")
assert_equal(result["inactivity time setting, sec"], "10")
assert_equal(result["spending allowed for the heir"], "false")
# TODO: heirlist keys are duplicating now
assert_equal(result["memo"], "TESTMEMO")
assert_equal(result["lifetime"], "1000.00000000")
assert_equal(result["type"], "coins")
assert_equal(result["InactivityTimeSetting"], "10")
assert_equal(result["InactivityTime"], "0")
assert_equal(result["IsHeirSpendingAllowed"], "false")
# waiting for 11 seconds to be sure that needed time passed for heir claiming
time.sleep(11)
rpc.generate(1)
self.sync_all()
result = rpc.heirinfo(heir_fund_txid)
assert_equal(result["funding available in coins"], "1000.00000000")
assert_equal(result["spending allowed for the heir"], "true")
assert_equal(result["lifetime"], "1000.00000000")
assert_equal(result["IsHeirSpendingAllowed"], "true")
# have to check that second node have coins to cover txfee at least
rpc.sendtoaddress(rpc1.getnewaddress(), 1)
@@ -84,7 +85,7 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework):
result = rpc1.heirclaim("0", "1000", heir_fund_txid)
assert_success(result)
heir_claim_txid = self.send_and_mine(result["hextx"], rpc1)
heir_claim_txid = self.send_and_mine(result["hex"], rpc1)
assert heir_claim_txid, "got claim txid"
# balance of second node after heirclaim should increase for 1000 coins - txfees
@@ -96,9 +97,63 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework):
# no more funds should be available for claiming
result = rpc.heirinfo(heir_fund_txid)
assert_equal(result["funding available in coins"], "0.00000000")
assert_equal(result["lifetime"], "1000.00000000")
assert_equal(result["available"], "0.00000000")
# TODO: valid heirfund case with tokens
# creating tokens which we put to heir contract
token_hex = rpc.tokencreate("TEST", "1", "TESTING")
token_txid = self.send_and_mine(token_hex["hex"], rpc)
assert token_txid, "got token txid"
# checking possesion over the tokens and balance
result = rpc.tokenbalance(token_txid, self.pubkey)["balance"]
assert_equal(result, 100000000)
# valid heir case with tokens
token_heir_hex = rpc.heirfund("0", "100000000", "UNITHEIR", self.pubkey1, "10", "TESTMEMO", token_txid)
token_heir_txid = self.send_and_mine(token_heir_hex["hex"], rpc)
assert token_heir_txid, "got txid of heirfund with tokens"
self.sync_all()
# checking heirinfo
result = rpc.heirinfo(token_heir_txid)
assert_success(result)
assert_equal(result["fundingtxid"], token_heir_txid)
assert_equal(result["name"], "UNITHEIR")
assert_equal(result["owner"], self.pubkey)
assert_equal(result["heir"], self.pubkey1)
assert_equal(result["lifetime"], "100000000")
assert_equal(result["type"], "tokens")
assert_equal(result["InactivityTimeSetting"], "10")
assert_equal(result["InactivityTime"], "0")
assert_equal(result["IsHeirSpendingAllowed"], "false")
# waiting for 11 seconds to be sure that needed time passed for heir claiming
time.sleep(11)
rpc.generate(1)
self.sync_all()
result = rpc.heirinfo(token_heir_txid)
assert_equal(result["lifetime"], "100000000")
assert_equal(result["IsHeirSpendingAllowed"], "true")
# let's claim whole heir sum from second node
result = rpc1.heirclaim("0", "100000000", token_heir_txid)
assert_success(result)
heir_tokens_claim_txid = self.send_and_mine(result["hex"], rpc1)
assert heir_tokens_claim_txid, "got claim txid"
# claiming node should have correct token balance now
result = rpc1.tokenbalance(token_txid, self.pubkey1)["balance"]
assert_equal(result, 100000000)
self.sync_all()
# no more funds should be available for claiming
result = rpc.heirinfo(token_heir_txid)
assert_equal(result["lifetime"], "100000000")
assert_equal(result["available"], "0")
def run_test(self):
print("Mining blocks...")

View File

@@ -22,13 +22,17 @@ class CryptoconditionsOraclesTest(CryptoconditionsTestFramework):
result = rpc.oraclesaddress()
assert_success(result)
for x in ['OraclesCCaddress', 'Oraclesmarker', 'myCCaddress', 'myaddress']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
result = rpc.oraclesaddress(self.pubkey)
assert_success(result)
for x in ['OraclesCCaddress', 'Oraclesmarker', 'myCCaddress', 'myaddress']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
# there are no oracles created yet
result = rpc.oracleslist()

View File

@@ -15,14 +15,18 @@ 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']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
result = rpc.rewardsaddress(self.pubkey)
for x in ['RewardsCCaddress', 'myCCaddress', 'Rewardsmarker', 'myaddress', 'CCaddress']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
# no rewards yet
result = rpc.rewardslist()

View File

@@ -21,23 +21,27 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework):
result = rpc.tokenaddress()
assert_success(result)
for x in ['TokensCCaddress', 'myCCaddress', 'Tokensmarker', 'myaddress']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
result = rpc.tokenaddress(self.pubkey)
assert_success(result)
for x in ['TokensCCaddress', 'myCCaddress', 'Tokensmarker', 'myaddress', 'CCaddress']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
result = rpc.assetsaddress()
assert_success(result)
for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
result = rpc.assetsaddress(self.pubkey)
assert_success(result)
for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress', 'CCaddress']:
assert_equal(result[x][0], 'R')
for x in result.keys():
if x.find('ddress') > 0:
assert_equal(result[x][0], 'R')
# there are no tokens created yet
result = rpc.tokenlist()
@@ -61,7 +65,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 +121,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 +140,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 +161,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 +188,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 +207,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 +224,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!)

151
qa/rpc-tests/dpowconfs.py Executable file
View File

@@ -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()

View File

@@ -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)

View File

@@ -36,7 +36,8 @@ LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
endif
if TARGET_DARWIN
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
else
endif
if TARGET_LINUX
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
endif
@@ -203,6 +204,7 @@ BITCOIN_CORE_H = \
mruset.h \
net.h \
netbase.h \
notaries_staked.h \
noui.h \
paymentdisclosure.h \
paymentdisclosuredb.h \
@@ -286,6 +288,7 @@ libbitcoin_server_a_SOURCES = \
bloom.cpp \
cc/eval.cpp \
cc/import.cpp \
cc/importgateway.cpp \
cc/CCassetsCore.cpp \
cc/CCcustom.cpp \
cc/CCtx.cpp \
@@ -310,6 +313,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 \
@@ -324,6 +328,7 @@ libbitcoin_server_a_SOURCES = \
metrics.h \
miner.cpp \
net.cpp \
notaries_staked.cpp \
noui.cpp \
notarisationdb.cpp \
paymentdisclosure.cpp \
@@ -486,6 +491,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)
@@ -571,8 +578,17 @@ komodod_LDADD += \
$(LIBBITCOIN_CRYPTO) \
$(LIBVERUS_CRYPTO) \
$(LIBVERUS_PORTABLE_CRYPTO) \
$(LIBZCASH_LIBS) \
libcc.so
$(LIBZCASH_LIBS)
if TARGET_DARWIN
komodod_LDADD += libcc.dylib $(LIBSECP256K1)
endif
if TARGET_WINDOWS
komodod_LDADD += libcc.dll $(LIBSECP256K1)
endif
if TARGET_LINUX
komodod_LDADD += libcc.so $(LIBSECP256K1)
endif
if ENABLE_PROTON
komodod_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS)

3
src/ac/ilien Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
./komodo-cli -ac_name=ILN $1 $2 $3 $4 $5 $6

2
src/ac/iln Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=ILN $1 $2 $3 $4 $5 $6

2
src/ac/morty Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=MORTY $1 $2 $3 $4 $5 $6

2
src/ac/rick Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=RICK $1 $2 $3 $4 $5 $6

2
src/ac/vote2019 Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=VOTE2019 $1 $2 $3 $4 $5 $6

View File

@@ -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",
@@ -240,5 +237,31 @@
"217.182.129.38",
"37.187.225.231"
]
}
},
{
"ac_name": "ILN",
"ac_supply": "10000000000",
"ac_cc": "2",
"addnode": ["51.75.122.83"]
},
{
"ac_name": "RICK",
"ac_supply": "90000000000",
"ac_reward": "100000000",
"ac_cc": "3",
"addnode": ["138.201.136.145"]
},
{
"ac_name": "MORTY",
"ac_supply": "90000000000",
"ac_reward": "100000000",
"ac_cc": "3",
"addnode": ["138.201.136.145"]
},
{
"ac_name": "VOTE2019",
"ac_supply": "123651638",
"ac_public": "1",
"addnode": ["95.213.238.98"]
}
]

View File

@@ -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 &
@@ -47,4 +46,7 @@ echo $pubkey
./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 &
./komodod -pubkey=$pubkey -ac_name=RICK -ac_supply=90000000000 -ac_reward=100000000 -ac_cc=3 -addnode=138.201.136.145 &
./komodod -pubkey=$pubkey -ac_name=MORTY -ac_supply=90000000000 -ac_reward=100000000 -ac_cc=3 -addnode=138.201.136.145 &
./komodod -pubkey=$pubkey -ac_name=VOTE2019 -ac_supply=123651638 -ac_public=1 -addnode=95.213.238.98 &

View File

@@ -296,13 +296,13 @@ CTxDestination CBitcoinAddress::Get() const
return CNoDestination();
}
bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const
bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type, bool ccflag) const
{
if (!IsValid()) {
return false;
} else if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) {
memcpy(&hashBytes, &vchData[0], 20);
type = 1;
ccflag ? type = 3 : type = 1;
return true;
} else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) {
memcpy(&hashBytes, &vchData[0], 20);
@@ -336,6 +336,84 @@ bool CBitcoinAddress::IsScript() const
return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
}
bool CCustomBitcoinAddress::Set(const CKeyID& id)
{
SetData(base58Prefixes[0], &id, 20);
return true;
}
bool CCustomBitcoinAddress::Set(const CPubKey& key)
{
CKeyID id = key.GetID();
SetData(base58Prefixes[0], &id, 20);
return true;
}
bool CCustomBitcoinAddress::Set(const CScriptID& id)
{
SetData(base58Prefixes[1], &id, 20);
return true;
}
bool CCustomBitcoinAddress::Set(const CTxDestination& dest)
{
return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
}
bool CCustomBitcoinAddress::IsValid() const
{
bool fCorrectSize = vchData.size() == 20;
bool fKnownVersion = vchVersion == base58Prefixes[0] ||
vchVersion == base58Prefixes[1];
return fCorrectSize && fKnownVersion;
}
bool CCustomBitcoinAddress::GetKeyID(CKeyID& keyID) const
{
if (!IsValid() || vchVersion != base58Prefixes[0])
return false;
uint160 id;
memcpy(&id, &vchData[0], 20);
keyID = CKeyID(id);
return true;
}
CTxDestination CCustomBitcoinAddress::Get() const
{
if (!IsValid())
return CNoDestination();
uint160 id;
memcpy(&id, &vchData[0], 20);
if (vchVersion == base58Prefixes[0])
return CKeyID(id);
else if (vchVersion == base58Prefixes[1])
return CScriptID(id);
else
return CNoDestination();
}
bool CCustomBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type, bool ccflag) const
{
if (!IsValid()) {
return false;
} else if (vchVersion == base58Prefixes[0]) {
memcpy(&hashBytes, &vchData[0], 20);
ccflag ? type = 3 : type = 1;
return true;
} else if (vchVersion == base58Prefixes[1]) {
memcpy(&hashBytes, &vchData[0], 20);
type = 2;
return true;
}
return false;
}
bool CCustomBitcoinAddress::IsScript() const
{
return IsValid() && vchVersion == base58Prefixes[1];
}
void CBitcoinSecret::SetKey(const CKey& vchSecret)
{
assert(vchSecret.IsValid());

View File

@@ -130,9 +130,9 @@ public:
*/
class CBitcoinAddress : public CBase58Data {
public:
bool Set(const CKeyID &id);
bool Set(const CPubKey &key);
bool Set(const CScriptID &id);
virtual bool Set(const CKeyID &id);
virtual bool Set(const CPubKey &key);
virtual bool Set(const CScriptID &id);
bool Set(const CTxDestination &dest);
bool IsValid() const;
bool IsValid(const CChainParams &params) const;
@@ -147,7 +147,32 @@ public:
CTxDestination Get() const;
bool GetKeyID(CKeyID &keyID) const;
bool GetKeyID_NoCheck(CKeyID& keyID) const;
bool GetIndexKey(uint160& hashBytes, int& type) const;
bool GetIndexKey(uint160& hashBytes, int& type, bool ccflag) const;
bool IsScript() const;
};
class CCustomBitcoinAddress : public CBitcoinAddress {
std::vector<unsigned char> base58Prefixes[2];
public:
bool Set(const CKeyID &id);
bool Set(const CPubKey &key);
bool Set(const CScriptID &id);
bool Set(const CTxDestination &dest);
bool IsValid() const;
CCustomBitcoinAddress() {}
CCustomBitcoinAddress(const CTxDestination &dest,uint8_t taddr,uint8_t pubkey_prefix,uint8_t script_prefix)
{
if (taddr!=0) base58Prefixes[0].push_back(taddr);
base58Prefixes[0].push_back(pubkey_prefix);
base58Prefixes[1].push_back(script_prefix);
Set(dest);
}
CTxDestination Get() const;
bool GetKeyID(CKeyID &keyID) const;
bool GetKeyID_NoCheck(CKeyID& keyID) const;
bool GetIndexKey(uint160& hashBytes, int& type, bool ccflag) const;
bool IsScript() const;
};

View File

@@ -59,27 +59,46 @@ static bool fDaemon;
#include "komodo_defs.h"
#define KOMODO_ASSETCHAIN_MAXLEN 65
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
extern int32_t ASSETCHAINS_BLOCKTIME;
extern uint64_t ASSETCHAINS_CBOPRET;
void komodo_passport_iteration();
uint64_t komodo_interestsum();
int32_t komodo_longestchain();
void komodo_cbopretupdate(int32_t forceflag);
void WaitForShutdown(boost::thread_group* threadGroup)
{
bool fShutdown = ShutdownRequested();
int32_t i; bool fShutdown = ShutdownRequested();
// Tell the main threads to shutdown.
if ( ASSETCHAINS_CBOPRET != 0 )
komodo_pricesinit();
while (!fShutdown)
{
//fprintf(stderr,"call passport iteration\n");
if ( ASSETCHAINS_SYMBOL[0] == 0 )
{
komodo_passport_iteration();
MilliSleep(10000);
for (i=0; i<10; i++)
{
fShutdown = ShutdownRequested();
if ( fShutdown != 0 )
break;
MilliSleep(1000);
}
}
else
{
//komodo_interestsum();
//komodo_longestchain();
MilliSleep(20000);
if ( ASSETCHAINS_CBOPRET != 0 )
komodo_cbopretupdate(0);
for (i=0; i<=ASSETCHAINS_BLOCKTIME/5; i++)
{
fShutdown = ShutdownRequested();
if ( fShutdown != 0 )
break;
MilliSleep(1000);
}
}
fShutdown = ShutdownRequested();
}

View File

@@ -18,23 +18,23 @@
#define CC_GATEWAYS_H
#include "CCinclude.h"
#include "../merkleblock.h"
bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys);
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4);
std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount);
std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount);
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount);
std::string GatewaysPartialSign(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex);
std::string GatewaysCompleteSigning(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex);
std::string GatewaysMarkDone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin);
UniValue GatewaysPendingDeposits(uint256 bindtxid,std::string refcoin);
UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin);
UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin);
UniValue GatewaysMultisig(char *txidaddr);
// CCcustom
UniValue GatewaysInfo(uint256 bindtxid);
UniValue GatewaysExternalAddress(uint256 bindtxid,CPubKey pubkey);
UniValue GatewaysDumpPrivKey(uint256 bindtxid,CKey privkey);
UniValue GatewaysList();
#endif

View File

@@ -27,15 +27,11 @@ bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,
class CoinHelper;
class TokenHelper;
UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirFundCoinCaller(int64_t txfee, int64_t coins, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo);
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid);
UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
UniValue HeirInfo(uint256 fundingtxid);
UniValue HeirList();
//std::string Heir_MakeBadTx(uint256 fundingtxid, uint8_t funcId, int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTime, uint32_t errMask);
//bool HeirExactTokenAmounts(bool compareTotals, struct CCcontract_info *cpHeir, Eval* eval, uint256 assetid, const CTransaction &tx);
#endif

38
src/cc/CCImportGateway.h Normal file
View File

@@ -0,0 +1,38 @@
/******************************************************************************
* Copyright © 2014-2018 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. *
* *
******************************************************************************/
#ifndef CC_IMPORTGATEWAY_H
#define CC_IMPORTGATEWAY_H
#include "CCinclude.h"
// CCcustom
bool ImportGatewayValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn);
bool ImportGatewayExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid);
std::string ImportGatewayBind(uint64_t txfee,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4);
std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t burnvout,std::string rawburntx,std::vector<uint8_t>proof,CPubKey destpub);
std::string ImportGatewayWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount);
std::string ImportGatewayPartialSign(uint64_t txfee,uint256 lasttxid,std::string refcoin, std::string hex);
std::string ImportGatewayCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string refcoin,std::string hex);
std::string ImportGatewayMarkDone(uint64_t txfee,uint256 completetxid,std::string refcoin);
UniValue ImportGatewayPendingDeposits(uint256 bindtxid,std::string refcoin);
UniValue ImportGatewayPendingWithdraws(uint256 bindtxid,std::string refcoin);
UniValue ImportGatewayProcessedWithdraws(uint256 bindtxid,std::string refcoin);
UniValue ImportGatewayExternalAddress(uint256 bindtxid,CPubKey pubkey);
UniValue ImportGatewayDumpPrivKey(uint256 bindtxid,CKey key);
UniValue ImportGatewayList();
UniValue ImportGatewayInfo(uint256 bindtxid);
#endif

View File

@@ -14,8 +14,8 @@
******************************************************************************/
#ifndef CC_TRIGGERS_H
#define CC_TRIGGERS_H
#ifndef CC_MARMARA_H
#define CC_MARMARA_H
#include "CCinclude.h"
#include "../komodo_cJSON.h"
@@ -24,6 +24,7 @@
#define MARMARA_MINLOCK (1440 * 3 * 30)
#define MARMARA_MAXLOCK (1440 * 24 * 30)
#define MARMARA_VINS 16
#define EVAL_MARMARA 0xef
extern uint8_t ASSETCHAINS_MARMARA;
uint64_t komodo_block_prg(uint32_t nHeight);

View File

@@ -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

View File

@@ -18,17 +18,34 @@
#define CC_PRICES_H
#include "CCinclude.h"
int32_t prices_extract(int64_t *pricedata,int32_t firstheight,int32_t numblocks,int32_t ind);
int32_t komodo_priceget(int64_t *buf64,int32_t ind,int32_t height,int32_t numblocks);
#define PRICES_DAYWINDOW ((3600*24/ASSETCHAINS_BLOCKTIME) + 1)
#define PRICES_TXFEE 10000
#define PRICES_MAXLEVERAGE 777
#define PRICES_SMOOTHWIDTH 1
#define KOMODO_MAXPRICES 2048 // must be power of 2 and less than 8192
#define KOMODO_PRICEMASK (~(KOMODO_MAXPRICES - 1))
#define PRICES_WEIGHT (KOMODO_MAXPRICES * 1)
#define PRICES_MULT (KOMODO_MAXPRICES * 2)
#define PRICES_DIV (KOMODO_MAXPRICES * 3)
#define PRICES_INV (KOMODO_MAXPRICES * 4)
#define PRICES_MDD (KOMODO_MAXPRICES * 5)
#define PRICES_MMD (KOMODO_MAXPRICES * 6)
#define PRICES_MMM (KOMODO_MAXPRICES * 7)
#define PRICES_DDD (KOMODO_MAXPRICES * 8)
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue PricesBet(uint64_t txfee,int64_t amount,int16_t leverage,std::vector<std::string> synthetic);
UniValue PricesAddFunding(uint64_t txfee,uint256 bettxid,int64_t amount);
UniValue PricesSetcostbasis(uint64_t txfee,uint256 bettxid);
UniValue PricesRekt(uint64_t txfee,uint256 bettxid,int32_t rektheight);
UniValue PricesCashout(uint64_t txfee,uint256 bettxid);
UniValue PricesInfo(uint256 bettxid,int32_t refheight);
UniValue PricesList();
UniValue PricesInfo(uint256 fundingtxid);
UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid);
std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector<CPubKey> pubkeys);
std::string PricesAddFunding(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount);
std::string PricesBet(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount,int32_t leverage);
std::string PricesFinish(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,uint256 bettxid);
#endif

View File

@@ -29,11 +29,8 @@
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCassetsCore
//CTxOut MakeAssetsVout(CAmount nValue,CPubKey pk);
//CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,std::string name,std::string description);
//CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
//bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
vscript_t EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &assetsEvalCode, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx);
int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid);
bool ValidateBidRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice);
@@ -50,7 +47,7 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t
//int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); // --> GetTokenBalance()
int64_t AddAssetInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 assetid, int64_t total, int32_t maxinputs);
UniValue AssetOrders(uint256 tokenid);
UniValue AssetOrders(uint256 tokenid, CPubKey pubkey, uint8_t additionalEvalCode);
//UniValue AssetInfo(uint256 tokenid);
//UniValue AssetList();
//std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description);

View File

@@ -43,17 +43,17 @@ bool ValidateBidRemainder(int64_t remaining_units,int64_t remaining_nValue,int64
int64_t unitprice,recvunitprice,newunitprice=0;
if ( orig_nValue == 0 || received_nValue == 0 || paidunits == 0 || totalunits == 0 )
{
fprintf(stderr,"ValidateAssetRemainder: orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
fprintf(stderr,"ValidateAssetRemainder() orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
return(false);
}
else if ( totalunits != (remaining_units + paidunits) )
{
fprintf(stderr,"ValidateAssetRemainder: totalunits %llu != %llu (remaining_units %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_units + paidunits),(long long)remaining_units,(long long)paidunits);
fprintf(stderr,"ValidateAssetRemainder() totalunits %llu != %llu (remaining_units %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_units + paidunits),(long long)remaining_units,(long long)paidunits);
return(false);
}
else if ( orig_nValue != (remaining_nValue + received_nValue) )
{
fprintf(stderr,"ValidateAssetRemainder: orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
fprintf(stderr,"ValidateAssetRemainder() orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
return(false);
}
else
@@ -68,10 +68,10 @@ bool ValidateBidRemainder(int64_t remaining_units,int64_t remaining_nValue,int64
newunitprice = (remaining_nValue / remaining_units);
if ( recvunitprice < unitprice )
{
fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
fprintf(stderr,"ValidateAssetRemainder() error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
return(false);
}
fprintf(stderr,"orig %llu total %llu, recv %llu paid %llu,recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(long long)orig_nValue,(long long)totalunits,(long long)received_nValue,(long long)paidunits,(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
fprintf(stderr,"ValidateAssetRemainder() orig %llu total %llu, recv %llu paid %llu,recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(long long)orig_nValue,(long long)totalunits,(long long)received_nValue,(long long)paidunits,(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
}
return(true);
}
@@ -89,7 +89,7 @@ bool SetBidFillamounts(int64_t &received_nValue,int64_t &remaining_units,int64_t
paidunits = totalunits;
received_nValue = orig_nValue;
remaining_units = 0;
fprintf(stderr,"totally filled!\n");
fprintf(stderr,"SetBidFillamounts() bid order totally filled!\n");
return(true);
}
remaining_units = (totalunits - paidunits);
@@ -100,7 +100,7 @@ bool SetBidFillamounts(int64_t &received_nValue,int64_t &remaining_units,int64_t
if ( unitprice > 0 && received_nValue > 0 && received_nValue <= orig_nValue )
{
remaining_nValue = (orig_nValue - received_nValue);
printf("total.%llu - paid.%llu, remaining %llu <- %llu (%llu - %llu)\n",(long long)totalunits,(long long)paidunits,(long long)remaining_nValue,(long long)(orig_nValue - received_nValue),(long long)orig_nValue,(long long)received_nValue);
printf("SetBidFillamounts() total.%llu - paid.%llu, remaining %llu <- %llu (%llu - %llu)\n",(long long)totalunits,(long long)paidunits,(long long)remaining_nValue,(long long)(orig_nValue - received_nValue),(long long)orig_nValue,(long long)received_nValue);
return(ValidateBidRemainder(remaining_units,remaining_nValue,orig_nValue,received_nValue,paidunits,totalunits));
} else return(false);
}
@@ -118,14 +118,14 @@ bool SetAskFillamounts(int64_t &received_assetoshis,int64_t &remaining_nValue,in
paid_nValue = total_nValue;
received_assetoshis = orig_assetoshis;
remaining_nValue = 0;
fprintf(stderr,"totally filled!\n");
fprintf(stderr,"SetAskFillamounts() ask order totally filled!\n");
return(true);
}
remaining_nValue = (total_nValue - paid_nValue);
dunitprice = ((double)total_nValue / orig_assetoshis);
received_assetoshis = (paid_nValue / dunitprice);
fprintf(stderr,"remaining_nValue %.8f (%.8f - %.8f)\n",(double)remaining_nValue/COIN,(double)total_nValue/COIN,(double)paid_nValue/COIN);
fprintf(stderr,"unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
fprintf(stderr,"SetAskFillamounts() remaining_nValue %.8f (%.8f - %.8f)\n",(double)remaining_nValue/COIN,(double)total_nValue/COIN,(double)paid_nValue/COIN);
fprintf(stderr,"SetAskFillamounts() unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
{
remaining_assetoshis = (orig_assetoshis - received_assetoshis);
@@ -138,17 +138,17 @@ bool ValidateAskRemainder(int64_t remaining_nValue,int64_t remaining_assetoshis,
int64_t unitprice,recvunitprice,newunitprice=0;
if ( orig_assetoshis == 0 || received_assetoshis == 0 || paid_nValue == 0 || total_nValue == 0 )
{
fprintf(stderr,"ValidateAssetRemainder: orig_assetoshis == %llu || received_assetoshis == %llu || paid_nValue == %llu || total_nValue == %llu\n",(long long)orig_assetoshis,(long long)received_assetoshis,(long long)paid_nValue,(long long)total_nValue);
fprintf(stderr,"ValidateAssetRemainder() orig_assetoshis == %llu || received_assetoshis == %llu || paid_nValue == %llu || total_nValue == %llu\n",(long long)orig_assetoshis,(long long)received_assetoshis,(long long)paid_nValue,(long long)total_nValue);
return(false);
}
else if ( total_nValue != (remaining_nValue + paid_nValue) )
{
fprintf(stderr,"ValidateAssetRemainder: total_nValue %llu != %llu (remaining_nValue %llu + %llu paid_nValue)\n",(long long)total_nValue,(long long)(remaining_nValue + paid_nValue),(long long)remaining_nValue,(long long)paid_nValue);
fprintf(stderr,"ValidateAssetRemainder() total_nValue %llu != %llu (remaining_nValue %llu + %llu paid_nValue)\n",(long long)total_nValue,(long long)(remaining_nValue + paid_nValue),(long long)remaining_nValue,(long long)paid_nValue);
return(false);
}
else if ( orig_assetoshis != (remaining_assetoshis + received_assetoshis) )
{
fprintf(stderr,"ValidateAssetRemainder: orig_assetoshis %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_assetoshis,(long long)(remaining_assetoshis - received_assetoshis),(long long)remaining_assetoshis,(long long)received_assetoshis);
fprintf(stderr,"ValidateAssetRemainder() orig_assetoshis %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_assetoshis,(long long)(remaining_assetoshis - received_assetoshis),(long long)remaining_assetoshis,(long long)received_assetoshis);
return(false);
}
else
@@ -159,10 +159,10 @@ bool ValidateAskRemainder(int64_t remaining_nValue,int64_t remaining_assetoshis,
newunitprice = (remaining_nValue / remaining_assetoshis);
if ( recvunitprice < unitprice )
{
fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
fprintf(stderr,"ValidateAskRemainder() error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
return(false);
}
fprintf(stderr,"got recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
fprintf(stderr,"ValidateAskRemainder() got recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
}
return(true);
}
@@ -172,7 +172,7 @@ bool SetSwapFillamounts(int64_t &received_assetoshis,int64_t &remaining_assetosh
int64_t remaining_assetoshis; double dunitprice;
if ( total_assetoshis2 == 0 )
{
fprintf(stderr,"total_assetoshis2.0 origsatoshis.%llu paid_assetoshis2.%llu\n",(long long)orig_assetoshis,(long long)paid_assetoshis2);
fprintf(stderr,"SetSwapFillamounts() total_assetoshis2.0 origsatoshis.%llu paid_assetoshis2.%llu\n",(long long)orig_assetoshis,(long long)paid_assetoshis2);
received_assetoshis = remaining_assetoshis2 = paid_assetoshis2 = 0;
return(false);
}
@@ -181,14 +181,14 @@ bool SetSwapFillamounts(int64_t &received_assetoshis,int64_t &remaining_assetosh
paid_assetoshis2 = total_assetoshis2;
received_assetoshis = orig_assetoshis;
remaining_assetoshis2 = 0;
fprintf(stderr,"totally filled!\n");
fprintf(stderr,"SetSwapFillamounts() swap order totally filled!\n");
return(true);
}
remaining_assetoshis2 = (total_assetoshis2 - paid_assetoshis2);
dunitprice = ((double)total_assetoshis2 / orig_assetoshis);
received_assetoshis = (paid_assetoshis2 / dunitprice);
fprintf(stderr,"remaining_assetoshis2 %llu (%llu - %llu)\n",(long long)remaining_assetoshis2/COIN,(long long)total_assetoshis2/COIN,(long long)paid_assetoshis2/COIN);
fprintf(stderr,"unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
fprintf(stderr,"SetSwapFillamounts() remaining_assetoshis2 %llu (%llu - %llu)\n",(long long)remaining_assetoshis2/COIN,(long long)total_assetoshis2/COIN,(long long)paid_assetoshis2/COIN);
fprintf(stderr,"SetSwapFillamounts() unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
{
remaining_assetoshis = (orig_assetoshis - received_assetoshis);
@@ -201,17 +201,17 @@ bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int6
int64_t unitprice,recvunitprice,newunitprice=0;
if ( orig_nValue == 0 || received_nValue == 0 || paidunits == 0 || totalunits == 0 )
{
fprintf(stderr,"ValidateAssetRemainder: orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
fprintf(stderr,"ValidateAssetRemainder() orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
return(false);
}
else if ( totalunits != (remaining_price + paidunits) )
{
fprintf(stderr,"ValidateAssetRemainder: totalunits %llu != %llu (remaining_price %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_price + paidunits),(long long)remaining_price,(long long)paidunits);
fprintf(stderr,"ValidateAssetRemainder() totalunits %llu != %llu (remaining_price %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_price + paidunits),(long long)remaining_price,(long long)paidunits);
return(false);
}
else if ( orig_nValue != (remaining_nValue + received_nValue) )
{
fprintf(stderr,"ValidateAssetRemainder: orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
fprintf(stderr,"ValidateAssetRemainder() orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
return(false);
}
else
@@ -222,10 +222,10 @@ bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int6
newunitprice = (remaining_nValue * COIN) / remaining_price;
if ( recvunitprice < unitprice )
{
fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
fprintf(stderr,"ValidateAssetRemainder() error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
return(false);
}
fprintf(stderr,"recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
fprintf(stderr,"ValidateAssetRemainder() recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
}
return(true);
}
@@ -239,30 +239,30 @@ CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,st
}
*/
CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey)
vscript_t EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> 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)
@@ -279,77 +279,77 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &o
return(0);
} */
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey)
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &assetsEvalCode, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey)
{
std::vector<uint8_t> vopretExtra, vopretStripped;
uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyAssetFuncId;
vscript_t vopretAssets; //, vopretAssetsStripped;
uint8_t *script, funcId = 0, assetsFuncId = 0, dummyEvalCode, dummyAssetFuncId;
uint256 dummyTokenid;
std::vector<CPubKey> voutPubkeysDummy;
std::vector<std::pair<uint8_t, vscript_t>> oprets;
tokenid = zeroid;
assetid2 = zeroid;
price = 0;
assetsEvalCode = 0;
assetsFuncId = 0;
// First - decode token opret:
funcId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra);
funcId = DecodeTokenOpRet(scriptPubKey, dummyEvalCode, tokenid, voutPubkeysDummy, oprets);
GetOpretBlob(oprets, OPRETID_ASSETSDATA, vopretAssets);
/*GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if (script == 0) {
std::cerr << "DecodeAssetOpRet() script is empty" << std::endl;
return (uint8_t)0;
}*/
//bool isEof = true; // 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 result = E_UNMARSHAL(vopret, ss >> evalCodeInOpret; ss >> funcId; ss >> tokenid; ss >> assetFuncId; isEof = ss.eof());
LOGSTREAM((char *)"ccassets", CCLOG_DEBUG2, stream << "DecodeAssetTokenOpRet() from DecodeTokenOpRet returned funcId=" << (int)funcId << std::endl);
if (funcId == 0 || vopretExtra.size() < 2) {
std::cerr << "DecodeAssetOpRet() incorrect opret or no asset's payload" << " funcId=" << (int)funcId << " vopretExtra.size()=" << vopretExtra.size() << std::endl;
if (funcId == 0 || vopretAssets.size() < 2) {
LOGSTREAM((char *)"ccassets", CCLOG_INFO, stream << "DecodeAssetTokenOpRet() incorrect opret or no asset's payload" << " funcId=" << (int)funcId << " vopretAssets.size()=" << vopretAssets.size() << std::endl);
return (uint8_t)0;
}
if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size
std::cerr << "DecodeAssetTokenOpRet() could not unmarshal vopretStripped" << std::endl;
return (uint8_t)0;
}
//if (!E_UNMARSHAL(vopretAssets, { ss >> vopretAssetsStripped; })) { //strip string size
// std::cerr << "DecodeAssetTokenOpRet() could not unmarshal vopretAssetsStripped" << std::endl;
// return (uint8_t)0;
//}
////tokenid = revuint256(tokenid); already done in DecodeToken!
evalCodeInOpret = vopretStripped.begin()[0];
assetFuncId = vopretStripped.begin()[1];
// additional check to prevent crash
if (vopretAssets.size() >= 2) {
//std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl;
assetsEvalCode = vopretAssets.begin()[0];
assetsFuncId = vopretAssets.begin()[1];
if(evalCodeInOpret == EVAL_ASSETS)
{
//fprintf(stderr,"decode.[%c] assetFuncId.[%c]\n", funcId, assetFuncId);
switch( assetFuncId )
LOGSTREAM((char *)"ccassets", CCLOG_DEBUG2, stream << "DecodeAssetTokenOpRet() assetsEvalCode=" << (int)assetsEvalCode << " funcId=" << (char)(funcId ? funcId : ' ') << " assetsFuncId=" << (char)(assetsFuncId ? assetsFuncId : ' ') << std::endl);
if (assetsEvalCode == EVAL_ASSETS)
{
case 'x': case 'o':
if (vopretStripped.size() == 2) // no data after 'evalcode assetFuncId' allowed
//fprintf(stderr,"DecodeAssetTokenOpRet() decode.[%c] assetFuncId.[%c]\n", funcId, assetFuncId);
switch (assetsFuncId)
{
case 'x': case 'o':
if (vopretAssets.size() == 2) // no data after 'evalcode assetFuncId' allowed
{
return(assetFuncId);
return(assetsFuncId);
}
break;
case 's': case 'b': case 'S': case 'B':
if (E_UNMARSHAL(vopretStripped, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0)
if (E_UNMARSHAL(vopretAssets, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0)
{
//fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price);
return(assetFuncId);
//fprintf(stderr,"DecodeAssetTokenOpRet() got price %llu\n",(long long)price);
return(assetsFuncId);
}
break;
case 'E': case 'e':
if ( E_UNMARSHAL(vopretStripped, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 )
if (E_UNMARSHAL(vopretAssets, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0)
{
//fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price);
//fprintf(stderr,"DecodeAssetTokenOpRet() got price %llu\n",(long long)price);
assetid2 = revuint256(assetid2);
return(assetFuncId);
return(assetsFuncId);
}
break;
default:
fprintf(stderr,"DecodeAssetTokenOpRet: illegal assetFuncId.%02x\n", assetFuncId);
//funcId = 0;
break;
}
}
}
LOGSTREAM((char *)"ccassets", CCLOG_INFO, stream << "DecodeAssetTokenOpRet() no asset's payload or incorrect assets funcId or evalcode" << " funcId=" << (int)funcId << " vopretAssets.size()=" << vopretAssets.size() << " assetsEvalCode=" << assetsEvalCode << " assetsFuncId=" << assetsFuncId << std::endl);
return (uint8_t)0;
}
@@ -358,49 +358,53 @@ bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CT
{
uint256 assetid,assetid2;
uint8_t evalCode;
if ( tx.vout.size() > 0 && DecodeAssetTokenOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey) != 0 )
return(true);
else
return(false);
}
// Calculate sell/buy owner's source token/asset address from ask/bid tx
bool GetAssetorigaddrs(struct CCcontract_info *cp, char *userCCaddr, char *destaddr, const CTransaction& tx)
// Calculate seller/buyer's dest cc address from ask/bid tx funcid
bool GetAssetorigaddrs(struct CCcontract_info *cp, char *origCCaddr, char *origNormalAddr, const CTransaction& vintx)
{
uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid;
uint256 assetid, assetid2;
int64_t price,nValue=0;
int32_t n;
uint8_t vintxFuncId;
std::vector<uint8_t> origpubkey;
CScript script;
uint8_t evalCode;
n = tx.vout.size();
if( n == 0 || (funcid = DecodeAssetTokenOpRet(tx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 )
n = vintx.vout.size();
if( n == 0 || (vintxFuncId = DecodeAssetTokenOpRet(vintx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 )
return(false);
bool bGetCCaddr = false;
if (funcid == 's' || funcid == 'S') {
struct CCcontract_info *cpTokens, tokensC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
bGetCCaddr = GetCCaddress(cpTokens, userCCaddr, pubkey2pk(origpubkey));
//bGetCCaddr = GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey));
struct CCcontract_info *cpTokens, tokensC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
if (vintxFuncId == 's' || vintxFuncId == 'S') {
// bGetCCaddr = GetCCaddress(cpTokens, origCCaddr, pubkey2pk(origpubkey));
cpTokens->additionalTokensEvalcode2 = cp->additionalTokensEvalcode2; // add non-fungible if present
bGetCCaddr = GetTokensCCaddress(cpTokens, origCCaddr, pubkey2pk(origpubkey)); // tokens to single-eval token or token+nonfungible
}
else if (funcid == 'b' || funcid == 'B') {
struct CCcontract_info *cpTokens, tokensC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
bGetCCaddr = GetCCaddress(cpTokens, userCCaddr, pubkey2pk(origpubkey));
else if (vintxFuncId == 'b' || vintxFuncId == 'B') {
cpTokens->additionalTokensEvalcode2 = cp->additionalTokensEvalcode2; // add non-fungible if present
bGetCCaddr = GetTokensCCaddress(cpTokens, origCCaddr, pubkey2pk(origpubkey)); // tokens to single-eval token or token+nonfungible
}
else {
std::cerr << "GetAssetorigaddrs incorrect funcid=" << (char)(funcid?funcid:' ') << std::endl;
std::cerr << "GetAssetorigaddrs incorrect vintx funcid=" << (char)(vintxFuncId?vintxFuncId:' ') << std::endl;
return false;
}
if( bGetCCaddr && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG))
if( bGetCCaddr && Getscriptaddress(origNormalAddr, CScript() << origpubkey << OP_CHECKSIG))
return(true);
else
return(false);
}
int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx)
int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *origCCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx)
{
uint256 hashBlock;
uint256 assetid, assetid2;
@@ -410,7 +414,7 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch
char destaddr[64], unspendableAddr[64];
origaddr[0] = destaddr[0] = CCaddr[0] = 0;
origaddr[0] = destaddr[0] = origCCaddr[0] = 0;
uint8_t funcid = 0;
if (tx.vout.size() > 0) {
@@ -418,6 +422,7 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch
int64_t tmpprice;
std::vector<uint8_t> tmporigpubkey;
uint8_t evalCode;
funcid = DecodeAssetTokenOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey);
}
@@ -427,45 +432,47 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch
return eval->Invalid("vin1 needs to be buyvin.vout[0]");
else if( eval->GetTxUnconfirmed(tx.vin[vini].prevout.hash, vinTx,hashBlock) == 0 )
{
/* int32_t z;
for (z=31; z>=0; z--)
fprintf(stderr,"%02x",((uint8_t *)&tx.vin[vini].prevout.hash)[z]);
fprintf(stderr," vini.%d\n",vini); */
std::cerr << "AssetValidateCCvin cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl;
std::cerr << "AssetValidateCCvin() cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl;
return eval->Invalid("always should find CCvin, but didnt");
}
// if fillSell or cancelSell --> to spend tokens from dual-eval token-assets unspendable addr
// check source cc unspendable cc address:
// if fillSell or cancelSell --> should spend tokens from dual-eval token-assets unspendable addr
else if( (funcid == 'S' || funcid == 'x') &&
(Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ||
!GetTokensCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) ||
strcmp(destaddr, unspendableAddr) != 0))
{
fprintf(stderr,"AssetValidateCCvin cc addr %s is not dual token-evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
return eval->Invalid("invalid vin AssetsCCaddr");
fprintf(stderr,"AssetValidateCCvin() cc addr %s is not dual token-evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
return eval->Invalid("invalid vin assets CCaddr");
}
// if fillBuy or cancelBuy --> to spend coins from asset unspendable addr
// if fillBuy or cancelBuy --> should spend coins from asset unspendable addr
else if ((funcid == 'B' || funcid == 'o') &&
(Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ||
!GetCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) ||
strcmp(destaddr, unspendableAddr) != 0))
{
fprintf(stderr, "AssetValidateCCvin cc addr %s is not evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
return eval->Invalid("invalid vin AssetsCCaddr");
fprintf(stderr, "AssetValidateCCvin() cc addr %s is not evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
return eval->Invalid("invalid vin assets CCaddr");
}
// end of check source unspendable cc address
//else if ( vinTx.vout[0].nValue < 10000 )
// return eval->Invalid("invalid dust for buyvin");
else if( GetAssetorigaddrs(cp, CCaddr, origaddr, vinTx) == 0 )
// get user dest cc and normal addresses:
else if( GetAssetorigaddrs(cp, origCCaddr, origaddr, vinTx) == 0 )
return eval->Invalid("couldnt get origaddr for buyvin");
fprintf(stderr,"AssetValidateCCvin got %.8f to origaddr.(%s)\n",(double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr);
//fprintf(stderr,"AssetValidateCCvin() got %.8f to origaddr.(%s)\n", (double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr);
if ( vinTx.vout[0].nValue == 0 )
return eval->Invalid("null value CCvin");
return(vinTx.vout[0].nValue);
}
int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid)
{
CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid, evalCode;
CCaddr[0] = origaddr[0] = 0;
// validate locked coins on Assets vin[1]
@@ -473,7 +480,7 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr
return(0);
else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("invalid normal vout0 for buyvin");
else if ((funcid = DecodeAssetTokenOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' &&
else if ((funcid = DecodeAssetTokenOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' &&
vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) // marker is only in 'b'?
return eval->Invalid("invalid normal vout1 for buyvin");
else
@@ -493,7 +500,7 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr
int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid)
{
CTransaction vinTx; int64_t nValue,assetoshis;
//fprintf(stderr,"AssetValidateSellvin\n");
//fprintf(stderr,"AssetValidateSellvin()\n");
if ( (nValue = AssetValidateCCvin(cp, eval, CCaddr, origaddr, tx, 1, vinTx)) == 0 )
return(0);
if ( (assetoshis= IsAssetvout(cp, tmpprice, tmporigpubkey, vinTx, 0, assetid)) == 0 )
@@ -514,7 +521,7 @@ bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &pr
if ((funcid = DecodeAssetTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, assetidOpret, assetidOpret2, price, origpubkey)) == 0)
{
std::cerr << "ValidateAssetOpret() DecodeAssetTokenOpRet returned null for the opret for txid=" << tx.GetHash().GetHex() << std::endl;
std::cerr << "ValidateAssetOpret() DecodeAssetTokenOpRet returned funcId=0 for opret from txid=" << tx.GetHash().GetHex() << std::endl;
return(false);
}
/* it is now on token level:
@@ -556,22 +563,20 @@ bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &pr
}
// Checks if the vout is a really Asset CC vout
// compareTotals == true, the func also validates the passed transaction itself:
// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx
int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid)
{
//std::cerr << "IsAssetvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for assetid=" << refassetid.GetHex() << std::endl;
int32_t n = tx.vout.size();
// just check boundaries:
if (v >= n - 1) { // just moved this up (dimxy)
std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl;
return(0);
}
if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here
{
int32_t n = tx.vout.size();
// just check boundaries:
if (v >= n - 1) { // just moved this up (dimxy)
std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl;
return(0);
}
// moved opret checking to this new reusable func (dimxy):
const bool valOpret = ValidateAssetOpret(tx, v, refassetid, price, origpubkey);
//std::cerr << "IsAssetvout() ValidateAssetOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for assetid=" << refassetid.GetHex() << std::endl;
@@ -620,22 +625,19 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t
assetoshis = IsTokensvout(false, false, cpTokens, NULL, vinTx, tx.vin[i].prevout.n, assetid);
if (assetoshis != 0)
{
std::cerr << "AssetCalcAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl;
//std::cerr << "AssetCalcAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl;
inputs += assetoshis;
}
}
}
}
for (int32_t i = 0; i < numvouts; i++)
for (int32_t i = 0; i < numvouts-1; i++)
{
// Note: we pass in here 'false' because we don't need to call AssetExactAmounts() recursively from IsAssetvout
// indeed, in this case we'll be checking this tx again
assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, tx, i, assetid);
if (assetoshis != 0)
{
std::cerr << "AssetCalcAmounts() vout i=" << i << " assetoshis=" << assetoshis << std::endl;
//std::cerr << "AssetCalcAmounts() vout i=" << i << " assetoshis=" << assetoshis << std::endl;
outputs += assetoshis;
}
}
@@ -643,12 +645,6 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t
//std::cerr << "AssetCalcAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
/* we do not verify inputs == outputs here,
it's done in Tokens:
if (inputs != outputs) {
if (tx.GetHash() != assetid) {
std::cerr << "AssetCalcAmounts() unequal inputs=" << inputs << " vs outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
return (!eval) ? false : eval->Invalid("assets cc inputs != cc outputs");
}
} */
it's now done in Tokens */
return(true);
}

View File

@@ -14,174 +14,145 @@
******************************************************************************/
#include "CCassets.h"
//#include "CCtokens.h"
#include "CCtokens.h"
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs)
{
char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t j,vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs!=0?maxinputs:64); // TODO: is maxinputs really not over 64, what if i want to calc total balance?
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if (it->second.satoshis < threshold)
continue;
for (j=0; j<mtx.vin.size(); j++)
if (txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n)
break;
if( j != mtx.vin.size() )
continue;
if( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey);
if( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
continue;
fprintf(stderr,"AddAssetInputs() check destaddress=%s vout amount=%.8f\n",destaddr,(double)vintx.vout[vout].nValue/COIN);
if( (nValue = IsAssetvout(cp, price, origpubkey, vintx, vout, assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
nValue = it->second.satoshis;
totalinputs += nValue;
//std::cerr << "AddAssetInputs() adding input nValue=" << nValue << std::endl;
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
}
}
}
//std::cerr << "AddAssetInputs() found totalinputs=" << totalinputs << std::endl;
return(totalinputs);
}
UniValue AssetOrders(uint256 refassetid)
UniValue AssetOrders(uint256 refassetid, CPubKey pk, uint8_t additionalEvalCode)
{
static uint256 zero;
UniValue result(UniValue::VARR);
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputsTokens, unspentOutputsAssets;
struct CCcontract_info *cpTokens, tokensC;
struct CCcontract_info *cpAssets, assetsC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
struct CCcontract_info *cpAssets, assetsC;
struct CCcontract_info *cpTokens, tokensC;
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
auto addOrders = [&](struct CCcontract_info *cp, std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it)
{
uint256 txid, hashBlock, assetid, assetid2;
int64_t price;
std::vector<uint8_t> origpubkey;
CTransaction vintx;
CTransaction ordertx;
uint8_t funcid, evalCode;
char numstr[32], funcidstr[16], origaddr[64], assetidstr[65];
char numstr[32], funcidstr[16], origaddr[64], origtokenaddr[64], assetidstr[65];
txid = it->first.txhash;
//std::cerr << "addOrders() txid=" << txid.GetHex() << std::endl;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() checking txid=" << txid.GetHex() << std::endl);
if ( GetTransaction(txid, ordertx, hashBlock, false) != 0 )
{
// for logging: funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey);
//std::cerr << "addOrders() vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl;
if (vintx.vout.size() > 0 && (funcid = DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0)
if (ordertx.vout.size() > 0 && (funcid = DecodeAssetTokenOpRet(ordertx.vout[ordertx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0)
{
if (refassetid != zero && assetid != refassetid)
{
//int32_t z;
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&txid)[z]);
//fprintf(stderr," txid\n");
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&assetid)[z]);
//fprintf(stderr," assetid\n");
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&refassetid)[z]);
//fprintf(stderr," refassetid\n");
return;
}
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() checking ordertx.vout.size()=" << ordertx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl);
//std::cerr << "addOrders() it->first.index=" << it->first.index << " vintx.vout[it->first.index].nValue=" << vintx.vout[it->first.index].nValue << std::endl;
if (vintx.vout[it->first.index].nValue == 0)
return;
if (refassetid != zero && assetid == refassetid ||
pk != CPubKey() && pk == pubkey2pk(origpubkey) && (funcid == 'S' || funcid == 's'))
{
UniValue item(UniValue::VOBJ);
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() it->first.index=" << it->first.index << " ordertx.vout[it->first.index].nValue=" << ordertx.vout[it->first.index].nValue << std::endl);
if (ordertx.vout[it->first.index].nValue == 0) {
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() order with value=0 skipped" << std::endl);
return;
}
funcidstr[0] = funcid;
funcidstr[1] = 0;
item.push_back(Pair("funcid", funcidstr));
item.push_back(Pair("txid", uint256_str(assetidstr,txid)));
item.push_back(Pair("vout", (int64_t)it->first.index));
if ( funcid == 'b' || funcid == 'B' )
{
sprintf(numstr,"%.8f",(double)vintx.vout[it->first.index].nValue/COIN);
item.push_back(Pair("amount",numstr));
sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
item.push_back(Pair("bidamount",numstr));
}
else
{
sprintf(numstr,"%llu",(long long)vintx.vout[it->first.index].nValue);
item.push_back(Pair("amount",numstr));
sprintf(numstr,"%llu",(long long)vintx.vout[0].nValue);
item.push_back(Pair("askamount",numstr));
}
if ( origpubkey.size() == 33 )
{
GetCCaddress(cp, origaddr, pubkey2pk(origpubkey)); // TODO: what is this? is it asset or token??
item.push_back(Pair("origaddress", origaddr));
}
if ( assetid != zeroid )
item.push_back(Pair("tokenid",uint256_str(assetidstr,assetid)));
if ( assetid2 != zeroid )
item.push_back(Pair("otherid",uint256_str(assetidstr,assetid2)));
if ( price > 0 )
{
if ( funcid == 's' || funcid == 'S' || funcid == 'e' || funcid == 'e' )
UniValue item(UniValue::VOBJ);
funcidstr[0] = funcid;
funcidstr[1] = 0;
item.push_back(Pair("funcid", funcidstr));
item.push_back(Pair("txid", uint256_str(assetidstr, txid)));
item.push_back(Pair("vout", (int64_t)it->first.index));
if (funcid == 'b' || funcid == 'B')
{
sprintf(numstr,"%.8f",(double)price / COIN);
item.push_back(Pair("totalrequired", numstr));
sprintf(numstr,"%.8f",(double)price / (COIN * vintx.vout[0].nValue));
item.push_back(Pair("price", numstr));
sprintf(numstr, "%.8f", (double)ordertx.vout[it->first.index].nValue / COIN);
item.push_back(Pair("amount", numstr));
sprintf(numstr, "%.8f", (double)ordertx.vout[0].nValue / COIN);
item.push_back(Pair("bidamount", numstr));
}
else
{
item.push_back(Pair("totalrequired", (int64_t)price));
sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue / (price * COIN));
item.push_back(Pair("price",numstr));
sprintf(numstr, "%llu", (long long)ordertx.vout[it->first.index].nValue);
item.push_back(Pair("amount", numstr));
sprintf(numstr, "%llu", (long long)ordertx.vout[0].nValue);
item.push_back(Pair("askamount", numstr));
}
if (origpubkey.size() == 33)
{
GetCCaddress(cp, origaddr, pubkey2pk(origpubkey));
item.push_back(Pair("origaddress", origaddr));
GetTokensCCaddress(cpTokens, origtokenaddr, pubkey2pk(origpubkey));
item.push_back(Pair("origtokenaddress", origtokenaddr));
}
if (assetid != zeroid)
item.push_back(Pair("tokenid", uint256_str(assetidstr, assetid)));
if (assetid2 != zeroid)
item.push_back(Pair("otherid", uint256_str(assetidstr, assetid2)));
if (price > 0)
{
if (funcid == 's' || funcid == 'S' || funcid == 'e' || funcid == 'e')
{
sprintf(numstr, "%.8f", (double)price / COIN);
item.push_back(Pair("totalrequired", numstr));
sprintf(numstr, "%.8f", (double)price / (COIN * ordertx.vout[0].nValue));
item.push_back(Pair("price", numstr));
}
else
{
item.push_back(Pair("totalrequired", (int64_t)price));
sprintf(numstr, "%.8f", (double)ordertx.vout[0].nValue / (price * COIN));
item.push_back(Pair("price", numstr));
}
}
result.push_back(item);
LOGSTREAM("ccassets", CCLOG_DEBUG1, stream << "addOrders() added order funcId=" << (char)(funcid ? funcid : ' ') << " it->first.index=" << it->first.index << " ordertx.vout[it->first.index].nValue=" << ordertx.vout[it->first.index].nValue << " tokenid=" << assetid.GetHex() << std::endl);
}
result.push_back(item);
//fprintf(stderr,"addOrders() func.(%c) %s/v%d %.8f\n",funcid,uint256_str(assetidstr,txid),(int32_t)it->first.index,(double)vintx.vout[it->first.index].nValue/COIN);
}
}
};
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputsTokens, unspentOutputsDualEvalTokens, unspentOutputsCoins;
char assetsUnspendableAddr[64];
GetCCaddress(cpAssets, assetsUnspendableAddr, GetUnspendable(cpAssets, NULL));
SetCCunspents(unspentOutputsAssets, assetsUnspendableAddr /*(char *)cpTokens->unspendableCCaddr*/);
SetCCunspents(unspentOutputsCoins, assetsUnspendableAddr,true);
char tokensUnspendableAddr[64];
GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
SetCCunspents(unspentOutputsAssets, tokensUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/);
char assetsTokensUnspendableAddr[64];
std::vector<uint8_t> vopretNonfungible;
if (refassetid != zeroid) {
GetNonfungibleData(refassetid, vopretNonfungible);
if (vopretNonfungible.size() > 0)
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
}
GetTokensCCaddress(cpAssets, assetsTokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
SetCCunspents(unspentOutputsTokens, assetsTokensUnspendableAddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itTokens = unspentOutputsTokens.begin();
// tokenbids:
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itCoins = unspentOutputsCoins.begin();
itCoins != unspentOutputsCoins.end();
itCoins++)
addOrders(cpAssets, itCoins);
// tokenasks:
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itTokens = unspentOutputsTokens.begin();
itTokens != unspentOutputsTokens.end();
itTokens++)
addOrders(cpTokens, itTokens);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itAssets = unspentOutputsAssets.begin();
itAssets != unspentOutputsAssets.end();
itAssets++)
addOrders(cpAssets, itAssets);
addOrders(cpAssets, itTokens);
if (additionalEvalCode != 0) { //this would be mytokenorders
char assetsDualEvalTokensUnspendableAddr[64];
// try also dual eval tokenasks (and we do not need bids):
cpAssets->additionalTokensEvalcode2 = additionalEvalCode;
GetTokensCCaddress(cpAssets, assetsDualEvalTokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
SetCCunspents(unspentOutputsDualEvalTokens, assetsDualEvalTokensUnspendableAddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itDualEvalTokens = unspentOutputsDualEvalTokens.begin();
itDualEvalTokens != unspentOutputsDualEvalTokens.end();
itDualEvalTokens++)
addOrders(cpAssets, itDualEvalTokens);
}
return(result);
}
@@ -328,14 +299,14 @@ std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, in
return ("");
}
CPubKey unspendablePubkey = GetUnspendable(cpAssets, 0);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, unspendablePubkey));
CPubKey unspendableAssetsPubkey = GetUnspendable(cpAssets, 0);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, unspendableAssetsPubkey));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk));
std::vector<CPubKey> voutTokenPubkeys; // should be empty - no token vouts
return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('b', zeroid, pricetotal, Mypubkey()))));
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.
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("");
@@ -348,7 +319,6 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
CPubKey mypk;
uint64_t mask;
int64_t inputs, CCchange;
CScript opret;
struct CCcontract_info *cpAssets, assetsC;
struct CCcontract_info *cpTokens, tokensC;
@@ -359,7 +329,8 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
return("");
}
cpAssets = CCinit(&assetsC, EVAL_ASSETS); // NOTE: this is for signing
cpAssets = CCinit(&assetsC, EVAL_ASSETS); // NOTE: for signing
if (txfee == 0)
txfee = 10000;
@@ -367,10 +338,11 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
mypk = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
{
std::vector<uint8_t> vopretNonfungible;
mask = ~((1LL << mtx.vin.size()) - 1);
// add single-eval tokens:
cpTokens = CCinit(&tokensC, EVAL_TOKENS); // NOTE: tokens is here
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, askamount, 60)) > 0)
// add single-eval tokens (or non-fungible tokens):
cpTokens = CCinit(&tokensC, EVAL_TOKENS); // NOTE: adding inputs only from EVAL_TOKENS cc
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, askamount, 60, vopretNonfungible)) > 0)
{
if (inputs < askamount) {
//was: askamount = inputs;
@@ -379,20 +351,26 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
return ("");
}
CPubKey unspendablePubkey = GetUnspendable(cpAssets, NULL);
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, askamount, unspendablePubkey));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); //marker
// if this is non-fungible tokens:
if( !vopretNonfungible.empty() )
// set its evalcode
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
CPubKey unspendableAssetsPubkey = GetUnspendable(cpAssets, NULL);
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, cpAssets->additionalTokensEvalcode2, askamount, unspendableAssetsPubkey));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); //marker (seems, it is not for tokenorders)
if (inputs > askamount)
CCchange = (inputs - askamount);
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // change to single-eval token vout
// change to single-eval or non-fungible token vout (although for non-fungible token change currently is not possible)
mtx.vout.push_back(MakeTokensCC1vout((cpAssets->additionalTokensEvalcode2) ? cpAssets->additionalTokensEvalcode2 : EVAL_TOKENS, CCchange, mypk));
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(unspendablePubkey);
voutTokenPubkeys.push_back(unspendableAssetsPubkey);
opret = EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey()));
return(FinalizeCCTx(mask,cpAssets, mtx, mypk, txfee, opret));
return FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey()))));
}
else {
fprintf(stderr, "need some tokens to place ask\n");
@@ -430,7 +408,7 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
if ((inputs = AddAssetInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0)
/*if ((inputs = AddAssetInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0)
{
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
if (inputs < askamount) {
@@ -458,13 +436,13 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
else {
opret = EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('e', assetid2, pricetotal, Mypubkey()));
}
}
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
}
else {
fprintf(stderr, "need some assets to place ask\n");
}
} */
}
else { // dimxy added 'else', because it was misleading message before
fprintf(stderr,"need some native coins to place ask\n");
@@ -494,12 +472,14 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
mask = ~((1LL << mtx.vin.size()) - 1);
if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0)
{
std::vector<uint8_t> vopretNonfungible;
GetNonfungibleData(assetid, vopretNonfungible);
bidamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets
if((funcid=DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey))!=0)
{
if (funcid == 's') mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); // spend marker if funcid='b'
else if (funcid=='S') mtx.vin.push_back(CTxIn(bidtxid, 3, CScript())); // spend marker if funcid='B'
}
@@ -510,8 +490,8 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
std::vector<CPubKey> voutTokenPubkeys; // should be empty, no token vouts
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('o', zeroid, 0, Mypubkey()))));
EncodeTokenOpRet(assetid, voutTokenPubkeys,
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('o', zeroid, 0, Mypubkey())))));
}
}
return("");
@@ -523,8 +503,12 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction vintx; uint64_t mask;
uint256 hashBlock; int64_t askamount;
CPubKey mypk; struct CCcontract_info *cpTokens, *cpAssets, tokensC, assetsC;
uint8_t funcid,dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector<uint8_t> dummyOrigpubkey;
CPubKey mypk;
struct CCcontract_info *cpTokens, *cpAssets, tokensC, assetsC;
uint8_t funcid, dummyEvalCode;
uint256 dummyAssetid, dummyAssetid2;
int64_t dummyPrice;
std::vector<uint8_t> dummyOrigpubkey;
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
@@ -538,27 +522,29 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
mask = ~((1LL << mtx.vin.size()) - 1);
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
{
std::vector<uint8_t> vopretNonfungible;
GetNonfungibleData(assetid, vopretNonfungible);
askamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(asktxid, 0, CScript()));
if ((funcid=DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey))!=0)
{
if (funcid == 's') mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s'
else if (funcid=='S') mtx.vin.push_back(CTxIn(asktxid, 3, CScript())); // marker if funcid='S'
if (funcid == 's')
mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s'
else if (funcid=='S')
mtx.vin.push_back(CTxIn(asktxid, 3, CScript())); // marker if funcid='S'
}
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); // one-eval token vout
if (vopretNonfungible.size() > 0)
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
mtx.vout.push_back(MakeTokensCC1vout(cpAssets->additionalTokensEvalcode2 == 0 ? EVAL_TOKENS : cpAssets->additionalTokensEvalcode2, askamount, mypk)); // one-eval token vout
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(mypk);
/* char myCCaddr[65];
uint8_t myPrivkey[32];
Myprivkey(myPrivkey);
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
GetCCaddress(cpAssets, myCCaddr, mypk); */
// this is only for unspendable addresses:
//CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); //do we need this? Seems FinalizeCCTx can attach to any evalcode cc addr by calling Getscriptaddress
@@ -572,8 +558,8 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
CCaddr2set(cpAssets, EVAL_TOKENS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('x', zeroid, 0, Mypubkey()))));
EncodeTokenOpRet(assetid, voutTokenPubkeys,
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('x', zeroid, 0, Mypubkey())))));
}
}
return("");
@@ -614,8 +600,9 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
SetAssetOrigpubkey(origpubkey, origprice, vintx);
mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript())); // Coins on Assets unspendable
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, fillamount, 60)) > 0)
std::vector<uint8_t> vopretNonfungible;
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, fillamount, 60, vopretNonfungible)) > 0)
{
if (inputs < fillamount) {
std::cerr << "FillBuyOffer(): insufficient tokens to fill buy offer" << std::endl;
@@ -624,6 +611,10 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
}
SetBidFillamounts(paid_amount, remaining_required, bidamount, fillamount, origprice);
uint8_t additionalTokensEvalcode2 = 0;
if (vopretNonfungible.size() > 0)
additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
if (inputs > fillamount)
CCchange = (inputs - fillamount);
@@ -634,13 +625,13 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // vout0 coins remainder
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // vout1 coins to normal
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens sent to the buyer
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,txfee,origpubkey)); // vout3 marker to origpubkey
mtx.vout.push_back(MakeTokensCC1vout(additionalTokensEvalcode2 == 0 ? EVAL_TOKENS : additionalTokensEvalcode2, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens sent to the originator
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, origpubkey)); // vout3 marker to origpubkey
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // vout4 change in single-eval tokens
fprintf(stderr,"FillBuyOffer remaining %llu -> origpubkey\n", (long long)remaining_required);
fprintf(stderr,"FillBuyOffer() remaining %llu -> origpubkey\n", (long long)remaining_required);
char unspendableAssetsAddr[64];
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
@@ -653,9 +644,9 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(pubkey2pk(origpubkey));
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('B', zeroid, remaining_required, origpubkey))));
return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('B', zeroid, remaining_required, origpubkey)))));
} else return("dont have any assets to fill bid");
}
}
@@ -691,15 +682,21 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
return("");
}
std::vector<uint8_t> vopretNonfungible;
uint8_t additionalTokensEvalcode2 = 0;
GetNonfungibleData(assetid, vopretNonfungible);
if (vopretNonfungible.size() > 0)
additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
if (txfee == 0)
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
//if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
//{
//mask = ~((1LL << mtx.vin.size()) - 1);
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
{
orig_assetoshis = vintx.vout[askvout].nValue;
@@ -707,13 +704,12 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
dprice = (double)total_nValue / orig_assetoshis;
paid_nValue = dprice * fillunits;
mtx.vin.push_back(CTxIn(asktxid, askvout, CScript())); // NOTE: this is the reference to tokens -> send cpTokens for signing into FinalizeCCTx!
if (assetid2 != zeroid)
inputs = AddAssetInputs(cpAssets, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet
if (assetid2 != zeroid) {
inputs = 0; // = AddAssetInputs(cpAssets, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet
}
else
{
inputs = AddNormalinputs(mtx, mypk, paid_nValue, 60);
inputs = AddNormalinputs(mtx, mypk, 2 * txfee + paid_nValue, 60); // Better to use single AddNormalinputs() to allow payment if user has only single utxo with normal funds
mask = ~((1LL << mtx.vin.size()) - 1);
}
if (inputs > 0)
@@ -723,7 +719,10 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
CCerror = strprintf("insufficient coins to fill sell");
return ("");
}
// cc vin should be after normal vin
mtx.vin.push_back(CTxIn(asktxid, askvout, CScript()));
if (assetid2 != zeroid)
SetSwapFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); //not implemented correctly yet
else
@@ -732,11 +731,11 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
if (assetid2 != zeroid && inputs > paid_nValue)
CCchange = (inputs - paid_nValue);
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // vout.0 tokens remainder to unspendable cc addr
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //vout.1 purchased tokens to self single-eval addr
// vout.0 tokens remainder to unspendable cc addr:
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, additionalTokensEvalcode2, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL)));
//vout.1 purchased tokens to self token single-eval or dual-eval token+nonfungible cc addr:
mtx.vout.push_back(MakeTokensCC1vout(additionalTokensEvalcode2 == 0 ? EVAL_TOKENS : additionalTokensEvalcode2, received_assetoshis, mypk));
// NOTE: no marker here
if (assetid2 != zeroid) {
std::cerr << "FillSell() WARNING: asset swap not implemented yet! (paid_nValue)" << std::endl;
// TODO: change MakeCC1vout appropriately when implementing:
@@ -768,14 +767,16 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(mypk);
cpAssets->additionalTokensEvalcode2 = additionalTokensEvalcode2;
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid2, remaining_nValue, origpubkey))));
EncodeTokenOpRet(assetid, voutTokenPubkeys,
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());
}
}
}
//}
return("");
}

View File

@@ -31,6 +31,7 @@
#include "CCPayments.h"
#include "CCGateways.h"
#include "CCtokens.h"
#include "CCImportGateway.h"
/*
CCcustom has most of the functions that need to be extended to create a new CC contract.
@@ -63,7 +64,6 @@ const char *AssetsCCaddr = "RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6";
const char *AssetsNormaladdr = "RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u";
char AssetsCChexstr[67] = { "02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702" };
uint8_t AssetsCCpriv[32] = { 0x9b, 0x17, 0x66, 0xe5, 0x82, 0x66, 0xac, 0xb6, 0xba, 0x43, 0x83, 0x74, 0xf7, 0x63, 0x11, 0x3b, 0xf0, 0xf3, 0x50, 0x6f, 0xd9, 0x6b, 0x67, 0x85, 0xf9, 0x7a, 0xf0, 0x54, 0x4d, 0xb1, 0x30, 0x77 };
#include "CCcustom.inc"
#undef FUNCNAME
#undef EVALCODE
@@ -75,7 +75,6 @@ const char *FaucetCCaddr = "R9zHrofhRbub7ER77B7NrVch3A63R39GuC";
const char *FaucetNormaladdr = "RKQV4oYs4rvxAWx1J43VnT73rSTVtUeckk";
char FaucetCChexstr[67] = { "03682b255c40d0cde8faee381a1a50bbb89980ff24539cb8518e294d3a63cefe12" };
uint8_t FaucetCCpriv[32] = { 0xd4, 0x4f, 0xf2, 0x31, 0x71, 0x7d, 0x28, 0x02, 0x4b, 0xc7, 0xdd, 0x71, 0xa0, 0x39, 0xc4, 0xbe, 0x1a, 0xfe, 0xeb, 0xc2, 0x46, 0xda, 0x76, 0xf8, 0x07, 0x53, 0x3d, 0x96, 0xb4, 0xca, 0xa0, 0xe9 };
#include "CCcustom.inc"
#undef FUNCNAME
#undef EVALCODE
@@ -243,28 +242,67 @@ uint8_t CClibCCpriv[32] = { 0x57, 0xcf, 0x49, 0x71, 0x7d, 0xb4, 0x15, 0x1b, 0x4f
#undef FUNCNAME
#undef EVALCODE
// ImportGateway
#define FUNCNAME IsImportGatewayInput
#define EVALCODE EVAL_IMPORTGATEWAY
const char *ImportGatewayCCaddr = "RXJT6CRAXHFuQ2UjqdxMj7EfrayF6UJpzZ";
const char *ImportGatewayNormaladdr = "RNFRho63Ddz1Rh2eGPETykrU4fA8r67S4Y";
char ImportGatewayCChexstr[67] = { "0397231cfe04ea32d5fafb2206773ec9fba6e15c5a4e86064468bca195f7542714" };
uint8_t ImportGatewayCCpriv[32] = { 0x65, 0xef, 0x27, 0xeb, 0x3d, 0xb0, 0xb4, 0xae, 0x0f, 0xbc, 0x77, 0xdb, 0xf8, 0x40, 0x48, 0x90, 0x52, 0x20, 0x9e, 0x45, 0x3b, 0x49, 0xd8, 0x97, 0x60, 0x8c, 0x27, 0x4c, 0x59, 0x46, 0xe1, 0xdf };
#include "CCcustom.inc"
#undef FUNCNAME
#undef EVALCODE
int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode)
{
CPubKey pk; uint8_t pub33[33]; char CCaddr[64];
CPubKey pk; int32_t i; uint8_t pub33[33],check33[33],hash[32]; char CCaddr[64],checkaddr[64],str[67];
cp->evalcode = evalcode;
cp->ismyvin = IsCClibInput;
memcpy(cp->CCpriv,CClibCCpriv,32);
if ( evalcode == EVAL_FIRSTUSER ) // eventually make a hashchain for each evalcode
{
cp->evalcode = evalcode;
cp->ismyvin = IsCClibInput;
strcpy(cp->CChexstr,CClibCChexstr);
memcpy(cp->CCpriv,CClibCCpriv,32);
decode_hex(pub33,33,cp->CChexstr);
pk = buf2pk(pub33);
Getscriptaddress(cp->normaladdr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG);
if ( strcmp(cp->normaladdr,CClibNormaladdr) != 0 )
fprintf(stderr,"CClib_initcp addr mismatch %s vs %s\n",cp->normaladdr,CClibNormaladdr);
GetCCaddress(cp,cp->unspendableCCaddr,pk);
return(0);
if ( priv2addr(checkaddr,check33,cp->CCpriv) != 0 )
{
if ( buf2pk(check33) == pk && strcmp(checkaddr,cp->normaladdr) == 0 )
{
//fprintf(stderr,"verified evalcode.%d %s %s\n",cp->evalcode,checkaddr,pubkey33_str(str,pub33));
return(0);
} else fprintf(stderr,"CClib_initcp mismatched privkey -> addr %s vs %s\n",checkaddr,cp->normaladdr);
}
}
else
{
for (i=EVAL_FIRSTUSER; i<evalcode; i++)
{
vcalc_sha256(0,hash,cp->CCpriv,32);
memcpy(cp->CCpriv,hash,32);
}
if ( priv2addr(cp->normaladdr,pub33,cp->CCpriv) != 0 )
{
pk = buf2pk(pub33);
for (i=0; i<33; i++)
sprintf(&cp->CChexstr[i*2],"%02x",pub33[i]);
cp->CChexstr[i*2] = 0;
GetCCaddress(cp,cp->unspendableCCaddr,pk);
//printf("evalcode.%d initialized\n",evalcode);
return(0);
}
}
return(-1);
}
struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
{
// important to clear because not all members are always initialized!
memset(cp, '\0', sizeof(*cp));
cp->evalcode = evalcode;
switch ( evalcode )
{
@@ -397,6 +435,14 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
cp->validate = TokensValidate;
cp->ismyvin = IsTokensInput;
break;
case EVAL_IMPORTGATEWAY:
strcpy(cp->unspendableCCaddr, ImportGatewayCCaddr);
strcpy(cp->normaladdr, ImportGatewayNormaladdr);
strcpy(cp->CChexstr, ImportGatewayCChexstr);
memcpy(cp->CCpriv, ImportGatewayCCpriv, 32);
cp->validate = ImportGatewayValidate;
cp->ismyvin = IsImportGatewayInput;
break;
default:
if ( CClib_initcp(cp,evalcode) < 0 )
return(0);

View File

@@ -42,6 +42,7 @@ one other technical note is that komodod has the insight-explorer extensions bui
#include <cryptoconditions.h>
#include "../script/standard.h"
#include "../base58.h"
#include "../key.h"
#include "../core_io.h"
#include "../script/sign.h"
#include "../wallet/wallet.h"
@@ -50,8 +51,9 @@ one other technical note is that komodod has the insight-explorer extensions bui
#include "../komodo_defs.h"
#include "../utlist.h"
#include "../uthash.h"
#include "merkleblock.h"
#define CC_BURNPUBKEY "02deaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead"
#define CC_MAXVINS 1024
#define SMALLVAL 0.000000000000001
@@ -66,6 +68,29 @@ one other technical note is that komodod has the insight-explorer extensions bui
#include "../komodo_cJSON.h"
// 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<std::pair<uint8_t, std::vector<uint8_t>>> &oprets, uint8_t id, std::vector<uint8_t> &vopret) {
vopret.clear();
for(auto p : oprets) if (p.first == id) { vopret = p.second; return true; }
return false;
}
struct CC_utxo
{
uint256 txid;
@@ -88,13 +113,14 @@ struct CCcontract_info
{
// this is for spending from 'unspendable' CC address
uint8_t evalcode;
uint8_t additionalTokensEvalcode2; // this is for making three-eval-token vouts (EVAL_TOKENS + evalcode + additionalEvalcode2)
char unspendableCCaddr[64], CChexstr[72], normaladdr[64];
uint8_t CCpriv[32];
// this for 1of2 keys coins cryptocondition (for this evalcode)
// NOTE: only one evalcode is allowed at this time
char coins1of2addr[64];
CPubKey coins1of2pk[2];
CPubKey coins1of2pk[2]; uint8_t coins1of2priv[32];
// the same for tokens 1of2 keys cc
char tokens1of2addr[64];
@@ -102,7 +128,7 @@ struct CCcontract_info
// this is for spending from two additional 'unspendable' CC addresses of other eval codes
// (that is, for spending from several cc contract 'unspendable' addresses):
uint8_t evalcode2, evalcode3;
uint8_t unspendableEvalcode2, unspendableEvalcode3; // changed evalcodeN to unspendableEvalcodeN for not mixing up with additionalEvalcodeN
char unspendableaddr2[64], unspendableaddr3[64];
uint8_t unspendablepriv2[32], unspendablepriv3[32];
CPubKey unspendablepk2, unspendablepk3;
@@ -121,6 +147,8 @@ struct oracleprice_info
int32_t height;
};
typedef std::vector<uint8_t> vscript_t;
#ifdef ENABLE_WALLET
extern CWallet* pwalletMain;
#endif
@@ -131,54 +159,70 @@ int32_t komodo_nextheight();
int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256 txid,int32_t vout);
void CCclearvars(struct CCcontract_info *cp);
UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params);
UniValue CClib(struct CCcontract_info *cp,char *method,char *jsonstr);
UniValue CClib_info(struct CCcontract_info *cp);
CBlockIndex *komodo_blockindex(uint256 hash);
CBlockIndex *komodo_chainactive(int32_t height);
int32_t komodo_blockheight(uint256 hash);
void StartShutdown();
static const uint256 zeroid;
static uint256 ignoretxid;
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);
bool myIsutxo_spentinmempool(uint256 txid,int32_t vout);
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);
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp);
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
int64_t CCaddress_balance(char *coinaddr);
int64_t CCaddress_balance(char *coinaddr,int32_t CCflag);
CPubKey CCtxidaddr(char *txidaddr,uint256 txid);
CPubKey CCCustomtxidaddr(char *txidaddr,uint256 txid,uint8_t taddr,uint8_t prefix,uint8_t prefix2);
bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn,
CTransaction &txOut, std::vector<std::vector<unsigned char>> &preConditions, std::vector<std::vector<unsigned char>> &params);
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format);
uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format);
uint256 OracleMerkle(int32_t height,uint256 reforacletxid,char *format,std::vector<struct oracle_merklepair>publishers);
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 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 EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
//bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description);
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload);
CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload);
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description);
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopretExtra);
uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format);
uint8_t DecodeOraclesOpRet(const CScript &scriptPubKey,uint256 &oracletxid,CPubKey &pk,int64_t &num);
uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data);
int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen);
//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, 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);
void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,std::vector<uint8_t> payload);
int32_t payments_parsehexdata(std::vector<uint8_t> &hexdata,cJSON *item,int32_t len);
int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex);
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, vscript_t vopretNonfungible);
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, std::vector<std::pair<uint8_t, vscript_t>> oprets);
CScript EncodeTokenImportOpRet(std::vector<uint8_t> origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector<std::pair<uint8_t, vscript_t>> oprets);
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::pair<uint8_t, vscript_t> opretWithId);
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> oprets);
int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk);
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description);
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, std::vector<std::pair<uint8_t, vscript_t>> &oprets);
uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector<std::pair<uint8_t, vscript_t>> &oprets);
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> &oprets);
void GetNonfungibleData(uint256 tokenid, vscript_t &vopretNonfungible);
bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector<CPubKey> &vinPubkeys);
// CCcustom
CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv);
//uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopret1, std::vector<uint8_t> &vopret2);
// CCutils
bool priv2addr(char *coinaddr,uint8_t buf33[33],uint8_t priv32[32]);
CPubKey buf2pk(uint8_t *buf33);
void endiancpy(uint8_t *dest,uint8_t *src,int32_t len);
uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t entropyvout,int32_t usevout);
@@ -189,26 +233,29 @@ CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2);
CC* GetCryptoCondition(CScript const& scriptSig);
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr);
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2,uint8_t *priv,char *coinaddr);
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2);
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2);
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk);
CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk);
CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2);
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2);
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk);
CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk);
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk);
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2);
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr);
int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode);
bool IsCCInput(CScript const& scriptSig);
bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime);
int32_t unstringbits(char *buf,uint64_t bits);
uint64_t stringbits(char *str);
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<uint8_t> pubkey);
int64_t CCfullsupply(uint256 tokenid);
int64_t CCtoken_balance(char *destaddr,uint256 tokenid);
@@ -219,20 +266,24 @@ bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubK
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue);
bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t numvins,int32_t preventCCvouts,int32_t numvouts);
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
bool GetCustomscriptaddress(char *destaddr,const CScript &scriptPubKey,uint8_t taddr,uint8_t prefix,uint8_t prefix2);
std::vector<uint8_t> Mypubkey();
bool Myprivkey(uint8_t myprivkey[]);
int64_t CCduration(int32_t &numblocks,uint256 txid);
uint256 CCOraclesReverseScan(char const *logcategory,uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid);
int32_t CCCointxidExists(char const *logcategory,uint256 cointxid);
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids);
bool komodo_txnotarizedconfirmed(uint256 txid);
CPubKey check_signing_pubkey(CScript scriptSig);
// CCtx
bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey);
extern std::vector<CPubKey> NULL_pubkeys;
std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret,std::vector<CPubKey> pubkeys = NULL_pubkeys);
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr);
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr);
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr,bool CCflag = true);
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr,bool CCflag = true);
int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs);
int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinputs);
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout);
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout,int32_t CCflag);
// curve25519 and sha256
bits256 curve25519_shared(bits256 privkey,bits256 otherpub);
@@ -242,4 +293,31 @@ void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uin
bits256 bits256_doublesha256(char *deprecated,uint8_t *data,int32_t datalen);
UniValue ValueFromAmount(const CAmount& amount);
// bitcoin LogPrintStr with category "-debug" cmdarg support for C++ ostringstream:
#define CCLOG_INFO 0
#define CCLOG_DEBUG1 1
#define CCLOG_DEBUG2 2
#define CCLOG_DEBUG3 3
#define CCLOG_MAXLEVEL 3
template <class T>
void CCLogPrintStream(const char *category, int level, T print_to_stream)
{
std::ostringstream stream;
print_to_stream(stream);
if (level < 0)
level = 0;
if (level > CCLOG_MAXLEVEL)
level = CCLOG_MAXLEVEL;
for (int i = level; i <= CCLOG_MAXLEVEL; i++)
if( LogAcceptCategory((std::string(category) + std::string("-") + std::to_string(i)).c_str()) || // '-debug=cctokens-0', '-debug=cctokens-1',...
i == 0 && LogAcceptCategory(std::string(category).c_str()) ) { // also supporting '-debug=cctokens' for CCLOG_INFO
LogPrintStr(stream.str());
break;
}
}
// use: LOGSTREAM("yourcategory", your-debug-level, stream << "some log data" << data2 << data3 << ... << std::endl);
#define LOGSTREAM(category, level, logoperator) CCLogPrintStream( category, level, [=](std::ostringstream &stream) {logoperator;} )
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -28,17 +28,13 @@
// CCcustom
bool TokensValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid);
//int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector<CPubKey> vinPubkeys);
std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description);
std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description, std::vector<uint8_t> nonfungibleData);
std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector<uint8_t> destpubkey, int64_t total);
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);
UniValue TokenList();
//this is in CCinclude.h int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs);
//this is in CCinclude.h uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
#endif

296
src/cc/CCtokensOpRet.cpp Normal file
View File

@@ -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<uint8_t> 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<std::pair<uint8_t, vscript_t>> 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<uint8_t> origpubkey, std::string name, std::string description, std::vector<std::pair<uint8_t, vscript_t>> 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<uint8_t> origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector<std::pair<uint8_t, vscript_t>> 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<CPubKey> voutPubkeys, std::pair<uint8_t, vscript_t> opretWithId)
{
std::vector<std::pair<uint8_t, vscript_t>> oprets;
oprets.push_back(opretWithId);
return EncodeTokenOpRet(tokenid, voutPubkeys, oprets);
}
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> 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<CPubKey> 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<uint8_t> &origpubkey, std::string &name, std::string &description) {
//vopret_t vopretNonfungibleDummy;
std::vector<std::pair<uint8_t, vscript_t>> opretsDummy;
return DecodeTokenCreateOpRet(scriptPubKey, origpubkey, name, description, opretsDummy);
}
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, std::vector<std::pair<uint8_t, vscript_t>> &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<uint8_t> &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector<std::pair<uint8_t, vscript_t>> &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<CPubKey> &voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> &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;
}

View File

@@ -46,9 +46,9 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
CTransaction vintx; std::string hex; CPubKey globalpk; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0;
int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0;
int32_t i,flag,utxovout,n,err = 0;
char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], tokensunspendable[64];
uint8_t *privkey, myprivkey[32], unspendablepriv[32], tokensunspendablepriv[32], *msg32 = 0;
CC *mycond=0, *othercond=0, *othercond2=0,*othercond4=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL;
char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], unspendabletokensaddr[64],CC1of2CCaddr[64];
uint8_t *privkey, myprivkey[32], unspendablepriv[32], /*tokensunspendablepriv[32],*/ *msg32 = 0;
CC *mycond=0, *othercond=0, *othercond2=0,*othercond4=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond=0, *condCC2=0,*mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL;
CPubKey unspendablepk /*, tokensunspendablepk*/;
struct CCcontract_info *cpTokens, tokensC;
globalpk = GetUnspendable(cp,0);
@@ -69,26 +69,28 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
GetCCaddress(cp,myaddr,mypk);
mycond = MakeCCcond1(cp->evalcode,mypk);
// to spend from single-eval evalcode 'unspendable'
// to spend from single-eval evalcode 'unspendable' cc addr
unspendablepk = GetUnspendable(cp, unspendablepriv);
GetCCaddress(cp, unspendable, unspendablepk);
othercond = MakeCCcond1(cp->evalcode, unspendablepk);
GetCCaddress1of2(cp,CC1of2CCaddr,unspendablepk,unspendablepk);
//fprintf(stderr,"evalcode.%d (%s)\n",cp->evalcode,unspendable);
// tokens support:
// to spend from dual-eval mypk vout
// to spend from dual/three-eval mypk vout
GetTokensCCaddress(cp, mytokensaddr, mypk);
mytokenscond = MakeTokensCCcond1(cp->evalcode, mypk);
// NOTE: if additionalEvalcode2 is not set it is a dual-eval (not three-eval) cc cond:
mytokenscond = MakeTokensCCcond1(cp->evalcode, cp->additionalTokensEvalcode2, mypk);
// to spend from single-eval EVAL_TOKENS mypk
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
GetCCaddress(cpTokens, mysingletokensaddr, mypk);
mysingletokenscond = MakeCCcond1(EVAL_TOKENS, mypk);
// to spend from dual-eval EVAL_TOKEN+evalcode 'unspendable' pk
//tokensunspendablepk = GetUnspendable(cpTokens, tokensunspendablepriv);
GetTokensCCaddress(cp, tokensunspendable, unspendablepk);
othertokenscond = MakeTokensCCcond1(cp->evalcode, unspendablepk);
// to spend from dual/three-eval EVAL_TOKEN+evalcode 'unspendable' pk:
GetTokensCCaddress(cp, unspendabletokensaddr, unspendablepk); // it may be a three-eval cc, if cp->additionalEvalcode2 is set
othertokenscond = MakeTokensCCcond1(cp->evalcode, cp->additionalTokensEvalcode2, unspendablepk);
//Reorder vins so that for multiple normal vins all other except vin0 goes to the end
//This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation.
@@ -154,10 +156,11 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
else
{
Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey);
//fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr);
//std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " myaddr=" << myaddr << std::endl;
if( strcmp(destaddr,myaddr) == 0 )
//fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s) vs %s\n",i,(double)utxovalues[i]/COIN,destaddr,cp->unspendableaddr2);
//std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " for vin[" << i << "] satoshis=" << utxovalues[i] << std::endl;
if( strcmp(destaddr, myaddr) == 0 )
{
//fprintf(stderr, "FinalizeCCTx() matched cc myaddr (%s)\n", myaddr);
privkey = myprivkey;
cond = mycond;
}
@@ -165,33 +168,33 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
{
privkey = myprivkey;
cond = mytokenscond;
//fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout CC addr.(%s)\n",mytokensaddr);
//fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout my token addr.(%s)\n",mytokensaddr);
}
else if (strcmp(destaddr, mysingletokensaddr) == 0) // if this is TokensCC1vout
{
privkey = myprivkey;
cond = mysingletokenscond;
//fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout CC addr.(%s)\n", mytokensaddr);
//fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout my token addr.(%s)\n", mytokensaddr);
}
else if ( strcmp(destaddr,unspendable) == 0 )
{
privkey = unspendablepriv;
cond = othercond;
//fprintf(stderr,"FinalizeCCTx() matched unspendable CC addr.(%s)\n",unspendable);
//fprintf(stderr,"FinalizeCCTx evalcode(%d) matched unspendable CC addr.(%s)\n",cp->evalcode,unspendable);
}
else if (strcmp(destaddr, tokensunspendable) == 0)
else if (strcmp(destaddr, unspendabletokensaddr) == 0)
{
privkey = unspendablepriv;
cond = othertokenscond;
//fprintf(stderr,"FinalizeCCTx() matched tokensunspendable CC addr.(%s)\n",unspendable);
//fprintf(stderr,"FinalizeCCTx() matched unspendabletokensaddr dual/three-eval CC addr.(%s)\n",unspendabletokensaddr);
}
// check if this is the 2nd additional evalcode + 'unspendable' cc addr:
else if ( strcmp(destaddr,cp->unspendableaddr2) == 0)
else if ( strcmp(destaddr, cp->unspendableaddr2) == 0)
{
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2);
privkey = cp->unspendablepriv2;
if ( othercond2 == 0 )
othercond2 = MakeCCcond1(cp->evalcode2, cp->unspendablepk2);
if( othercond2 == 0 )
othercond2 = MakeCCcond1(cp->unspendableEvalcode2, cp->unspendablepk2);
cond = othercond2;
}
// check if this is 3rd additional evalcode + 'unspendable' cc addr:
@@ -199,26 +202,36 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
{
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3);
privkey = cp->unspendablepriv3;
if ( othercond3 == 0 )
othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3);
if( othercond3 == 0 )
othercond3 = MakeCCcond1(cp->unspendableEvalcode3, cp->unspendablepk3);
cond = othercond3;
}
// check if this is spending from 1of2 cc coins addr:
else if (strcmp(cp->coins1of2addr, destaddr) == 0)
{
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr);
privkey = myprivkey;
privkey = cp->coins1of2priv;//myprivkey;
if (othercond1of2 == 0)
othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->coins1of2pk[0], cp->coins1of2pk[1]);
cond = othercond1of2;
}
else if ( strcmp(CC1of2CCaddr,destaddr) == 0 )
{
//fprintf(stderr,"FinalizeCCTx() matched %s CC1of2CCaddr!\n",CC1of2CCaddr);
privkey = unspendablepriv;
if (condCC2 == 0)
condCC2 = MakeCCcond1of2(cp->evalcode,unspendablepk,unspendablepk);
cond = condCC2;
}
// check if this is spending from 1of2 cc tokens addr:
else if (strcmp(cp->tokens1of2addr, destaddr) == 0)
{
//fprintf(stderr,"FinalizeCCTx() matched %s cp->tokens1of2addr!\n", cp->tokens1of2addr);
privkey = myprivkey;
if (othercond1of2tokens == 0)
othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->tokens1of2pk[0], cp->tokens1of2pk[1]);
// NOTE: if additionalEvalcode2 is not set then it is dual-eval cc else three-eval cc
// TODO: verify evalcodes order if additionalEvalcode2 is not 0
othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->additionalTokensEvalcode2, cp->tokens1of2pk[0], cp->tokens1of2pk[1]);
cond = othercond1of2tokens;
}
else
@@ -242,7 +255,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
if ( flag == 0 )
{
fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr);
continue;
return("");
}
}
uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata);
@@ -264,9 +277,11 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
}
}
} else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
}
}
if ( mycond != 0 )
cc_free(mycond);
if ( condCC2 != 0 )
cc_free(condCC2);
if ( othercond != 0 )
cc_free(othercond);
if ( othercond2 != 0 )
@@ -275,13 +290,23 @@ 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);
else return("0");
}
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr)
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr,bool ccflag)
{
int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
n = (int32_t)strlen(coinaddr);
@@ -290,7 +315,7 @@ void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValu
for (i=0; i<=n; i++)
ptr[i] = coinaddr[i];
CBitcoinAddress address(addrstr);
if ( address.GetIndexKey(hashBytes, type) == 0 )
if ( address.GetIndexKey(hashBytes, type, ccflag) == 0 )
return;
addresses.push_back(std::make_pair(hashBytes,type));
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++)
@@ -300,7 +325,7 @@ void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValu
}
}
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr)
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr,bool ccflag)
{
int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
n = (int32_t)strlen(coinaddr);
@@ -309,7 +334,7 @@ void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex
for (i=0; i<=n; i++)
ptr[i] = coinaddr[i];
CBitcoinAddress address(addrstr);
if ( address.GetIndexKey(hashBytes, type) == 0 )
if ( address.GetIndexKey(hashBytes, type, ccflag) == 0 )
return;
addresses.push_back(std::make_pair(hashBytes,type));
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++)
@@ -319,10 +344,10 @@ void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex
}
}
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout,int32_t CCflag)
{
uint256 txid; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,CCflag!=0?true:false);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -332,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(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
{
@@ -366,10 +403,10 @@ int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256
return(0);
}
int64_t CCaddress_balance(char *coinaddr)
int64_t CCaddress_balance(char *coinaddr,int32_t CCflag)
{
int64_t sum = 0; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,CCflag!=0?true:false);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
sum += it->second.satoshis;
@@ -380,32 +417,33 @@ int64_t CCaddress_balance(char *coinaddr)
int64_t CCfullsupply(uint256 tokenid)
{
uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector<uint8_t> origpubkey; std::string name,description;
if ( GetTransaction(tokenid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
if ( myGetTransaction(tokenid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if (DecodeTokenCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description))
{
return(tx.vout[0].nValue);
return(tx.vout[1].nValue);
}
}
return(0);
}
int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
int64_t CCtoken_balance(char *coinaddr,uint256 reftokenid)
{
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock;
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 tokenid,txid,hashBlock;
std::vector<uint8_t> vopretExtra;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
uint8_t evalCode;
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts=tx.vout.size()) > 0 )
{
char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN);
char str[65];
std::vector<CPubKey> voutTokenPubkeys;
if ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, voutTokenPubkeys, vopretExtra) != 0 && assetid == tokenid )
std::vector<std::pair<uint8_t, vscript_t>> oprets;
if ( reftokenid==txid || (DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, tokenid, voutTokenPubkeys, oprets) != 0 && reftokenid == tokenid))
{
sum += it->second.satoshis;
}
@@ -471,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=64; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> 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<COutput> 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)
{
@@ -507,7 +547,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
if ( i != n )
continue;
}
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
up = &utxos[n++];
up->txid = txid;
@@ -515,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;
}
}
@@ -561,18 +601,19 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
return(0);
}
int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinputs)
{
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=64; 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<std::pair<CAddressUnspentKey, CAddressUnspentValue> > 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);
SetCCunspents(unspentOutputs,coinaddr,false);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -598,7 +639,7 @@ int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinput
if ( i != n )
continue;
}
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
up = &utxos[n++];
up->txid = txid;
@@ -606,7 +647,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;
}
}

105
src/cc/CCutilbits.cpp Normal file
View File

@@ -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<unsigned char> 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<uint8_t> 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<n; i++)
dest[i] = pubkey33[i];
return(pk);
}

View File

@@ -76,7 +76,8 @@ CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2)
return(vout);
}
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2)
// make three-eval (token+evalcode+evalcode2) 1of2 cryptocondition:
CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2)
{
// make 1of2 sigs cond
std::vector<CC*> pks;
@@ -85,44 +86,68 @@ CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2)
std::vector<CC*> thresholds;
thresholds.push_back( CCNewEval(E_MARSHAL(ss << evalcode)) );
if( evalcode != EVAL_TOKENS ) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1of2()!
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc
if( evalcode != EVAL_TOKENS ) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1of2()!
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
if( evalcode2 != 0 )
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc
return CCNewThreshold(thresholds.size(), thresholds);
}
// overload to make two-eval (token+evalcode) 1of2 cryptocondition:
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) {
return MakeTokensCCcond1of2(evalcode, 0, pk1, pk2);
}
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk)
// make three-eval (token+evalcode+evalcode2) cryptocondition:
CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk)
{
std::vector<CC*> pks;
pks.push_back(CCNewSecp256k1(pk));
std::vector<CC*> thresholds;
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode)));
if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1()!
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
thresholds.push_back(CCNewThreshold(1, pks)); // signature
if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1()!
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
if (evalcode2 != 0)
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
thresholds.push_back(CCNewThreshold(1, pks)); // signature
return CCNewThreshold(thresholds.size(), thresholds);
}
// overload to make two-eval (token+evalcode) cryptocondition:
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk) {
return MakeTokensCCcond1(evalcode, 0, pk);
}
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2)
// make three-eval (token+evalcode+evalcode2) 1of2 cc vout:
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2)
{
CTxOut vout;
CC *payoutCond = MakeTokensCCcond1of2(evalcode, pk1, pk2);
CC *payoutCond = MakeTokensCCcond1of2(evalcode, evalcode2, pk1, pk2);
vout = CTxOut(nValue, CCPubKey(payoutCond));
cc_free(payoutCond);
return(vout);
}
// overload to make two-eval (token+evalcode) 1of2 cc vout:
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) {
return MakeTokensCC1of2vout(evalcode, 0, nValue, pk1, pk2);
}
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk)
// make three-eval (token+evalcode+evalcode2) cc vout:
CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk)
{
CTxOut vout;
CC *payoutCond = MakeTokensCCcond1(evalcode, pk);
CC *payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk);
vout = CTxOut(nValue, CCPubKey(payoutCond));
cc_free(payoutCond);
return(vout);
}
// overload to make two-eval (token+evalcode) cc vout:
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk) {
return MakeTokensCC1vout(evalcode, 0, nValue, pk);
}
CC* GetCryptoCondition(CScript const& scriptSig)
{
@@ -143,120 +168,53 @@ bool IsCCInput(CScript const& scriptSig)
return true;
}
int32_t unstringbits(char *buf,uint64_t bits)
bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime)
{
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 )
int64_t interest; uint64_t valuein;
CCoinsViewCache &view = *pcoinsTip;
valuein = view.GetValueIn(height,&interest,tx,blocktime);
if ( valuein-tx.GetValueOut() > txfee )
{
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<unsigned char> 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];
//fprintf(stderr, "txfee.%li vs txfee.%li\n", valuein-tx.GetValueOut(), txfee);
return false;
}
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<uint8_t> 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<n; i++)
dest[i] = pubkey33[i];
return(pk);
return true;
}
// set additional 'unspendable' addr
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
{
cp->evalcode2 = evalcode;
cp->unspendableEvalcode2 = evalcode;
cp->unspendablepk2 = pk;
memcpy(cp->unspendablepriv2,priv,32);
strcpy(cp->unspendableaddr2,coinaddr);
}
// set yet another additional 'unspendable' addr
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
{
cp->evalcode3 = evalcode;
cp->unspendableEvalcode3 = evalcode;
cp->unspendablepk3 = pk;
memcpy(cp->unspendablepriv3,priv,32);
strcpy(cp->unspendableaddr3,coinaddr);
}
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 cryptocondition vout:
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr)
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2,uint8_t *priv,char *coinaddr)
{
cp->coins1of2pk[0] = pk1;
cp->coins1of2pk[1] = pk2;
strcpy(cp->coins1of2addr, coinaddr);
memcpy(cp->coins1of2priv,priv,32);
strcpy(cp->coins1of2addr,coinaddr);
}
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 tokens cryptocondition vout:
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr)
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 token cryptocondition vout
// to get tokenaddr use GetTokensCCaddress()
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *tokenaddr)
{
cp->tokens1of2pk[0] = pk1;
cp->tokens1of2pk[1] = pk2;
strcpy(cp->tokens1of2addr, coinaddr);
strcpy(cp->tokens1of2addr, tokenaddr);
}
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
@@ -271,6 +229,18 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
return(false);
}
bool GetCustomscriptaddress(char *destaddr,const CScript &scriptPubKey,uint8_t taddr,uint8_t prefix, uint8_t prefix2)
{
CTxDestination address; txnouttype whichType;
if ( ExtractDestination(scriptPubKey,address) != 0 )
{
strcpy(destaddr,(char *)CCustomBitcoinAddress(address,taddr,prefix,prefix2).ToString().c_str());
return(true);
}
//fprintf(stderr,"ExtractDestination failed\n");
return(false);
}
bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn,
CTransaction &txOut, std::vector<std::vector<unsigned char>> &preConditions, std::vector<std::vector<unsigned char>> &params)
{
@@ -331,6 +301,16 @@ CPubKey CCtxidaddr(char *txidaddr,uint256 txid)
return(pk);
}
CPubKey CCCustomtxidaddr(char *txidaddr,uint256 txid,uint8_t taddr,uint8_t prefix,uint8_t prefix2)
{
uint8_t buf33[33]; CPubKey pk;
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&txid,32);
pk = buf2pk(buf33);
GetCustomscriptaddress(txidaddr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG,taddr,prefix,prefix2);
return(pk);
}
bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk)
{
CC *payoutCond;
@@ -351,11 +331,11 @@ bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
return(_GetCCaddress(destaddr,cp->evalcode,pk));
}
bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, CPubKey pk)
bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, uint8_t evalcode2, CPubKey pk)
{
CC *payoutCond;
destaddr[0] = 0;
if ((payoutCond = MakeTokensCCcond1(evalcode, pk)) != 0)
if ((payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk)) != 0)
{
Getscriptaddress(destaddr, CCPubKey(payoutCond));
cc_free(payoutCond);
@@ -363,12 +343,13 @@ bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, CPubKey pk)
return(destaddr[0] != 0);
}
// get scriptPubKey adddress for three/dual eval token cc vout
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk)
{
destaddr[0] = 0;
if (pk.size() == 0)
pk = GetUnspendable(cp, 0);
return(_GetTokensCCaddress(destaddr, cp->evalcode, pk));
return(_GetTokensCCaddress(destaddr, cp->evalcode, cp->additionalTokensEvalcode2, pk));
}
@@ -384,11 +365,12 @@ bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubK
return(destaddr[0] != 0);
}
// get scriptPubKey adddress for three/dual eval token 1of2 cc vout
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2)
{
CC *payoutCond;
destaddr[0] = 0;
if ((payoutCond = MakeTokensCCcond1of2(cp->evalcode, pk, pk2)) != 0)
if ((payoutCond = MakeTokensCCcond1of2(cp->evalcode, cp->additionalTokensEvalcode2, pk, pk2)) != 0) // if additionalTokensEvalcode2 not set then it is dual-eval cc else three-eval cc
{
Getscriptaddress(destaddr, CCPubKey(payoutCond));
cc_free(payoutCond);
@@ -442,6 +424,20 @@ bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t n
return(true);
}
bool priv2addr(char *coinaddr,uint8_t *buf33,uint8_t priv32[32])
{
CKey priv; CPubKey pk; int32_t i; uint8_t *src;
priv.SetKey32(priv32);
pk = priv.GetPubKey();
if ( buf33 != 0 )
{
src = (uint8_t *)pk.begin();
for (i=0; i<33; i++)
buf33[i] = src[i];
}
return(Getscriptaddress(coinaddr, CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG));
}
std::vector<uint8_t> Mypubkey()
{
extern uint8_t NOTARY_PUBKEY33[33];
@@ -456,7 +452,7 @@ std::vector<uint8_t> Mypubkey()
bool Myprivkey(uint8_t myprivkey[])
{
char coinaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret;
char coinaddr[64],checkaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret; uint8_t buf33[33];
if ( Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG) != 0 )
{
n = (int32_t)strlen(coinaddr);
@@ -477,7 +473,13 @@ bool Myprivkey(uint8_t myprivkey[])
fprintf(stderr,"0x%02x, ",myprivkey[i]);
fprintf(stderr," found privkey for %s!\n",dest);
}
return(true);
if ( priv2addr(checkaddr,buf33,myprivkey) != 0 )
{
if ( buf2pk(buf33) == Mypubkey() && strcmp(checkaddr,coinaddr) == 0 )
return(true);
else printf("mismatched privkey -> addr %s vs %s\n",checkaddr,coinaddr);
}
return(false);
}
#endif
}
@@ -495,7 +497,7 @@ CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv)
void CCclearvars(struct CCcontract_info *cp)
{
cp->evalcode2 = cp->evalcode3 = 0;
cp->unspendableEvalcode2 = cp->unspendableEvalcode3 = 0;
cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0;
}
@@ -530,6 +532,95 @@ int64_t CCduration(int32_t &numblocks,uint256 txid)
return(duration);
}
uint256 CCOraclesReverseScan(char const *logcategory,uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid)
{
CTransaction tx; uint256 hash,mhash,bhash,hashBlock,oracletxid; int32_t len,len2,numvouts;
int64_t val,merkleht; CPubKey pk; std::vector<uint8_t>data; char str[65],str2[65];
txid = zeroid;
LogPrint(logcategory,"start reverse scan %s\n",uint256_str(str,batontxid));
while ( myGetTransaction(batontxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
{
LogPrint(logcategory,"check %s\n",uint256_str(str,batontxid));
if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid )
{
LogPrint(logcategory,"decoded %s\n",uint256_str(str,batontxid));
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());
LogPrint(logcategory,"found merkleht.%d len.%d len2.%d %s %s\n",(int32_t)merkleht,len,len2,uint256_str(str,hash),uint256_str(str2,mhash));
if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid )
{
txid = batontxid;
LogPrint(logcategory,"set txid\n");
return(mhash);
}
else
{
LogPrint(logcategory,"missing hash\n");
return(zeroid);
}
}
else LogPrint(logcategory,"height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height);
batontxid = bhash;
LogPrint(logcategory,"new hash %s\n",uint256_str(str,batontxid));
} else break;
}
LogPrint(logcategory,"end of loop\n");
return(zeroid);
}
int32_t myIs_coinaddr_inmempoolvout(char const *logcategory,char *coinaddr)
{
int32_t i,n; char destaddr[64];
BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
{
const CTransaction &tx = e.GetTx();
if ( (n= tx.vout.size()) > 0 )
{
const uint256 &txid = tx.GetHash();
for (i=0; i<n; i++)
{
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
if ( strcmp(destaddr,coinaddr) == 0 )
{
LogPrint(logcategory,"found (%s) vout in mempool\n",coinaddr);
return(1);
}
}
}
}
return(0);
}
int32_t CCCointxidExists(char const *logcategory,uint256 cointxid)
{
char txidaddr[64]; std::string coin; int32_t numvouts; uint256 hashBlock;
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
CCtxidaddr(txidaddr,cointxid);
SetCCtxids(addressIndex,txidaddr,true);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
return(-1);
}
return(myIs_coinaddr_inmempoolvout(logcategory,txidaddr));
}
/* Get the block merkle root for a proof
* IN: proofData
* OUT: merkle root
* OUT: transaction IDS
*/
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids)
{
CMerkleBlock merkleBlock;
if (!E_UNMARSHAL(proofData, ss >> merkleBlock))
return uint256();
return merkleBlock.txn.ExtractMatches(txids);
}
bool komodo_txnotarizedconfirmed(uint256 txid)
{
char str[65];
@@ -614,6 +705,9 @@ bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> param
from_mempool = 1;
height &= ((1<<30) - 1);
}
if (cp->validate == NULL)
return eval->Invalid("validation not supported for eval code");
//fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d vs CCactive.%d\n",height,from_mempool,KOMODO_CCACTIVATE);
// there is a chance CC tx is valid in mempool, but invalid when in block, so we cant filter duplicate requests. if any of the vins are spent, for example
//txid = ctx.GetHash();

View File

@@ -13,7 +13,7 @@ $(info $(OS))
TARGET = ../libcc.so
TARGET_DARWIN = ../libcc.dylib
TARGET_WIN = ../libcc.dll
SOURCES = cclib.cpp
SOURCES = cclib.cpp
#HEADERS = $(shell echo ../cryptoconditions/include/*.h)
all: $(TARGET)

38
src/cc/Makefile_rogue Normal file
View File

@@ -0,0 +1,38 @@
SHELL = /bin/sh
CC = gcc
CC_DARWIN = g++-6
CC_WIN = x86_64-w64-mingw32-gcc-posix
CFLAGS_DARWIN = -DBUILD_ROGUE -std=c++11 -arch x86_64 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib
CFLAGS = -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared
CFLAGS_WIN = -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I./rogue/x86_64-w64-mingw32/include -I./rogue/x86_64-w64-mingw32/include/ncursesw -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared
DEBUGFLAGS = -O0 -D _DEBUG
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
$(info $(OS))
OS := $(shell uname -s)
$(info $(OS))
TARGET = librogue.so
TARGET_DARWIN = librogue.dylib
TARGET_WIN = librogue.dll
SOURCES = cclib.cpp
#HEADERS = $(shell echo ../cryptoconditions/include/*.h) -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/
all: $(TARGET)
$(TARGET): $(SOURCES)
$(info Building cclib to src/)
ifeq ($(OS),Darwin)
$(CC_DARWIN) $(CFLAGS_DARWIN) $(DEBUGFLAGS) -o $(TARGET_DARWIN) -c $(SOURCES)
cp $(TARGET_DARWIN) ../libcc.dylib
else ifeq ($(HOST),x86_64-w64-mingw32)
$(info WINDOWS)
$(CC_WIN) $(CFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) -c $(SOURCES)
cp $(TARGET_WIN) ../libcc.dll
#else ifeq ($(WIN_HOST),True) - todo: pass ENV var from build.sh if WIN host
else
$(info LINUX)
$(CC) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) -c $(SOURCES)
cp $(TARGET) ../libcc.so
endif
clean:
rm -rf $(TARGET)

View File

@@ -14,6 +14,7 @@
******************************************************************************/
#include "CCassets.h"
#include "CCtokens.h"
/*
Assets can be created or transferred.
@@ -129,21 +130,21 @@
bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
static uint256 zero;
CTxDestination address; CTransaction vinTx,createTx; uint256 hashBlock,assetid,assetid2;
int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts;
int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector<uint8_t> origpubkey,tmporigpubkey,ignorepubkey;
CTxDestination address;
CTransaction vinTx, createTx;
uint256 hashBlock, assetid, assetid2;
int32_t i,starti, numvins, numvouts, preventCCvins, preventCCvouts;
int64_t remaining_price, nValue, assetoshis, outputsDummy,inputs,tmpprice,totalunits,ignore;
std::vector<uint8_t> origpubkey, tmporigpubkey, ignorepubkey, vopretNonfungible, vopretNonfungibleDummy;
uint8_t funcid, evalCodeInOpret;
char destaddr[64], origaddr[64], assetsCCaddr[64], userTokensCCaddr[64]; //, signleEvalTokensCCaddr[64];
char destaddr[64], origNormalAddr[64], origTokensCCaddr[64], origCCaddrDummy[64];
char tokensDualEvalUnspendableCCaddr[64], origAssetsCCaddr[64];
//return true;
//CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL);
//CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, NULL);
//GetCCaddress(cpTokens, tokensUnspendableCCaddr, unspendableTokensPk);
numvins = tx.vin.size();
numvouts = tx.vout.size();
outputs = inputs = 0;
outputsDummy = inputs = 0;
preventCCvins = preventCCvouts = -1;
// add specific chains exceptions for old token support:
@@ -153,16 +154,28 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
if (strcmp(ASSETCHAINS_SYMBOL, "MGNX") == 0 && chainActive.Height() <= 210190)
return true;
// add specific chains exceptions for old token support:
if (strcmp(ASSETCHAINS_SYMBOL, "SEC") == 0 && chainActive.Height() <= 144073)
return true;
if (strcmp(ASSETCHAINS_SYMBOL, "MGNX") == 0 && chainActive.Height() <= 210190)
return true;
if (numvouts == 0)
return eval->Invalid("AssetValidate: no vouts");
if((funcid = DecodeAssetTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 )
return eval->Invalid("AssetValidate: invalid opreturn payload");
// non-fungible tokens support:
GetNonfungibleData(assetid, vopretNonfungible);
if (vopretNonfungible.size() > 0)
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
// find dual-eval tokens unspendable addr:
char tokensUnspendableAddr[64],origpubkeyCCaddr[64];
GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
GetCCaddress(cpAssets, origpubkeyCCaddr, origpubkey);
GetTokensCCaddress(cpAssets, tokensDualEvalUnspendableCCaddr, GetUnspendable(cpAssets, NULL));
// this is for marker validation:
GetCCaddress(cpAssets, origAssetsCCaddr, origpubkey);
// we need this for validating single-eval tokens' vins/vous:
struct CCcontract_info *cpTokens, tokensC;
@@ -171,13 +184,13 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
// find single-eval token user cc addr:
//GetCCaddress(cpTokens, signleEvalTokensCCaddr, pubkey2pk(origpubkey));
fprintf(stderr,"AssetValidate (%c)\n",funcid);
//fprintf(stderr,"AssetValidate (%c)\n",funcid);
if( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid, createTx, hashBlock) == 0 )
return eval->Invalid("cant find asset create txid");
else if( funcid != 'o' && funcid != 'x' && assetid2 != zero && eval->GetTxUnconfirmed(assetid2, createTx, hashBlock) == 0 )
return eval->Invalid("cant find asset2 create txid");
else if( IsCCInput(tx.vin[0].scriptSig) != 0 )
else if( IsCCInput(tx.vin[0].scriptSig) != 0 ) // vin0 should be normal vin
return eval->Invalid("illegal asset vin0");
else if( numvouts < 2 )
return eval->Invalid("too few vouts"); // it was if(numvouts < 1) but it refers at least to vout[1] below
@@ -191,7 +204,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
if( assetid == zero )
return eval->Invalid("illegal assetid");
else if (!AssetCalcAmounts(cpAssets, inputs, outputs, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs
else if (!AssetCalcAmounts(cpAssets, inputs, outputsDummy/*outputsDummy is calculated incorrectly but not used*/, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs
return false; // returns false if some problems with reading vintxes
}
}
@@ -226,9 +239,13 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.1: CC output for marker
//vout.2: normal output for change (if any)
// vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
// as we don't use tokenconvert we should not be here:
return eval->Invalid("invalid asset funcid (b)");
if( remaining_price == 0 )
return eval->Invalid("illegal null amount for buyoffer");
else if( ConstrainVout(tx.vout[0],1,cpAssets->unspendableCCaddr,0) == 0 )
else if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr,0) == 0 ) // coins to assets unspendable cc addr
return eval->Invalid("invalid vout for buyoffer");
preventCCvins = 1;
preventCCvouts = 1;
@@ -243,13 +260,13 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.1: vin.2 back to users pubkey
//vout.2: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['o']
if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 )
if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, origCCaddrDummy, origNormalAddr, tx, assetid)) == 0 )
return(false);
else if( ConstrainVout(tx.vout[0],0, origaddr, nValue) == 0 )
else if( ConstrainVout(tx.vout[0],0, origNormalAddr, nValue) == 0 )
return eval->Invalid("invalid refund for cancelbuy");
preventCCvins = 3;
preventCCvouts = 0;
fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origaddr);
//fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origNormalAddr);
break;
case 'B': // fillbuy:
@@ -264,7 +281,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey]
preventCCvouts = 4;
if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 )
if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 )
return(false);
else if( numvouts < 4 )
return eval->Invalid("not enough vouts for fillbuy");
@@ -274,28 +291,29 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
{
if( nValue != tx.vout[0].nValue + tx.vout[1].nValue )
return eval->Invalid("locked value doesnt match vout0+1 fillbuy");
else if( tx.vout[4].scriptPubKey.IsPayToCryptoCondition() != 0 )
else if( tx.vout[4].scriptPubKey.IsPayToCryptoCondition() != 0 ) // if cc change present
{
if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, 0) == 0 ) // tokens on user cc addr
if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, 0) == 0 ) // tokens to originator cc addr (tokens+nonfungible evals)
return eval->Invalid("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, assetsCCaddr, inputs) == 0 ) // tokens on user cc addr
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");
else if( ConstrainVout(tx.vout[1],0,0,0) == 0 )
else if( ConstrainVout(tx.vout[1], 0, NULL, 0) == 0 )
return eval->Invalid("vout1 is CC for fillbuy");
else if( ConstrainVout(tx.vout[3], 1, origpubkeyCCaddr, 10000) == 0 )
else if( ConstrainVout(tx.vout[3], 1, origAssetsCCaddr, 10000) == 0 ) // marker to asset cc addr
return eval->Invalid("invalid marker for original pubkey");
else if( ValidateBidRemainder(remaining_price, tx.vout[0].nValue, nValue, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false )
return eval->Invalid("mismatched remainder for fillbuy");
else if( remaining_price != 0 )
{
if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) // coins on asset unspendable cc addr
if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) // coins to asset unspendable cc addr
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy");
}
}
fprintf(stderr,"fillbuy validated\n");
//fprintf(stderr,"fillbuy validated\n");
break;
//case 'e': // selloffer
// break; // disable swaps
@@ -308,25 +326,30 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.3: normal output for change (if any)
//'s'.vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey]
//'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey]
// as we don't use tokenconvert we should not be here:
return eval->Invalid("invalid asset funcid (s)");
preventCCvouts = 2;
if( remaining_price == 0 )
return eval->Invalid("illegal null remaining_price for selloffer");
if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("invalid normal vout1 for sellvin");
if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) // cc change
if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) // if cc change presents
{
preventCCvouts++;
if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // check also cc vout[0]
if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // tokens to tokens unspendable cc addr. TODO: this in incorrect, should be assets if we got here!
return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
else if( tx.vout[0].nValue + tx.vout[2].nValue != inputs )
return eval->Invalid("mismatched vout0+vout2 total for selloffer");
}
else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // no cc change, just vout[0]
// no cc change:
else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // tokens to tokens unspendable cc addr TODO: this in incorrect, should be assets if got here!
return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
//fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price);
break;
case 'x': // cancel
case 'x': // cancel sell
//vin.0: normal input
//vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx
//vin.2: CC marker from selloffer for txfee
@@ -335,9 +358,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.2: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 ) // NOTE:
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 ) // NOTE:
return(false);
else if( ConstrainVout(tx.vout[0], 1, userTokensCCaddr, assetoshis) == 0 )
else if( ConstrainVout(tx.vout[0], 1, origTokensCCaddr, assetoshis) == 0 ) // tokens returning to originator cc addr
return eval->Invalid("invalid vout for cancel");
preventCCvins = 3;
preventCCvouts = 1;
@@ -353,7 +376,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.3: normal output for change (if any)
//'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey]
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 )
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 )
return(false);
else if( numvouts < 4 )
return eval->Invalid("not enough vouts for fillask");
@@ -365,21 +388,19 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("locked value doesnt match vout0+1 fillask");
if( ValidateAskRemainder(remaining_price, tx.vout[0].nValue, assetoshis, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false )
return eval->Invalid("mismatched remainder for fillask");
else if( ConstrainVout(tx.vout[1], 1, 0, 0) == 0 )
else if( ConstrainVout(tx.vout[1], 1, NULL, 0) == 0 ) // do not check token buyer's cc addr
return eval->Invalid("normal vout1 for fillask");
else if( ConstrainVout(tx.vout[2], 0, origaddr, 0) == 0 )
else if( ConstrainVout(tx.vout[2], 0, origNormalAddr, 0) == 0 ) // coins to originator normal addr
return eval->Invalid("normal vout1 for fillask");
else if( ConstrainVout(tx.vout[3], 1, origpubkeyCCaddr, 10000) == 0 )
else if( ConstrainVout(tx.vout[3], 1, origAssetsCCaddr, 10000) == 0 ) // marker to originator asset cc addr
return eval->Invalid("invalid marker for original pubkey");
else if( remaining_price != 0 )
{
//char tokensUnspendableAddr[64];
//GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
if ( ConstrainVout(tx.vout[0], 1, tokensUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/, 0) == 0 )
if ( ConstrainVout(tx.vout[0], 1, tokensDualEvalUnspendableCCaddr, 0) == 0 )
return eval->Invalid("mismatched vout0 assets dual unspendable CCaddr for fill sell");
}
}
fprintf(stderr,"fill validated\n");
//fprintf(stderr,"fill validated\n");
break;
case 'E': // fillexchange
////////// not implemented yet ////////////
@@ -399,7 +420,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
// eval->Invalid("asset2 inputs != outputs");
////////// not implemented yet ////////////
if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 )
if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 )
return(false);
else if( numvouts < 3 )
return eval->Invalid("not enough vouts for fillex");
@@ -412,7 +433,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
////////// not implemented yet ////////////
{
if( ConstrainVout(tx.vout[2], 1, userTokensCCaddr, 0) == 0 )
if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, 0) == 0 )
return eval->Invalid("vout2 doesnt go to origpubkey fillex");
else if( inputs != tx.vout[2].nValue + tx.vout[3].nValue )
{
@@ -421,7 +442,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
}
}
////////// not implemented yet ////////////
else if( ConstrainVout(tx.vout[2], 1, userTokensCCaddr, inputs) == 0 )
else if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, inputs) == 0 )
return eval->Invalid("vout2 doesnt match inputs fillex");
else if( ConstrainVout(tx.vout[1], 0, 0, 0) == 0 )
return eval->Invalid("vout1 is CC for fillex");
@@ -438,7 +459,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
}
}
////////// not implemented yet ////////////
fprintf(stderr,"fill validated\n");
//fprintf(stderr,"fill validated\n");
break;
default:
@@ -448,8 +469,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
}
// what does this do?
bool bPrevent = PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts);
std::cerr << "AssetsValidate() PreventCC returned=" << bPrevent << std::endl;
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);
}

View File

@@ -124,7 +124,7 @@ int64_t AddAuctionInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPu
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;

View File

@@ -28,25 +28,298 @@
#include "crosschain.h"
#define FAUCET2SIZE COIN
#define EVAL_FAUCET2 EVAL_FIRSTUSER
struct CClib_rpcinfo
{
char *method,*help;
int32_t numrequiredargs,maxargs; // frontloaded with required
uint8_t funcid;
}
CClib_methods[] =
{
{ (char *)"faucet2_fund", (char *)"amount", 1, 1, 'F' },
{ (char *)"faucet2_get", (char *)"<no args>", 0, 0, 'G' },
};
#ifdef BUILD_ROGUE
#define EVAL_ROGUE 17
std::string MYCCLIBNAME = (char *)"rogue";
std::string MYCCLIBNAME = (char *)"faucet2";
#elif BUILD_CUSTOMCC
#include "customcc.h"
#elif BUILD_GAMESCC
#include "gamescc.h"
#else
#define EVAL_SUDOKU 17
#define EVAL_MUSIG 18
#define EVAL_DILITHIUM 19
std::string MYCCLIBNAME = (char *)"sudoku";
#endif
#ifndef BUILD_GAMESCC
void komodo_netevent(std::vector<uint8_t> payload) {}
#endif
extern std::string MYCCLIBNAME;
char *CClib_name() { return((char *)MYCCLIBNAME.c_str()); }
struct CClib_rpcinfo
{
char *CCname,*method,*help;
int32_t numrequiredargs,maxargs;
uint8_t funcid,evalcode;
}
CClib_methods[] =
{
{ (char *)"faucet2", (char *)"fund", (char *)"amount", 1, 1, 'F', EVAL_FAUCET2 },
{ (char *)"faucet2", (char *)"get", (char *)"<no args>", 0, 0, 'G', EVAL_FAUCET2 },
#ifdef BUILD_ROGUE
{ (char *)"rogue", (char *)"newgame", (char *)"maxplayers buyin", 0, 2, 'G', EVAL_ROGUE },
{ (char *)"rogue", (char *)"gameinfo", (char *)"gametxid", 1, 1, 'T', EVAL_ROGUE },
{ (char *)"rogue", (char *)"pending", (char *)"<no args>", 0, 0, 'P', EVAL_ROGUE },
{ (char *)"rogue", (char *)"register", (char *)"gametxid [playertxid]", 1, 2, 'R', EVAL_ROGUE },
{ (char *)"rogue", (char *)"keystrokes", (char *)"gametxid keystrokes", 2, 2, 'K', EVAL_ROGUE },
{ (char *)"rogue", (char *)"bailout", (char *)"gametxid", 1, 1, 'Q', EVAL_ROGUE },
{ (char *)"rogue", (char *)"highlander", (char *)"gametxid", 1, 1, 'H', EVAL_ROGUE },
{ (char *)"rogue", (char *)"playerinfo", (char *)"playertxid", 1, 1, 'I', EVAL_ROGUE },
{ (char *)"rogue", (char *)"players", (char *)"<no args>", 0, 0, 'D', EVAL_ROGUE },
{ (char *)"rogue", (char *)"games", (char *)"<no args>", 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
#elif BUILD_GAMESCC
RPC_FUNCS
#else
{ (char *)"sudoku", (char *)"gen", (char *)"<no args>", 0, 0, 'G', EVAL_SUDOKU },
{ (char *)"sudoku", (char *)"txidinfo", (char *)"txid", 1, 1, 'T', EVAL_SUDOKU },
{ (char *)"sudoku", (char *)"pending", (char *)"<no args>", 0, 0, 'U', EVAL_SUDOKU },
{ (char *)"sudoku", (char *)"solution", (char *)"txid solution timestamps[81]", 83, 83, 'S', EVAL_SUDOKU },
{ (char *)"musig", (char *)"calcmsg", (char *)"sendtxid scriptPubKey", 2, 2, 'C', EVAL_MUSIG },
{ (char *)"musig", (char *)"combine", (char *)"pubkeys ...", 2, 999999999, 'P', EVAL_MUSIG },
{ (char *)"musig", (char *)"session", (char *)"myindex,numsigners,combined_pk,pkhash,msg32", 5, 5, 'R', EVAL_MUSIG },
{ (char *)"musig", (char *)"commit", (char *)"pkhash,ind,commitment", 3, 3, 'H', EVAL_MUSIG },
{ (char *)"musig", (char *)"nonce", (char *)"pkhash,ind,nonce", 3, 3, 'N', EVAL_MUSIG },
{ (char *)"musig", (char *)"partialsig", (char *)"pkhash,ind,partialsig", 3, 3, 'S', EVAL_MUSIG },
{ (char *)"musig", (char *)"verify", (char *)"msg sig pubkey", 3, 3, 'V', EVAL_MUSIG },
{ (char *)"musig", (char *)"send", (char *)"combined_pk amount", 2, 2, 'x', EVAL_MUSIG },
{ (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
};
std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *params);
#ifdef BUILD_ROGUE
int32_t rogue_replay(uint64_t seed,int32_t sleepmillis);
bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
UniValue rogue_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
#else
bool sudoku_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
UniValue sudoku_txidinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue sudoku_generate(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue sudoku_solution(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue sudoku_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
bool musig_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue musig_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue musig_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
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
cJSON *cclib_reparse(int32_t *nump,char *jsonstr) // assumes origparams will be freed by caller
{
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);
//free(origparams);
} else params = 0;
return(params);
}
UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr)
{
UniValue result(UniValue::VOBJ); uint64_t txfee = 10000; int32_t m; cJSON *params = cclib_reparse(&m,jsonstr);
fprintf(stderr,"method.(%s) -> (%s)\n",jsonstr!=0?jsonstr:"",params!=0?jprint(params,0):"");
#ifdef BUILD_ROGUE
if ( cp->evalcode == EVAL_ROGUE )
{
if ( strcmp(method,"newgame") == 0 )
return(rogue_newgame(txfee,cp,params));
else if ( strcmp(method,"pending") == 0 )
return(rogue_pending(txfee,cp,params));
else if ( strcmp(method,"gameinfo") == 0 )
return(rogue_gameinfo(txfee,cp,params));
else if ( strcmp(method,"register") == 0 )
return(rogue_register(txfee,cp,params));
else if ( strcmp(method,"keystrokes") == 0 )
return(rogue_keystrokes(txfee,cp,params));
else if ( strcmp(method,"bailout") == 0 )
return(rogue_bailout(txfee,cp,params));
else if ( strcmp(method,"highlander") == 0 )
return(rogue_highlander(txfee,cp,params));
else if ( strcmp(method,"extract") == 0 )
return(rogue_extract(txfee,cp,params));
else if ( strcmp(method,"playerinfo") == 0 )
return(rogue_playerinfo(txfee,cp,params));
else if ( strcmp(method,"players") == 0 )
return(rogue_players(txfee,cp,params));
else if ( strcmp(method,"games") == 0 )
return(rogue_games(txfee,cp,params));
else if ( strcmp(method,"setname") == 0 )
return(rogue_setname(txfee,cp,params));
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid rogue method"));
result.push_back(Pair("method",method));
return(result);
}
}
#elif BUILD_CUSTOMCC
CUSTOM_DISPATCH
#elif BUILD_GAMESCC
CUSTOM_DISPATCH
#else
if ( cp->evalcode == EVAL_SUDOKU )
{
//printf("CClib_method params.%p\n",params);
if ( strcmp(method,"txidinfo") == 0 )
return(sudoku_txidinfo(txfee,cp,params));
else if ( strcmp(method,"gen") == 0 )
return(sudoku_generate(txfee,cp,params));
else if ( strcmp(method,"solution") == 0 )
return(sudoku_solution(txfee,cp,params));
else if ( strcmp(method,"pending") == 0 )
return(sudoku_pending(txfee,cp,params));
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid sudoku method"));
result.push_back(Pair("method",method));
return(result);
}
}
else if ( cp->evalcode == EVAL_MUSIG )
{
//printf("CClib_method params.%p\n",params);
if ( strcmp(method,"combine") == 0 )
return(musig_combine(txfee,cp,params));
else if ( strcmp(method,"calcmsg") == 0 )
return(musig_calcmsg(txfee,cp,params));
else if ( strcmp(method,"session") == 0 )
return(musig_session(txfee,cp,params));
else if ( strcmp(method,"commit") == 0 )
return(musig_commit(txfee,cp,params));
else if ( strcmp(method,"nonce") == 0 ) // returns combined nonce if ready
return(musig_nonce(txfee,cp,params));
else if ( strcmp(method,"partialsig") == 0 )
return(musig_partialsig(txfee,cp,params));
else if ( strcmp(method,"verify") == 0 )
return(musig_verify(txfee,cp,params));
else if ( strcmp(method,"send") == 0 )
return(musig_send(txfee,cp,params));
else if ( strcmp(method,"spend") == 0 )
return(musig_spend(txfee,cp,params));
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid musig method"));
result.push_back(Pair("method",method));
return(result);
}
}
else if ( cp->evalcode == EVAL_DILITHIUM )
{
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));
else if ( strcmp(method,"keypair") == 0 )
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 )
return(dilithium_verify(txfee,cp,params));
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid dilithium method"));
result.push_back(Pair("method",method));
return(result);
}
}
#endif
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","only sudoku supported for now"));
result.push_back(Pair("evalcode",(int)cp->evalcode));
return(result);
}
}
UniValue CClib_info(struct CCcontract_info *cp)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i; char str[2];
@@ -55,6 +328,7 @@ UniValue CClib_info(struct CCcontract_info *cp)
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
{
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("evalcode",CClib_methods[i].evalcode));
if ( CClib_methods[i].funcid < ' ' || CClib_methods[i].funcid >= 128 )
obj.push_back(Pair("funcid",CClib_methods[i].funcid));
else
@@ -63,7 +337,8 @@ UniValue CClib_info(struct CCcontract_info *cp)
str[1] = 0;
obj.push_back(Pair("funcid",str));
}
obj.push_back(Pair("name",CClib_methods[i].method));
obj.push_back(Pair("name",CClib_methods[i].CCname));
obj.push_back(Pair("method",CClib_methods[i].method));
obj.push_back(Pair("help",CClib_methods[i].help));
obj.push_back(Pair("params_required",CClib_methods[i].numrequiredargs));
obj.push_back(Pair("params_max",CClib_methods[i].maxargs));
@@ -73,32 +348,38 @@ UniValue CClib_info(struct CCcontract_info *cp)
return(result);
}
UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params)
UniValue CClib(struct CCcontract_info *cp,char *method,char *jsonstr)
{
UniValue result(UniValue::VOBJ); int32_t i; std::string rawtx;
UniValue result(UniValue::VOBJ); int32_t i; std::string rawtx; cJSON *params;
//printf("CClib params.(%s)\n",jsonstr!=0?jsonstr:"");
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
{
if ( strcmp(method,CClib_methods[i].method) == 0 )
if ( cp->evalcode == CClib_methods[i].evalcode && strcmp(method,CClib_methods[i].method) == 0 )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("method",CClib_methods[i].method));
rawtx = CClib_rawtxgen(cp,CClib_methods[i].funcid,params);
result.push_back(Pair("rawtx",rawtx));
return(result);
if ( cp->evalcode == EVAL_FAUCET2 )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("method",CClib_methods[i].method));
params = cJSON_Parse(jsonstr);
rawtx = CClib_rawtxgen(cp,CClib_methods[i].funcid,params);
free_json(params);
result.push_back(Pair("rawtx",rawtx));
return(result);
} else return(CClib_method(cp,method,jsonstr));
}
}
result.push_back(Pair("result","error"));
result.push_back(Pair("method",CClib_methods[i].method));
result.push_back(Pair("method",method));
result.push_back(Pair("error","method not found"));
return(result);
}
int64_t IsCClibvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
int64_t IsCClibvout(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 && strcmp(destaddr,cmpaddr) == 0 )
return(tx.vout[v].nValue);
}
return(0);
@@ -123,7 +404,7 @@ bool CClibExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
//fprintf(stderr,"vini.%d check hash and vout\n",i);
if ( hashBlock == zerohash )
return eval->Invalid("cant faucet2 from mempool");
if ( (assetoshis= IsCClibvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
if ( (assetoshis= IsCClibvout(cp,vinTx,tx.vin[i].prevout.n,cp->unspendableCCaddr)) != 0 )
inputs += assetoshis;
}
}
@@ -131,7 +412,7 @@ bool CClibExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
for (i=0; i<numvouts; i++)
{
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
if ( (assetoshis= IsCClibvout(cp,tx,i)) != 0 )
if ( (assetoshis= IsCClibvout(cp,tx,i,cp->unspendableCCaddr)) != 0 )
outputs += assetoshis;
}
if ( inputs != outputs+FAUCET2SIZE+txfee )
@@ -146,6 +427,24 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
if ( cp->evalcode != EVAL_FAUCET2 )
{
#ifdef BUILD_ROGUE
return(rogue_validate(cp,height,eval,tx));
#elif BUILD_CUSTOMCC
return(custom_validate(cp,height,eval,tx));
#elif BUILD_GAMESCC
return(games_validate(cp,height,eval,tx));
#else
if ( cp->evalcode == EVAL_SUDOKU )
return(sudoku_validate(cp,height,eval,tx));
else if ( cp->evalcode == EVAL_MUSIG )
return(musig_validate(cp,height,eval,tx));
else if ( cp->evalcode == EVAL_DILITHIUM )
return(dilithium_validate(cp,height,eval,tx));
else return eval->Invalid("invalid evalcode");
#endif
}
numvins = tx.vin.size();
numvouts = tx.vout.size();
preventCCvins = preventCCvouts = -1;
@@ -170,7 +469,7 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
else
{
preventCCvouts = 1;
if ( IsCClibvout(cp,tx,0) != 0 )
if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) != 0 )
{
preventCCvouts++;
i = 1;
@@ -183,7 +482,7 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
else if ( (hash[0] & 0xff) != 0 || (hash[31] & 0xff) != 0 )
return eval->Invalid("invalid faucetget txid");
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
SetCCtxids(txids,destaddr);
SetCCtxids(txids,destaddr,tx.vout[i].scriptPubKey.IsPayToCryptoCondition());
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
{
//int height = it->first.blockHeight;
@@ -202,24 +501,28 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
}
}
int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs,char *cmpaddr,int32_t CCflag)
{
char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0,txfee = 10000; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
SetCCunspents(unspentOutputs,coinaddr,CCflag!=0?true:false);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs != 0 )
threshold = total/maxinputs;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( it->second.satoshis < threshold )
//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 == txfee )
continue;
//char str[65]; fprintf(stderr,"check %s/v%d %.8f`\n",uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsCClibvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsCClibvout(cp,vintx,vout,cmpaddr)) >= 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -228,12 +531,36 @@ int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
} else fprintf(stderr,"nValue too small or already spent in mempool\n");
} //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);
}
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<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::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)
{
@@ -251,21 +578,6 @@ std::string Faucet2Fund(struct CCcontract_info *cp,uint64_t txfee,int64_t funds)
return("");
}
/*UniValue FaucetInfo()
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey faucetpk; struct CCcontract_info *cp,C; int64_t funding;
result.push_back(Pair("result","success"));
result.push_back(Pair("name","Faucet"));
cp = CCinit(&C,EVAL_FAUCET);
faucetpk = GetUnspendable(cp,0);
funding = AddFaucetInputs(cp,mtx,faucetpk,0,0);
sprintf(numstr,"%.8f",(double)funding/COIN);
result.push_back(Pair("funding",numstr));
return(result);
}*/
std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *params)
{
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -284,19 +596,19 @@ std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *para
return("");
cclibpk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
if ( (inputs= AddCClibInputs(cp,mtx,cclibpk,nValue+txfee,60)) > 0 )
if ( (inputs= AddCClibInputs(cp,mtx,cclibpk,nValue+txfee,60,cp->unspendableCCaddr,1)) > 0 )
{
if ( inputs > nValue )
CCchange = (inputs - nValue - txfee);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_FIRSTUSER,CCchange,cclibpk));
mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET2,CCchange,cclibpk));
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++)
{
tmpmtx = mtx;
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_FIRSTUSER << (uint8_t)'G' << j));
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_FAUCET2 << (uint8_t)'G' << j));
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
{
len >>= 1;
@@ -315,3 +627,79 @@ std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *para
} else fprintf(stderr,"cant find faucet inputs\n");
return("");
}
UniValue cclib_error(UniValue &result,const char *errorstr)
{
result.push_back(Pair("status","error"));
result.push_back(Pair("error",errorstr));
return(result);
}
uint256 juint256(cJSON *obj)
{
uint256 tmp; bits256 t = jbits256(obj,0);
memcpy(&tmp,&t,sizeof(tmp));
return(revuint256(tmp));
}
int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len)
{
char *hexstr;
if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == len*2 )
{
decode_hex(hash32,len,hexstr);
return(0);
} else return(-1);
}
#ifdef BUILD_ROGUE
#include "rogue_rpc.cpp"
#include "rogue/cursesd.c"
#include "rogue/vers.c"
#include "rogue/extern.c"
#include "rogue/armor.c"
#include "rogue/chase.c"
#include "rogue/command.c"
#include "rogue/daemon.c"
#include "rogue/daemons.c"
#include "rogue/fight.c"
#include "rogue/init.c"
#include "rogue/io.c"
#include "rogue/list.c"
#include "rogue/mach_dep.c"
#include "rogue/rogue.c"
#include "rogue/xcrypt.c"
#include "rogue/mdport.c"
#include "rogue/misc.c"
#include "rogue/monsters.c"
#include "rogue/move.c"
#include "rogue/new_level.c"
#include "rogue/options.c"
#include "rogue/pack.c"
#include "rogue/passages.c"
#include "rogue/potions.c"
#include "rogue/rings.c"
#include "rogue/rip.c"
#include "rogue/rooms.c"
#include "rogue/save.c"
#include "rogue/scrolls.c"
#include "rogue/state.c"
#include "rogue/sticks.c"
#include "rogue/things.c"
#include "rogue/weapons.c"
#include "rogue/wizard.c"
#elif BUILD_CUSTOMCC
#include "customcc.cpp"
#elif BUILD_GAMESCC
#include "rogue/cursesd.c"
#include "gamescc.cpp"
#else
#include "sudoku.cpp"
#include "musig.cpp"
#include "dilithium.c"
//#include "../secp256k1/src/modules/musig/example.c"
#endif

View File

@@ -62,6 +62,8 @@ Possible third iteration:
// start of consensus code
#define CC_MARKER_VALUE 10000
int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub, CPubKey destpub,int32_t v)
{
char destaddr[65],channeladdr[65],tokenschanneladdr[65];
@@ -92,26 +94,29 @@ 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<CPubKey> 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<uint8_t> vopret; uint8_t *script,e,f,tokenevalcode;
std::vector<CPubKey> pubkeys; std::vector<uint8_t> vOpretExtra;
std::vector<std::pair<uint8_t, vscript_t>> oprets;
std::vector<uint8_t> vopret,vOpretExtra; uint8_t *script,e,f,tokenevalcode;
std::vector<CPubKey> 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)
{
if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0);
vopret=vOpretExtra;
}
else GetOpReturnData(scriptPubKey, vopret);
if ( vopret.size() > 2 )
@@ -123,8 +128,8 @@ uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey, uint256 &tokenid, uint2
{
return(f);
}
} else fprintf(stderr,"script[0] %02x != EVAL_CHANNELS\n",script[0]);
} else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
} else LOGSTREAM("channelscc",CCLOG_DEBUG1, stream << "script[0] " << script[0] << " != EVAL_CHANNELS" << std::endl);
} else LOGSTREAM("channelscc",CCLOG_DEBUG1, stream << "not enough opret.[" << vopret.size() << "]" << std::endl);
return(0);
}
@@ -164,7 +169,7 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti
}
if ( inputs != outputs )
{
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
LOGSTREAM("channelscc",CCLOG_INFO, stream << "inputs " << inputs << " vs outputs " << outputs << std::endl);
return eval->Invalid("mismatched inputs != outputs");
}
else return (true);
@@ -180,7 +185,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,p1,param1; bool retval;
uint256 txid,hashblock,p3,param3,opentxid,tmp_txid,genhashchain,hashchain,tokenid;
uint8_t funcid,hash[32],hashdest[32];
uint8_t funcid,hash[32],hashdest[32]; char channeladdress[65],srcmarker[65],destmarker[65],destaddr[65],srcaddr[65],desttokensaddr[65],srctokensaddr[65];
int64_t p2,param2,payment;
CPubKey srcpub, destpub;
CTransaction channelOpenTx,channelCloseTx,prevTx;
@@ -199,9 +204,20 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
else
{
txid = tx.GetHash();
memcpy(hash,&txid,sizeof(hash));
memcpy(hash,&txid,sizeof(hash));
if ( (funcid = DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, tokenid, opentxid, srcpub, destpub, param1, param2, param3)) != 0)
{
if (myGetTransaction(opentxid,channelOpenTx,hashblock)== 0)
return eval->Invalid("invalid channelopen tx!");
else if ((numvouts=channelOpenTx.vout.size()) > 0 && (DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 'O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
GetCCaddress1of2(cp,channeladdress,srcpub,destpub);
GetCCaddress(cp,srcmarker,srcpub);
GetCCaddress(cp,destmarker,destpub);
Getscriptaddress(srcaddr,CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG);
Getscriptaddress(destaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG);
_GetCCaddress(srctokensaddr,EVAL_TOKENS,srcpub);
_GetCCaddress(desttokensaddr,EVAL_TOKENS,destpub);
switch ( funcid )
{
case 'O':
@@ -222,56 +238,53 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
//vout.3: normal output of payment amount to receiver pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret
if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelOpen is not yet confirmed(notarised)!");
if ( IsCCInput(channelOpenTx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[0],1,channeladdress,numpayments*payment)==0 )
return eval->Invalid("vout.0 is CC or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelopen!");
else if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelopen is not yet confirmed(notarised)!");
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelPayment!");
return eval->Invalid("vin.0 is normal for channelpayment!");
else if ( IsCCInput(tx.vin[1].scriptSig) == 0 )
return eval->Invalid("vin.1 is CC for channelPayment!");
return eval->Invalid("vin.1 is CC for channelpayment!");
else if ( IsCCInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("vin.2 is CC for channelPayment!");
else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition()==0 )
return eval->Invalid("vout.0 is CC for channelPayment!");
else if ( IsChannelsMarkervout(cp,tx,srcpub,1)==0 )
return eval->Invalid("vout.1 is CC for channelPayment (marker to srcPub)!");
else if ( IsChannelsMarkervout(cp,tx,destpub,2)==0 )
return eval->Invalid("vout.2 is CC for channelPayment (marker to dstPub)!");
else if ( tokenid!=zeroid && tx.vout[3].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.3 is CC for channelPayment!");
else if ( tokenid==zeroid && tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
return eval->Invalid("vout.3 is normal for channelPayment!");
else if ( tokenid!=zeroid && tx.vout[3].scriptPubKey!=MakeCC1vout(EVAL_TOKENS,tx.vout[3].nValue,destpub).scriptPubKey)
return eval->Invalid("payment funds do not go to receiver!");
else if ( tokenid==zeroid && tx.vout[3].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)
return eval->Invalid("payment funds do not go to receiver!");
return eval->Invalid("vin.2 is CC for channelpayment!");
else if ( ConstrainVout(tx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelpayment!");
else if ( ConstrainVout(tx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelpayment!");
else if ( tokenid!=zeroid && ConstrainVout(tx.vout[3],1,desttokensaddr,param2*payment)==0 )
return eval->Invalid("vout.3 is CC or invalid amount or invalid receiver for channelpayment!");
else if ( tokenid==zeroid && ConstrainVout(tx.vout[3],0,destaddr,param2*payment)==0 )
return eval->Invalid("vout.3 is normal or invalid amount or invalid receiver for channelpayment!");
else if ( param1 > CHANNELS_MAXPAYMENTS)
return eval->Invalid("too many payment increments!");
else
{
if (myGetTransaction(opentxid,channelOpenTx,hashblock) != 0)
{
endiancpy(hash, (uint8_t * ) & param3, 32);
for (i = 0; i < numpayments-param1; i++)
{
if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
endiancpy(hash, (uint8_t * ) & param3, 32);
for (i = 0; i < numpayments-param1; i++)
{
vcalc_sha256(0, hashdest, hash, 32);
memcpy(hash, hashdest, 32);
}
endiancpy((uint8_t*)&genhashchain,hashdest,32);
if (hashchain!=genhashchain)
return eval->Invalid("invalid secret for payment, does not reach final hashchain!");
else if (tx.vout[3].nValue != param2*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
vcalc_sha256(0, hashdest, hash, 32);
memcpy(hash, hashdest, 32);
}
endiancpy((uint8_t*)&genhashchain,hashdest,32);
if (hashchain!=genhashchain)
return eval->Invalid("invalid secret for payment, does not reach final hashchain!");
else if (tx.vout[3].nValue != param2*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
{
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
return eval->Invalid("invalid previous tx OP_RETURN data!");
else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey)
return eval->Invalid("invalid destination for sender marker!");
else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey)
return eval->Invalid("invalid destination for receiver marker!");
else if ( ConstrainVout(tx.vout[0],1,channeladdress,(p1-param2)*payment)==0 )
return eval->Invalid("vout.0 is CC or invalid CC change amount for channelpayment!");
else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE)
return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelpayment!");
else if (param1+param2!=p1)
return eval->Invalid("invalid payment depth!");
else if (tx.vout[3].nValue > prevTx.vout[0].nValue)
@@ -287,37 +300,37 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
//vout.1: CC vout marker to senders pubKey
//vout.2: CC vout marker to receiver pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0
if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelOpen is not yet confirmed(notarised)!");
//vout.n-1: opreturn - 'C' opentxid senderspubkey receiverspubkey numpayments payment 0
if ( IsCCInput(channelOpenTx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[0],1,channeladdress,numpayments*payment)==0 )
return eval->Invalid("vout.0 is CC or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelopen!");
else if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelopen is not yet confirmed(notarised)!");
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelClose!");
return eval->Invalid("vin.0 is normal for channelclose!");
else if ( IsCCInput(tx.vin[1].scriptSig) == 0 )
return eval->Invalid("vin.1 is CC for channelClose!");
return eval->Invalid("vin.1 is CC for channelclose!");
else if ( IsCCInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("vin.2 is CC for channelClose!");
else if ( IsChannelsvout(cp,tx,srcpub,destpub,0)==0 )
return eval->Invalid("vout.0 is CC for channelClose!");
else if ( IsChannelsMarkervout(cp,tx,srcpub,1)==0 )
return eval->Invalid("vout.1 is CC for channelClose (marker to srcPub)!");
else if ( IsChannelsMarkervout(cp,tx,destpub,2)==0 )
return eval->Invalid("vout.2 is CC for channelClose (marker to dstPub)!");
return eval->Invalid("vin.2 is CC for channelclose!");
else if ( ConstrainVout(tx.vout[0],1,channeladdress,0)==0 )
return eval->Invalid("vout.0 is CC for channelclose!");
else if ( ConstrainVout(tx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelclose!");
else if ( ConstrainVout(tx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelclose!");
else if ( param1 > CHANNELS_MAXPAYMENTS)
return eval->Invalid("too many payment increments!");
else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0)
return eval->Invalid("invalid open txid!");
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
else if (tx.vout[0].nValue != param1*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
{
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
return eval->Invalid("invalid previous tx OP_RETURN data!");
else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey)
return eval->Invalid("invalid destination for sender marker!");
else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey)
return eval->Invalid("invalid destination for receiver marker!");
else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE)
return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelclose!");
else if (tx.vout[0].nValue != prevTx.vout[0].nValue)
return eval->Invalid("invalid CC amount, amount must match funds in channel");
}
@@ -331,50 +344,40 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
//vout.2: normal output of CC input to senders pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'R' opentxid senderspubkey receiverspubkey numpayments payment closetxid
if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelOpen is not yet confirmed(notarised)!");
if ( IsCCInput(channelOpenTx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[0],1,channeladdress,numpayments*payment)==0 )
return eval->Invalid("vout.0 is CC or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelopen!");
else if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelopen is not yet confirmed(notarised)!");
else if (komodo_txnotarizedconfirmed(param3) == 0)
return eval->Invalid("channelClose is not yet confirmed(notarised)!");
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelRefund!");
return eval->Invalid("vin.0 is normal for channelrefund!");
else if ( IsCCInput(tx.vin[1].scriptSig) == 0 )
return eval->Invalid("vin.1 is CC for channelRefund!");
return eval->Invalid("vin.1 is CC for channelrefund!");
else if ( IsCCInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("vin.2 is CC for channelRefund!");
else if ( IsChannelsMarkervout(cp,tx,srcpub,0)==0 )
return eval->Invalid("vout.0 is CC for channelRefund (marker to srcPub)!");
else if ( IsChannelsMarkervout(cp,tx,destpub,1)==0 )
return eval->Invalid("vout.1 is CC for channelRefund (marker to dstPub)!");
else if ( tokenid!=zeroid && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.2 is CC for channelPayment!");
else if ( tokenid==zeroid && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 )
return eval->Invalid("vout.2 is normal for channelPayment!");
else if ( tokenid!=zeroid && tx.vout[2].scriptPubKey!=MakeCC1vout(EVAL_TOKENS,tx.vout[2].nValue,srcpub).scriptPubKey)
return eval->Invalid("payment funds do not go to sender!");
else if ( tokenid==zeroid && tx.vout[2].scriptPubKey!=CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG)
return eval->Invalid("payment funds do not go to sender!");
return eval->Invalid("vin.2 is CC for channelrefund!");
else if ( ConstrainVout(tx.vout[0],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.0 is CC marker to srcpub or invalid amount for channelrefund!");
else if ( ConstrainVout(tx.vout[1],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to destpub or invalid amount for channelrefund!");
else if ( tokenid!=zeroid && ConstrainVout(tx.vout[2],1,srctokensaddr,param1*payment)==0 )
return eval->Invalid("vout.2 is CC or invalid amount or invalid receiver for channelrefund!");
else if ( tokenid==zeroid && ConstrainVout(tx.vout[2],0,srcaddr,param1*payment)==0 )
return eval->Invalid("vout.2 is normal or invalid amount or invalid receiver for channelrefund!");
else if ( param1 > CHANNELS_MAXPAYMENTS)
return eval->Invalid("too many payment increments!");
else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0)
return eval->Invalid("invalid open txid!");
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
else if (myGetTransaction(param3,channelCloseTx,hashblock) == 0)
return eval->Invalid("invalid close txid!");
else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, param1, param2, param3) != 'C')
return eval->Invalid("invalid channelclose OP_RETURN data!");
else if (tmp_txid!=opentxid)
return eval->Invalid("invalid close tx, opentxid do not match on close and refund!");
else if (tx.vout[2].nValue != param1*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
{
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
return eval->Invalid("invalid previous tx OP_RETURN data!");
else if (tx.vout[0].scriptPubKey != prevTx.vout[1].scriptPubKey)
return eval->Invalid("invalid destination for sender marker!");
else if (tx.vout[1].scriptPubKey != prevTx.vout[2].scriptPubKey)
return eval->Invalid("invalid destination for receiver marker!");
else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE)
return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelrefund!");
else if (tx.vout[2].nValue != prevTx.vout[0].nValue)
return eval->Invalid("invalid amount, refund amount and funds in channel must match!");
}
@@ -387,8 +390,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
else return eval->Invalid("unexpected channels missing funcid");
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
if ( retval != 0 )
fprintf(stderr,"Channel tx validated\n");
else fprintf(stderr,"Channel tx invalid\n");
LOGSTREAM("channels",CCLOG_INFO, stream << "Channels tx validated" << std::endl);
else fprintf(stderr,"Channels tx invalid\n");
return(retval);
}
}
@@ -408,11 +411,11 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C
{
if (tokenid!=zeroid) GetTokensCCaddress1of2(cp,coinaddr,srcpub,destpub);
else GetCCaddress1of2(cp,coinaddr,srcpub,destpub);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
}
else
{
fprintf(stderr,"invalid channel open txid\n");
LOGSTREAM("channelscc",CCLOG_INFO, stream << "invalid channel open txid" << std::endl);
return 0;
}
if (srcpub==mypk) marker=1;
@@ -430,7 +433,7 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C
}
}
}
if (txid!=zeroid && myIsutxo_spentinmempool(txid,0) != 0)
if (txid!=zeroid && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,0) != 0)
{
txid=zeroid;
int32_t mindepth=CHANNELS_MAXPAYMENTS;
@@ -455,7 +458,7 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C
mtx.vin.push_back(CTxIn(txid,marker,CScript()));
Myprivkey(myprivkey);
if (tokenid!=zeroid) CCaddrTokens1of2set(cp,srcpub,destpub,coinaddr);
else CCaddr1of2set(cp,srcpub,destpub,coinaddr);
else CCaddr1of2set(cp,srcpub,destpub,myprivkey,coinaddr);
return totalinputs;
}
else return 0;
@@ -470,7 +473,7 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
if ( numpayments <= 0 || payment <= 0 || numpayments > CHANNELS_MAXPAYMENTS )
{
CCerror = strprintf("invalid ChannelOpen param numpayments.%d max.%d payment.%lld\n",numpayments,CHANNELS_MAXPAYMENTS,(long long)payment);
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
cp = CCinit(&C,EVAL_CHANNELS);
@@ -481,11 +484,11 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
funds = numpayments * payment;
if (tokenid!=zeroid)
{
amount=AddNormalinputs(mtx,mypk,3*txfee,5);
amount=AddNormalinputs(mtx,mypk,txfee+2*CC_MARKER_VALUE,5);
tokens=AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, funds, 64);
}
else amount=AddNormalinputs(mtx,mypk,funds+3*txfee,64);
if (amount+tokens >= funds+2*txfee)
else amount=AddNormalinputs(mtx,mypk,funds+txfee+2*CC_MARKER_VALUE,64);
if (amount+tokens >= funds+txfee+2*CC_MARKER_VALUE)
{
hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1);
endiancpy(hash,(uint8_t *)&hentropy,32);
@@ -497,13 +500,13 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
endiancpy((uint8_t *)&hashchain,hashdest,32);
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub));
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,destpub));
if (tokenid!=zeroid && tokens>funds) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,tokens-funds,mypk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',tokenid,zeroid,mypk,destpub,numpayments,payment,hashchain)));
}
CCerror = strprintf("error adding funds");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
@@ -523,7 +526,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{
CCerror = strprintf("invalid channel open txid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O')
@@ -531,23 +534,29 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
if (mypk != srcpub && mypk != destpub)
{
CCerror = strprintf("this is not our channel");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
else if (amount % payment != 0 || amount<payment)
{
CCerror = strprintf("invalid amount, not a magnitude of payment size");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
}
else
{
CCerror = strprintf("invalid channel open tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (AddNormalinputs(mtx,mypk,2*txfee,3) > 0)
if (komodo_txnotarizedconfirmed(opentxid)==false)
{
CCerror = strprintf("channelsopen tx not yet confirmed/notarized");
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if (AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,3) > 0)
{
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && (change=funds-amount)>=0)
{
@@ -559,12 +568,12 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
if (numpayments > prevdepth)
{
CCerror = strprintf("not enough funds in channel for that amount");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
} else if (numpayments == 0)
{
CCerror = strprintf("invalid amount");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (secret!=zeroid)
@@ -579,7 +588,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
if (gensecret!=hashchain)
{
CCerror = strprintf("invalid secret supplied");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
@@ -602,13 +611,13 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
else
{
CCerror = strprintf("invalid previous tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub));
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,srcpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,srcpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,destpub));
if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, amount, destpub));
else mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG));
return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', tokenid, opentxid, srcpub, destpub, prevdepth-numpayments, numpayments, secret)));
@@ -616,12 +625,12 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
else
{
CCerror = strprintf("error adding CC inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
CCerror = strprintf("error adding normal inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
@@ -642,40 +651,46 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid)
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{
CCerror = strprintf("invalid channel open txid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
{
CCerror = strprintf("invalid channel open tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (komodo_txnotarizedconfirmed(opentxid)==false)
{
CCerror = strprintf("channelsopen tx not yet confirmed/notarized");
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if (mypk != srcpub)
{
CCerror = strprintf("cannot close, you are not channel owner");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 )
if ( AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,3) > 0 )
{
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds>0)
{
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, funds, mypk, destpub));
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds, mypk, destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,destpub));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',tokenid,opentxid,mypk,destpub,funds/payment,payment,zeroid)));
}
else
{
CCerror = strprintf("error adding CC inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
CCerror = strprintf("error adding normal inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
@@ -696,48 +711,60 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
if (GetTransaction(closetxid,channelCloseTx,hashblock,false) == 0)
{
CCerror = strprintf("invalid channel close txid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,param1,param2,param3)!='C')
{
CCerror = strprintf("invalid channel close tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (komodo_txnotarizedconfirmed(closetxid)==false)
{
CCerror = strprintf("channelsclose tx not yet confirmed/notarized");
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if (txid!=opentxid)
{
CCerror = strprintf("open and close txid are not from same channel");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{
CCerror = strprintf("invalid channel open txid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (komodo_txnotarizedconfirmed(opentxid)==false)
{
CCerror = strprintf("channelsopen tx not yet confirmed/notarized");
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
{
CCerror = strprintf("invalid channel open tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (mypk != srcpub)
{
CCerror = strprintf("cannot refund, you are not the channel owner");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 )
if ( AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,3) > 0 )
{
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds>0)
{
if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 0 &&
DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, param1, param2, param3) != 0)
{
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,destpub));
if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,funds,mypk));
else mtx.vout.push_back(CTxOut(funds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',tokenid,opentxid,mypk,destpub,funds/payment,payment,closetxid)));
@@ -745,19 +772,19 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
else
{
CCerror = strprintf("previous tx is invalid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
else
{
CCerror = strprintf("error adding CC inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
CCerror = strprintf("error adding normal inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
@@ -770,7 +797,7 @@ UniValue ChannelsList()
cp = CCinit(&C,EVAL_CHANNELS);
mypk = pubkey2pk(Mypubkey());
GetCCaddress(cp,myCCaddr,mypk);
SetCCtxids(txids,myCCaddr);
SetCCtxids(txids,myCCaddr,true);
result.push_back(Pair("result","success"));
result.push_back(Pair("name","Channels List"));
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
@@ -778,7 +805,7 @@ UniValue ChannelsList()
txid = it->first.txhash;
vout = (int32_t)it->first.index;
nValue = (int64_t)it->second;
if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
if ( (vout == 1 || vout == 2) && nValue == CC_MARKER_VALUE && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O')
{
@@ -821,7 +848,7 @@ UniValue ChannelsInfo(uint256 channeltxid)
result.push_back(Pair("Denomination (satoshi)",i64tostr(param2)));
result.push_back(Pair("Amount (satoshi)",i64tostr(param1*param2)));
}
SetCCtxids(addressIndex,CCaddr);
SetCCtxids(addressIndex,CCaddr,true);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
if (GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )

88
src/cc/customcc.cpp Normal file
View File

@@ -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<uint8_t> 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");
}

45
src/cc/customcc.h Normal file
View File

@@ -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 *)"<parameter help>", 1, 1, '0', EVAL_CUSTOM }, \
{ (char *)MYCCNAME, (char *)"func1", (char *)"<no args>", 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); \
} \
}

0
src/cc/dapps/cJSON.c Executable file → Normal file
View File

1119
src/cc/dapps/dappstd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -236,7 +236,7 @@ void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep)
{
fclose(fp);
*lenp = 0;
printf("loadfile null size.(%s)\n",fname);
//printf("loadfile null size.(%s)\n",fname);
return(0);
}
if ( filesize > buflen )
@@ -312,22 +312,20 @@ uint64_t get_btcusd()
char *REFCOIN_CLI;
cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3)
cJSON *get_cli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3)
{
long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[256];
sprintf(fname,"/tmp/oraclefeed.%s",method);
if ( acname[0] != 0 )
{
if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 )
printf("unexpected: refcoin.(%s) acname.(%s)\n",refcoin,acname);
sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,arg3,fname);
if ( refcoin[0] == 0 )
printf("must supply reference coin\n");
sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s %s > %s 2>/tmp/oraclefeed.error\n",acname,method,arg0,arg1,arg2,arg3,fname);
}
else if ( strcmp(refcoin,"KMD") == 0 )
sprintf(cmdstr,"./komodo-cli %s %s %s %s %s > %s\n",method,arg0,arg1,arg2,arg3,fname);
else if ( REFCOIN_CLI != 0 && REFCOIN_CLI[0] != 0 )
{
sprintf(cmdstr,"%s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname);
printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr);
sprintf(cmdstr,"%s %s %s %s %s %s > %s 2>/tmp/oraclefeed.error\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname);
//printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr);
}
#ifdef TESTMODE
fprintf(stderr,"cmd: %s\n",cmdstr);
@@ -340,22 +338,24 @@ cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char
#ifdef TESTMODE
fprintf(stderr,"jsonstr.(%s)\n",jsonstr);
#endif // TESTMODE
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 )
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0)
*retstrp = jsonstr;
else free(jsonstr);
}
else if ( (jsonstr= filestr(&fsize,"/tmp/oraclefeed.error")) != 0 )
*retstrp = jsonstr;
return(retjson);
}
bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson)
bits256 broadcasttx(char *refcoin,char *acname,cJSON *hexjson)
{
char *hexstr,*retstr,str[65]; cJSON *retjson; bits256 txid;
memset(txid.bytes,0,sizeof(txid));
if ( (hexstr= jstr(hexjson,"hex")) != 0 )
{
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 )
{
//fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0));
if (strcmp("error",jstr(retjson,"result"))==0) printf("%s\n",jstr(retjson,"error"));
free_json(retjson);
}
else if ( retstr != 0 )
@@ -372,36 +372,14 @@ bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson)
return(txid);
}
bits256 sendtoaddress(char *refcoin,char *acname,char *destaddr,int64_t satoshis)
{
char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid;
memset(txid.bytes,0,sizeof(txid));
sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"","")) != 0 )
{
fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
if ( strlen(retstr) >= 64 )
{
retstr[64] = 0;
decode_hex(txid.bytes,32,retstr);
}
fprintf(stderr,"sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid));
free(retstr);
}
return(txid);
}
int32_t get_coinheight(char *refcoin,char *acname)
{
cJSON *retjson; char *retstr; int32_t height=0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 )
{
height = jint(retjson,"blocks");
free_json(retjson);
}
else if ( retstr != 0 )
{
@@ -416,7 +394,7 @@ bits256 get_coinblockhash(char *refcoin,char *acname,int32_t height)
cJSON *retjson; char *retstr,heightstr[32]; bits256 hash;
memset(hash.bytes,0,sizeof(hash));
sprintf(heightstr,"%d",height);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 )
{
fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0));
free_json(retjson);
@@ -437,7 +415,7 @@ bits256 get_coinmerkleroot(char *refcoin,char *acname,bits256 blockhash)
{
cJSON *retjson; char *retstr,str[65]; bits256 merkleroot;
memset(merkleroot.bytes,0,sizeof(merkleroot));
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 )
{
merkleroot = jbits256(retjson,"merkleroot");
//fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot));
@@ -472,10 +450,12 @@ int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *m
return(0);
}
cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr)
cJSON *get_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxidstr)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspending",bindtxidstr,refcoin,"","")) != 0 )
cJSON *retjson; char *retstr; char function[64];
if (type==0) sprintf(function,"%s","gatewayspendingwithdraws");
else if (type==1) sprintf(function,"%s","importgatewaypendingwithdraws");
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bindtxidstr,refcoin,"","")) != 0 )
{
//printf("pending.(%s)\n",jprint(retjson,0));
return(retjson);
@@ -488,10 +468,13 @@ cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr)
return(0);
}
cJSON *get_gatewaysprocessed(char *refcoin,char *acname,char *bindtxidstr)
cJSON *get_gatewaysprocessed(int8_t type,char *refcoin,char *acname,char *bindtxidstr)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysprocessed",bindtxidstr,refcoin,"","")) != 0 )
char function[64];
if (type==0) sprintf(function,"%s","gatewaysprocessed");
else if (type==1) sprintf(function,"%s","importgatewayprocessed");
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bindtxidstr,refcoin,"","")) != 0 )
{
//printf("pending.(%s)\n",jprint(retjson,0));
return(retjson);
@@ -507,7 +490,7 @@ cJSON *get_gatewaysprocessed(char *refcoin,char *acname,char *bindtxidstr)
cJSON *get_rawmempool(char *refcoin,char *acname)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 )
{
//printf("mempool.(%s)\n",jprint(retjson,0));
return(retjson);
@@ -526,14 +509,14 @@ cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 )
printf("warning: assumes %s has addressindex enabled\n",refcoin);
sprintf(jsonbuf,"{\\\"addresses\\\":[\\\"%s\\\"]}",coinaddr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 )
{
//printf("addressutxos.(%s)\n",jprint(retjson,0));
return(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr);
//fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr);
free(retstr);
}
return(0);
@@ -542,7 +525,7 @@ cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid)
{
cJSON *retjson; char *retstr,str[65];
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 )
{
return(retjson);
}
@@ -557,7 +540,7 @@ cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid)
int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* compare)
{
cJSON *retjson; char *retstr; int32_t res=0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","")) != 0 )
{
if (is_cJSON_True(jobj(retjson,compare)) != 0 ) res=1;
free_json(retjson);
@@ -576,7 +559,7 @@ void importaddress(char *refcoin,char *acname,char *depositaddr, char *label,int
cJSON *retjson; char *retstr; char rescanstr[10];
if (rescan) strcpy(rescanstr,"true");
else strcpy(rescanstr,"false");
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"importaddress",depositaddr,label,rescanstr,"")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"importaddress",depositaddr,label,rescanstr,"")) != 0 )
{
printf("importaddress.(%s)\n",jprint(retjson,0));
free_json(retjson);
@@ -588,19 +571,20 @@ void importaddress(char *refcoin,char *acname,char *depositaddr, char *label,int
}
}
void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys,char *bindtxidstr)
void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys)
{
cJSON *retjson; char *retstr,Mstr[10],tmp[128];
cJSON *retjson; char *retstr,Mstr[10],addr[64];
sprintf(Mstr,"%d",M);
sprintf(tmp,"\"%s\"",bindtxidstr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,tmp,"")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,"","")) != 0 )
{
fprintf(stderr,"unexpected addmultisigaddress json.(%s)\n",jprint(retjson,0));
free(retstr);
}
else if ( retstr != 0 )
{
sprintf(addr,"\"%s\"",retstr);
get_cli(refcoin,&retstr,acname,"importaddress",addr,"\"\"","false","");
printf("addmultisigaddress.(%s)\n",retstr);
free_json(retjson);
}
@@ -641,12 +625,11 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
else txfee = 10000;
if ( satoshis < txfee )
{
printf("createrawtx satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN);
printf("createrawtx: satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN);
return(0);
}
satoshis -= txfee;
sprintf(array,"\'[\"%s\"]\'",depositaddr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 )
{
//createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...}
if ( (vins= getinputarray(&total,retjson,satoshis)) != 0 )
@@ -667,7 +650,7 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
char *argB=malloc(sizeof(char) * (strlen(tmpB)+3));
sprintf(argA,"\'%s\'",tmpA);
sprintf(argB,"\'%s\'",tmpB);
if ( (retjson2= get_komodocli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 )
if ( (retjson2= get_cli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 )
{
printf("createrawtx: unexpected JSON2.(%s)\n",jprint(retjson2,0));
free_json(retjson2);
@@ -680,7 +663,7 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
free(argB);
}
else printf("not enough funds to create withdraw tx\n");
}
}
free_json(retjson);
}
else if ( retstr != 0 )
@@ -692,14 +675,14 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
return(txstr);
}
cJSON *addsignature(char *refcoin,char *acname,char *rawtx)
cJSON *addsignature(char *refcoin,char *acname,char *rawtx, int M)
{
char *retstr,*hexstr; cJSON *retjson;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 )
{
if ( is_cJSON_True(jobj(retjson,"complete")) != 0 )
return(retjson);
else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) )
else if ((hexstr=jstr(retjson,"hex"))!= 0 && strlen(hexstr) > strlen(rawtx) + (M*2) + 1)
{
jaddnum(retjson,"partialtx",1);
return(retjson);
@@ -714,32 +697,17 @@ cJSON *addsignature(char *refcoin,char *acname,char *rawtx)
return(0);
}
char *get_gatewaysmultisig(char *refcoin,char *acname,char *txidaddr,int32_t *K)
bits256 gatewayspartialsign(int8_t type,char *refcoin,char *acname,bits256 txid,char *hex)
{
char *retstr,*hexstr,*hex=0; cJSON *retjson;
if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",txidaddr,"","","")) != 0 )
char str[65],*retstr; cJSON *retjson; char function[64];
if (type==0) sprintf(function,"%s","gatewayspartialsign");
else if (type==1) sprintf(function,"%s","importgatewaypartialsign");
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bits256_str(str,txid),refcoin,hex,"")) != 0 )
{
if ((hexstr=jstr(retjson,"hex")) != 0 )
{
if (strlen(hexstr)>0) hex = clonestr(hexstr);
}
*K=jint(retjson,"number_of_signs");
free_json(retjson);
}
else if ( retstr != 0 )
{
printf("error parsing gatewaysmultisig.(%s)\n",retstr);
free(retstr);
}
return(hex);
}
bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex)
{
char str[65],*retstr; cJSON *retjson;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),refcoin,hex,"")) != 0 )
{
return(komodobroadcast(refcoin,acname,retjson));
if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson);
else printf("%s\n",jstr(retjson,"error"));
free(retjson);
return (txid);
}
else if ( retstr != 0 )
{
@@ -749,42 +717,55 @@ bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex)
return (zeroid);
}
void gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *coin,char *hex)
bits256 gatewayscompletesigning(int8_t type,char *refcoin,char *acname,bits256 withtxid,char *hex)
{
char str[65],str2[65],*retstr; cJSON *retjson;
printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid));
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayscompletesigning",bits256_str(str,withtxid),coin,hex,"")) != 0 )
char str[65],*retstr; cJSON *retjson; bits256 txid; char function[64];
if (type==0) sprintf(function,"%s","gatewayscompletesigning");
else if (type==1) sprintf(function,"%s","importgatewaycompletesigning");
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bits256_str(str,withtxid),refcoin,hex,"")) != 0 )
{
komodobroadcast(refcoin,acname,retjson);
free_json(retjson);
if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson);
else printf("%s\n",jstr(retjson,"error"));
free(retjson);
return (txid);
}
else if ( retstr != 0 )
{
printf("error parsing gatewayscompletesigning.(%s)\n",retstr);
free(retstr);
}
return (zeroid);
}
void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin)
bits256 gatewaysmarkdone(int8_t type,char *refcoin,char *acname,bits256 withtxid)
{
char str[65],str2[65],*retstr; cJSON *retjson;
printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid));
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),coin,"","")) != 0 )
char str[65],str2[65],*retstr; cJSON *retjson; bits256 txid; ; char function[64];
if (type==0) sprintf(function,"%s","gatewaysmarkdone");
else if (type==1) sprintf(function,"%s","importgatewaymarkdone");
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bits256_str(str,withtxid),refcoin,"","")) != 0 )
{
komodobroadcast(refcoin,acname,retjson);
free_json(retjson);
if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson);
else printf("%s\n",jstr(retjson,"error"));
free(retjson);
return (txid);
}
else if ( retstr != 0 )
{
printf("error parsing gatewaysmarkdone.(%s)\n",retstr);
free(retstr);
}
return (zeroid);
}
int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys)
int32_t get_gatewaysinfo(int8_t type,char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys)
{
char *oracle,*retstr,*name,*deposit,temp[128]; cJSON *retjson,*pubarray; int32_t n;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysinfo",bindtxidstr,"","","")) != 0 )
char *oracle,*retstr,*name,*deposit,temp[128]; cJSON *retjson,*pubarray; int32_t n; char function[64];
if (type==0) sprintf(function,"%s","gatewaysinfo");
else if (type==1) sprintf(function,"%s","importgatewayinfo");
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bindtxidstr,"","","")) != 0 )
{
if ( (oracle= jstr(retjson,"oracletxid")) != 0 && strcmp(oracle,oraclestr) == 0 && (deposit= jstr(retjson,"deposit")) != 0 )
{
@@ -809,7 +790,6 @@ int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *M
strcat(*pubkeys,temp);
}
}
else printf("%s != %s\n",oracle,oraclestr);
free_json(retjson);
}
else if ( retstr != 0 )
@@ -882,57 +862,11 @@ int32_t markerexists(char *refcoin,char *acname,char *coinaddr)
free_json(array);
}
}
fprintf(stderr,"Num=%d\n",num);
return(num);
}
int32_t markerfromthisnodeorunconfirmed(char *refcoin,char *acname,char *coinaddr)
{
cJSON *array,*item,*rawtx,*vins,*vin; bits256 txid,tmptxid; int32_t i,n,m,num=0; char *retstr;
if ( (array= get_addressutxos(refcoin,acname,coinaddr)) != 0 )
{
n=cJSON_GetArraySize(array);
for (i=0; i<n; i++)
{
if ((item=jitem(array,i))!=0 && (bits256_nonz(tmptxid=jbits256(item,"txid")))!=0 && (rawtx=get_rawtransaction(refcoin,acname,tmptxid))!=0 && (vins=jarray(&m,rawtx,"vin"))!=0)
{
for (int j=0;j<m;j++)
{
if ((vin=jitem(vins,j))!=0 && validateaddress(refcoin,acname,jstr(vin,"address"),"ismine")!=0)
{
num=1;
break;
}
}
}
if (num==1) break;
}
free_json(array);
}
else return(-1);
if ( num == 0 )
{
if ( (array= get_rawmempool(refcoin,acname)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) != 0 )
{
for (i=0; i<n; i++)
{
txid = jbits256i(array,i);
if ( tx_has_voutaddress(refcoin,acname,txid,coinaddr) > 0 )
{
num = 1;
break;
}
}
}
free_json(array);
} else return(-1);
}
return(num);
}
void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N)
void update_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N)
{
// check queue to prevent duplicate
// check KMD chain and mempool for txidaddr
@@ -941,9 +875,11 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t
/// if enough sigs, sendrawtransaction and when it confirms spend marker (txid.2)
/// if not enough sigs, post partially signed to acname with marker2
// monitor marker2, for the partially signed withdraws
cJSON *retjson,*pending,*item,*clijson; char str[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,origtxid; int64_t satoshis;
cJSON *retjson,*pending,*item,*clijson; char str[65],str1[65],str2[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr;
int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,withdrawtxid,lasttxid,completetxid; int64_t satoshis;
memset(&zeroid,0,sizeof(zeroid));
if ( (retjson= get_gatewayspending("KMD",acname,bindtxidstr)) != 0 )
if ( (retjson= get_gatewayspending(type,refcoin,acname,bindtxidstr)) != 0 )
{
if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 )
{
@@ -954,86 +890,95 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t
if ( processed != 0 ) // avoid out of utxo conditions
break;
item = jitem(pending,i);
origtxid = jbits256(item,"txid");
withdrawtxid = jbits256(item,"withdrawtxid");
//process item.0 {"txid":"10ec8f4dad6903df6b249b361b879ac77b0617caad7629b97e10f29fa7e99a9b","txidaddr":"RMbite4TGugVmkGmu76ytPHDEQZQGSUjxz","withdrawaddr":"RNJmgYaFF5DbnrNUX6pMYz9rcnDKC2tuAc","amount":"1.00000000","depositaddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","signeraddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj"}
if ( (txidaddr= jstr(item,"txidaddr")) != 0 && (withdrawaddr= jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 )
if ( (txidaddr=jstr(item,"withdrawtxidaddr"))!= 0 && (withdrawaddr=jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 )
{
if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0 && markerfromthisnodeorunconfirmed("KMD",acname,txidaddr) == 0)
if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0)
{
if ( strcmp(depositaddr,signeraddr) == 0 )
{
rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis);
if ( rawtx != 0 )
{
if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0)
if ( (clijson=addsignature(refcoin,"",rawtx,M)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0)
{
gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex"));
fprintf(stderr,"withdraw %.8f %s to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,withdrawaddr);
txid=gatewayscompletesigning(type,refcoin,acname,withdrawtxid,jstr(clijson,"hex"));
if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s 1of1\n",bits256_str(str,withdrawtxid));
else fprintf(stderr,"### SIGNING error broadcasting tx on %s",acname);
free_json(clijson);
}
processed++;
processed++;
}
free(rawtx);
} else fprintf(stderr,"couldnt create rawtx\n");
}
else
{
if ( (rawtx= get_gatewaysmultisig(refcoin,acname,txidaddr,&K)) == 0)
lasttxid = jbits256(item,"last_txid");
if ( lasttxid.txid==withdrawtxid.txid)
{
rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis);
}
if ( rawtx != 0 )
else rawtx=jstr(item,"hex");
K=jint(item,"number_of_signs");
if ( rawtx!=0 && (clijson=addsignature(refcoin,"",rawtx,M)) != 0 )
{
if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 )
{
if ( is_cJSON_True(jobj(clijson,"complete")) != 0 )
{
gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex"));
fprintf(stderr,"withdraw %.8f %s M.%d N.%d to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,M,N,withdrawaddr);
}
else if ( jint(clijson,"partialtx") != 0 )
{
txid=gatewayspartialsign(refcoin,acname,origtxid,jstr(clijson,"hex"));
fprintf(stderr,"%d sign(s) %dof%d partialtx %s sent\n",K+1,M,N,bits256_str(str,txid));
}
free_json(clijson);
if ( is_cJSON_True(jobj(clijson,"complete")) != 0 )
{
txid=gatewayscompletesigning(type,refcoin,acname,lasttxid,jstr(clijson,"hex"));
if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %dof%d\n",bits256_str(str,withdrawtxid),K+1,N);
else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname);
}
else if ( jint(clijson,"partialtx") != 0 )
{
txid=gatewayspartialsign(type,refcoin,acname,lasttxid,jstr(clijson,"hex"));
if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %d/%dof%d\n",bits256_str(str,withdrawtxid),K+1,M,N);
else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname);
}
free_json(clijson);
processed++;
free(rawtx);
} else fprintf(stderr,"couldnt create msig rawtx\n");
}
}
if ( lasttxid.txid==withdrawtxid.txid) free(rawtx);
}
}
}
}
}
}
}
free_json(retjson);
}
if ( (retjson= get_gatewaysprocessed("KMD",acname,bindtxidstr)) != 0 )
if ( (retjson= get_gatewaysprocessed(type,refcoin,acname,bindtxidstr)) != 0 )
{
if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 )
{
if ( (pending=jarray(&n,retjson,"processed")) != 0 )
if ((pending=jarray(&n,retjson,"processed")) != 0)
{
for (i=0; i<n; i++)
{
item = jitem(pending,i);
origtxid = jbits256(item,"txid");
completetxid = jbits256(item,"completesigningtxid");
txidaddr = jstr(item,"withdrawtxidaddr");
withdrawtxid= jbits256(item,"withdrawtxid");
double amount = jdouble(item,"amount");
if (validateaddress(refcoin,"",txidaddr,"iswatchonly")==0 && validateaddress(refcoin,"",txidaddr,"ismine")==0)
importaddress(refcoin,"",txidaddr,jstr(item,"txid"),0);
if ( txidaddr != 0 && markerexists(refcoin,"",txidaddr)==0)
importaddress(refcoin,"",txidaddr,jstr(item,"withdrawtxid"),0);
if (is_cJSON_True(jobj(item,"confirmed_or_notarized")) && txidaddr != 0 && markerexists(refcoin,"",txidaddr)==0)
{
cointxid = komodobroadcast(refcoin,"",item);
cointxid = broadcasttx(refcoin,"",item);
if ( bits256_nonz(cointxid) != 0 )
{
withdrawaddr = jstr(item,"withdrawaddr");
fprintf(stderr,"withdraw %.8f %s to %s - %s broadcasted on %s\n",(double)satoshis/SATOSHIDEN,refcoin,withdrawaddr,bits256_str(str,cointxid),refcoin);
gatewaysmarkdone("KMD",acname,origtxid,refcoin);
withdrawaddr = jstr(item,"withdrawaddr");
fprintf(stderr,"### WITHDRAW %.8f %s sent to %s\n",amount,refcoin,withdrawaddr);
txid=gatewaysmarkdone(type,refcoin,acname,completetxid);
if (txid.txid!=zeroid.txid) fprintf(stderr,"### MARKDONE withdraw %s\n",bits256_str(str,withdrawtxid));
else fprintf(stderr,"### MARKDONE error broadcasting tx on %s\n",refcoin);
}
else fprintf(stderr,"### WITHDRAW error broadcasting tx on %s\n",refcoin);
}
}
}
}
free_json(retjson);
}
}
@@ -1094,7 +1039,7 @@ oraclesdata 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff 034
int32_t main(int32_t argc,char **argv)
{
cJSON *clijson,*clijson2,*regjson,*item; int32_t acheight,i,retval,M,N,n,height,prevheight = 0; char *pubkeys,*format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,depositaddr[64],hexstr[4096],refcoin[64]; uint64_t price; bits256 txid;
cJSON *clijson,*clijson2,*regjson,*item; int32_t type,i,retval,M,N,n,height,prevheight = 0; char *pubkeys,*format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,depositaddr[64],hexstr[4096],refcoin[64]; uint64_t price; bits256 txid;
if ( argc < 6 )
{
printf("usage: oraclefeed $ACNAME $ORACLETXID $MYPUBKEY $FORMAT $BINDTXID [refcoin_cli]\n");
@@ -1114,13 +1059,12 @@ int32_t main(int32_t argc,char **argv)
printf("only formats of L and Ihh are supported now\n");
return(-1);
}
M = N = 1;
acheight = 0;
M = N = 0;
refcoin[0] = 0;
while ( 1 )
{
retstr = 0;
if ( (refcoin[0] == 0 || prevheight < (get_coinheight(refcoin,"") - 10)) && (clijson= get_komodocli("KMD",&retstr,acname,"oraclesinfo",oraclestr,"","","")) != 0 )
if ( (refcoin[0] == 0 || prevheight < (get_coinheight(refcoin,"") - 10)) && (clijson= get_cli(refcoin,&retstr,acname,"oraclesinfo",oraclestr,"","","")) != 0 )
{
if ( refcoin[0] == 0 && jstr(clijson,"name") != 0 )
{
@@ -1131,15 +1075,17 @@ int32_t main(int32_t argc,char **argv)
exit(0);
}
pubkeys=0;
if ( get_gatewaysinfo("KMD",acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) < 0 )
if ( get_gatewaysinfo(0,refcoin,acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) == 0 ) type=0;
else if ( get_gatewaysinfo(1,refcoin,acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) == 0 ) type=1;
else
{
printf("cant find bindtxid.(%s)\n",bindtxidstr);
exit(0);
}
if (validateaddress(refcoin,"",depositaddr,"iswatchonly")==0 && validateaddress(refcoin,"",depositaddr,"ismine")==0)
{
if (M==N==1) importaddress(refcoin,"",depositaddr,bindtxidstr,0);
else addmultisigaddress(refcoin,"",M,pubkeys,bindtxidstr);
if (M==1 && N==1) importaddress(refcoin,"",depositaddr,bindtxidstr,0);
else addmultisigaddress(refcoin,"",M,pubkeys);
}
if (pubkeys!=0) free(pubkeys);
printf("set refcoin %s <- %s [%s] M.%d of N.%d\n",depositaddr,refcoin,REFCOIN_CLI,M,N);
@@ -1153,16 +1099,14 @@ int32_t main(int32_t argc,char **argv)
{
if ( (height= get_oracledata(refcoin,"",prevheight,hexstr,sizeof(hexstr),"Ihh")) != 0 )
{
if ( (clijson2= get_komodocli("KMD",&retstr2,acname,"oraclesdata",oraclestr,hexstr,"","")) != 0 )
if ( (clijson2= get_cli(refcoin,&retstr2,acname,"oraclesdata",oraclestr,hexstr,"","")) != 0 )
{
//printf("data.(%s)\n",jprint(clijson2,0));
txid = komodobroadcast("KMD",acname,clijson2);
txid = broadcasttx(refcoin,acname,clijson2);
if ( bits256_nonz(txid) != 0 )
{
prevheight = height;
acheight = get_coinheight(refcoin,"");
printf("%s ht.%d <- %s\n",refcoin,height,hexstr);
update_gatewayspending(refcoin,acname,bindtxidstr,M,N);
update_gatewayspending(type,refcoin,acname,bindtxidstr,M,N);
}
free_json(clijson2);
}

View File

@@ -700,23 +700,6 @@ int32_t z_getnewaddress(char *coinaddr,char *refcoin,char *acname,char *typestr)
return(retval);
}
int32_t z_getnewaddress(char *coinaddr,char *refcoin,char *acname,char *typestr)
{
cJSON *retjson; char *retstr; int64_t amount=0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getnewaddress",typestr,"","","")) != 0 )
{
fprintf(stderr,"z_getnewaddress.(%s) %s returned json!\n",refcoin,acname);
free_json(retjson);
return(-1);
}
else if ( retstr != 0 )
{
strcpy(coinaddr,retstr);
free(retstr);
return(0);
}
}
int64_t find_onetime_amount(char *coinstr,char *coinaddr)
{
cJSON *array,*item; int32_t i,n; char *addr; int64_t amount = 0;
@@ -812,53 +795,8 @@ int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr
{
cJSON *retjson; char *retstr,addr[128],*opstr; int32_t retval = -1;
sprintf(addr,"[\\\"ANY_SPROUT\\\"]");
//printf("z_sendmany from.(%s) -> %s\n",addr,destaddr);
if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_mergetoaddress",addr,destaddr,"","")) != 0 )
{
/*{
"remainingUTXOs": 0,
"remainingTransparentValue": 0.00000000,
"remainingNotes": 222,
"remainingShieldedValue": 5413.39093055,
"mergingUTXOs": 0,
"mergingTransparentValue": 0.00000000,
"mergingNotes": 10,
"mergingShieldedValue": 822.47447172,
"opid": "opid-f28f6261-4120-436c-aca5-859870a40a70"
}*/
if ( (opstr= jstr(retjson,"opid")) != 0 )
strcpy(opidstr,opstr);
retval = jint(retjson,"remainingNotes");
fprintf(stderr,"%s\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"z_mergetoaddress.(%s) -> opid.(%s)\n",coinstr,retstr);
strcpy(opidstr,retstr);
free(retstr);
}
return(retval);
}
int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr)
{
cJSON *retjson; char *retstr,addr[128],*opstr; int32_t retval = -1;
sprintf(addr,"[\\\"ANY_SPROUT\\\"]");
//printf("z_sendmany from.(%s) -> %s\n",addr,destaddr);
if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_mergetoaddress",addr,destaddr,"","")) != 0 )
{
/*{
"remainingUTXOs": 0,
"remainingTransparentValue": 0.00000000,
"remainingNotes": 222,
"remainingShieldedValue": 5413.39093055,
"mergingUTXOs": 0,
"mergingTransparentValue": 0.00000000,
"mergingNotes": 10,
"mergingShieldedValue": 822.47447172,
"opid": "opid-f28f6261-4120-436c-aca5-859870a40a70"
}*/
if ( (opstr= jstr(retjson,"opid")) != 0 )
strcpy(opidstr,opstr);
retval = jint(retjson,"remainingNotes");

View File

@@ -264,12 +264,12 @@ int32_t dicefinish_utxosget(int32_t &total,struct dicefinish_utxo *utxos,int32_t
int32_t n = 0; int64_t threshold = 2 * 10000;
total = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,false);
{
LOCK(mempool.cs);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
if ( myIsutxo_spentinmempool(it->first.txhash,(int32_t)it->first.index) == 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,it->first.txhash,(int32_t)it->first.index) == 0 )
{
if ( it->second.satoshis < threshold || it->second.satoshis > 10*threshold )
continue;
@@ -302,7 +302,7 @@ int32_t dice_betspent(char *debugstr,uint256 bettxid)
}
{
//LOCK(mempool.cs);
if ( myIsutxo_spentinmempool(bettxid,0) != 0 || myIsutxo_spentinmempool(bettxid,1) != 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,bettxid,0) != 0 || myIsutxo_spentinmempool(ignoretxid,ignorevin,bettxid,1) != 0 )
{
fprintf(stderr,"%s bettxid.%s already spent in mempool\n",debugstr,bettxid.GetHex().c_str());
return(-1);
@@ -1051,10 +1051,12 @@ uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
char coinaddr[64],str[65]; uint64_t threshold,sbits,nValue,totalinputs = 0; uint256 txid,hash,proof,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total / maxinputs;
else threshold = total / 64;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -1067,7 +1069,7 @@ uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
break;
if ( j != mtx.vin.size() )
continue;
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
{
@@ -1106,7 +1108,7 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit
fundingPubKey = tx.vout[1].scriptPubKey;
} else return(0);
GetCCaddress(cp,coinaddr,dicepk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
entropyval = 0;
int loops = 0;
int numtxs = unspentOutputs.size()/2;
@@ -1176,7 +1178,7 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit
continue;
}
}
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
entropytxid = txid;
entropyval = tx.vout[0].nValue;
@@ -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)
@@ -1220,7 +1225,7 @@ bool DicePlanExists(CScript &fundingPubKey,uint256 &fundingtxid,struct CCcontrac
char CCaddr[64]; uint64_t sbits=0; uint256 txid,hashBlock; CTransaction tx;
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
GetCCaddress(cp,CCaddr,dicepk);
SetCCtxids(txids,cp->normaladdr);
SetCCtxids(txids,cp->normaladdr,false);
if ( fundingtxid != zeroid ) // avoid scan unless creating new funding plan
{
//fprintf(stderr,"check fundingtxid\n");
@@ -1316,7 +1321,7 @@ UniValue DiceList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits; int64_t minbet,maxbet,maxodds,timeoutblocks; char str[65];
cp = CCinit(&C,EVAL_DICE);
SetCCtxids(addressIndex,cp->normaladdr);
SetCCtxids(addressIndex,cp->normaladdr,false);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
@@ -1447,7 +1452,7 @@ std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet
CCerror = "Your dealer is broke, find a new casino.";
return("");
}
if ( myIsutxo_spentinmempool(entropytxid,0) != 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,entropytxid,0) != 0 )
{
CCerror = "entropy txid is spent";
return("");
@@ -1657,7 +1662,7 @@ void *dealer0_loop(void *_arg)
if ( (cp= Diceinit(fundingPubKey,dealer0_fundingtxid,&C,planstr,txfee,mypk,dicepk,refsbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
{
fprintf(stderr,"error initializing dealer0_loop\n");
exit(-1);
StartShutdown();
}
fprintf(stderr,"dealer0 node running\n");
height = lastht = 0;
@@ -1769,7 +1774,7 @@ double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettx
return(0.);
}
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;

3682
src/cc/dilithium.c Normal file

File diff suppressed because one or more lines are too long

475
src/cc/dilithium.h Normal file
View File

@@ -0,0 +1,475 @@
#include <stdint.h>
/*
#ifndef CPUCYCLES_H
#define CPUCYCLES_H
#ifdef DBENCH
#define DBENCH_START() uint64_t time = cpucycles_start()
#define DBENCH_STOP(t) t += cpucycles_stop() - time - timing_overhead
#else
#define DBENCH_START()
#define DBENCH_STOP(t)
#endif
#ifdef USE_RDPMC // Needs echo 2 > /sys/devices/cpu/rdpmc
#ifdef SERIALIZE_RDC
static inline uint64_t cpucycles_start(void) {
const uint32_t ecx = (1U << 30) + 1;
uint64_t result;
asm volatile("cpuid; movl %1,%%ecx; rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax"
: "=&a" (result) : "r" (ecx) : "rbx", "rcx", "rdx");
return result;
}
static inline uint64_t cpucycles_stop(void) {
const uint32_t ecx = (1U << 30) + 1;
uint64_t result, dummy;
asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax; movq %%rax,%0; cpuid"
: "=&r" (result), "=c" (dummy) : "c" (ecx) : "rax", "rbx", "rdx");
return result;
}
#else
static inline uint64_t cpucycles_start(void) {
const uint32_t ecx = (1U << 30) + 1;
uint64_t result;
asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax"
: "=a" (result) : "c" (ecx) : "rdx");
return result;
}
static inline uint64_t cpucycles_stop(void) {
const uint32_t ecx = (1U << 30) + 1;
uint64_t result;
asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax"
: "=a" (result) : "c" (ecx) : "rdx");
return result;
}
#endif
#else
#ifdef SERIALIZE_RDC
static inline uint64_t cpucycles_start(void) {
uint64_t result;
asm volatile("cpuid; rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax"
: "=a" (result) : : "%rbx", "%rcx", "%rdx");
return result;
}
static inline uint64_t cpucycles_stop(void) {
uint64_t result;
asm volatile("rdtscp; shlq $32,%%rdx; orq %%rdx,%%rax; mov %%rax,%0; cpuid"
: "=r" (result) : : "%rax", "%rbx", "%rcx", "%rdx");
return result;
}
#else
static inline uint64_t cpucycles_start(void) {
uint64_t result;
asm volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax"
: "=a" (result) : : "%rdx");
return result;
}
static inline uint64_t cpucycles_stop(void) {
uint64_t result;
asm volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax"
: "=a" (result) : : "%rdx");
return result;
}
#endif
#endif
int64_t cpucycles_overhead(void);
#endif*/
#ifndef FIPS202_H
#define FIPS202_H
#define SHAKE128_RATE 168
#define SHAKE256_RATE 136
void shake128_absorb(uint64_t *s,
const uint8_t *input,
int32_t inlen);
void shake128_squeezeblocks(uint8_t *output,
int32_t nblocks,
uint64_t *s);
void shake256_absorb(uint64_t *s,
const uint8_t *input,
int32_t inlen);
void shake256_squeezeblocks(uint8_t *output,
int32_t nblocks,
uint64_t *s);
void shake128(uint8_t *output,
int32_t outlen,
const uint8_t *input,
int32_t inlen);
void shake256(uint8_t *output,
int32_t outlen,
const uint8_t *input,
int32_t inlen);
#endif
#ifndef PARAMS_H
#define PARAMS_H
#ifndef MODE
#define MODE 3
#endif
#define SEEDBYTES 32U
#define CRHBYTES 48U
#define N 256U
#define Q 8380417U
#define QBITS 23U
#define ROOT_OF_UNITY 1753U
#define D 14U
#define GAMMA1 ((Q - 1U)/16U)
#define GAMMA2 (GAMMA1/2U)
#define ALPHA (2U*GAMMA2)
#if MODE == 0
#define K 3U
#define L 2U
#define ETA 7U
#define SETABITS 4U
#define BETA 375U
#define OMEGA 64U
#elif MODE == 1
#define K 4U
#define L 3U
#define ETA 6U
#define SETABITS 4U
#define BETA 325U
#define OMEGA 80U
#elif MODE == 2
#define K 5U
#define L 4U
#define ETA 5U
#define SETABITS 4U
#define BETA 275U
#define OMEGA 96U
#elif MODE == 3
#define K 6U
#define L 5U
#define ETA 3U
#define SETABITS 3U
#define BETA 175U
#define OMEGA 120U
#endif
#define POL_SIZE_PACKED ((N*QBITS)/8)
#define POLT1_SIZE_PACKED ((N*(QBITS - D))/8)
#define POLT0_SIZE_PACKED ((N*D)/8)
#define POLETA_SIZE_PACKED ((N*SETABITS)/8)
#define POLZ_SIZE_PACKED ((N*(QBITS - 3))/8)
#define POLW1_SIZE_PACKED ((N*4)/8)
#define POLVECK_SIZE_PACKED (K*POL_SIZE_PACKED)
#define POLVECL_SIZE_PACKED (L*POL_SIZE_PACKED)
#define CRYPTO_PUBLICKEYBYTES (SEEDBYTES + K*POLT1_SIZE_PACKED)
#define CRYPTO_SECRETKEYBYTES (2*SEEDBYTES + (L + K)*POLETA_SIZE_PACKED + CRHBYTES + K*POLT0_SIZE_PACKED)
#define CRYPTO_BYTES (L*POLZ_SIZE_PACKED + (OMEGA + K) + (N/8 + 8))
#endif
#ifndef POLY_H
#define POLY_H
//#include <stdint.h>
//#include "params.h"
//#include "fips202.h"
typedef struct {
uint32_t coeffs[N];
} poly __attribute__((aligned(32)));
void poly_reduce(poly *a);
void poly_csubq(poly *a);
void poly_freeze(poly *a);
void poly_add(poly *c, const poly *a, const poly *b);
void poly_sub(poly *c, const poly *a, const poly *b);
void poly_neg(poly *a);
void poly_shiftl(poly *a, uint32_t k);
void poly_ntt(poly *a);
void poly_invntt_montgomery(poly *a);
void poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b);
void poly_power2round(poly *a1, poly *a0, const poly *a);
void poly_decompose(poly *a1, poly *a0, const poly *a);
uint32_t poly_make_hint(poly *h, const poly *a, const poly *b);
void poly_use_hint(poly *a, const poly *b, const poly *h);
int poly_chknorm(const poly *a, uint32_t B);
void poly_uniform(poly *a, const uint8_t *buf);
void poly_uniform_eta(poly *a,
const uint8_t seed[SEEDBYTES],
uint8_t nonce);
void poly_uniform_gamma1m1(poly *a,
const uint8_t seed[SEEDBYTES + CRHBYTES],
uint16_t nonce);
void polyeta_pack(uint8_t *r, const poly *a);
void polyeta_unpack(poly *r, const uint8_t *a);
void polyt1_pack(uint8_t *r, const poly *a);
void polyt1_unpack(poly *r, const uint8_t *a);
void polyt0_pack(uint8_t *r, const poly *a);
void polyt0_unpack(poly *r, const uint8_t *a);
void polyz_pack(uint8_t *r, const poly *a);
void polyz_unpack(poly *r, const uint8_t *a);
void polyw1_pack(uint8_t *r, const poly *a);
#endif
#ifndef POLYVEC_H
#define POLYVEC_H
//#include <stdint.h>
//#include "params.h"
//#include "poly.h"
/* Vectors of polynomials of length L */
typedef struct {
poly vec[L];
} polyvecl;
void polyvecl_freeze(polyvecl *v);
void polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v);
void polyvecl_ntt(polyvecl *v);
void polyvecl_pointwise_acc_invmontgomery(poly *w,
const polyvecl *u,
const polyvecl *v);
int polyvecl_chknorm(const polyvecl *v, uint32_t B);
/* Vectors of polynomials of length K */
typedef struct {
poly vec[K];
} polyveck;
void polyveck_reduce(polyveck *v);
void polyveck_csubq(polyveck *v);
void polyveck_freeze(polyveck *v);
void polyveck_add(polyveck *w, const polyveck *u, const polyveck *v);
void polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v);
void polyveck_shiftl(polyveck *v, uint32_t k);
void polyveck_ntt(polyveck *v);
void polyveck_invntt_montgomery(polyveck *v);
int polyveck_chknorm(const polyveck *v, uint32_t B);
void polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v);
void polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v);
uint32_t polyveck_make_hint(polyveck *h,
const polyveck *u,
const polyveck *v);
void polyveck_use_hint(polyveck *w, const polyveck *v, const polyveck *h);
#endif
#ifndef NTT_H
#define NTT_H
//#include <stdint.h>
//#include "params.h"
void ntt(uint32_t p[N]);
void invntt_frominvmont(uint32_t p[N]);
#endif
#ifndef PACKING_H
#define PACKING_H
//#include "params.h"
//#include "polyvec.h"
void pack_pk(uint8_t pk[CRYPTO_PUBLICKEYBYTES],
const uint8_t rho[SEEDBYTES], const polyveck *t1);
void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES],
const uint8_t rho[SEEDBYTES],
const uint8_t key[SEEDBYTES],
const uint8_t tr[CRHBYTES],
const polyvecl *s1,
const polyveck *s2,
const polyveck *t0);
void pack_sig(uint8_t sig[CRYPTO_BYTES],
const polyvecl *z, const polyveck *h, const poly *c);
void unpack_pk(uint8_t rho[SEEDBYTES], polyveck *t1,
const uint8_t pk[CRYPTO_PUBLICKEYBYTES]);
void unpack_sk(uint8_t rho[SEEDBYTES],
uint8_t key[SEEDBYTES],
uint8_t tr[CRHBYTES],
polyvecl *s1,
polyveck *s2,
polyveck *t0,
const uint8_t sk[CRYPTO_SECRETKEYBYTES]);
int unpack_sig(polyvecl *z, polyveck *h, poly *c,
const uint8_t sig[CRYPTO_BYTES]);
#endif
#ifndef REDUCE_H
#define REDUCE_H
//#include <stdint.h>
#define MONT 4193792U // 2^32 % Q
#define QINV 4236238847U // -q^(-1) mod 2^32
/* a <= Q*2^32 => r < 2*Q */
uint32_t montgomery_reduce(uint64_t a);
/* r < 2*Q */
uint32_t reduce32(uint32_t a);
/* a < 2*Q => r < Q */
uint32_t csubq(uint32_t a);
/* r < Q */
uint32_t freeze(uint32_t a);
#endif
#ifndef ROUNDING_H
#define ROUNDING_H
//#include <stdint.h>
uint32_t power2round(const uint32_t a, uint32_t *a0);
uint32_t decompose(uint32_t a, uint32_t *a0);
uint32_t make_hint(const uint32_t a, const uint32_t b);
uint32_t use_hint(const uint32_t a, const uint32_t hint);
#endif
#ifndef SIGN_H
#define SIGN_H
//#include "params.h"
//#include "poly.h"
//#include "polyvec.h"
void expand_mat(polyvecl mat[K], const uint8_t rho[SEEDBYTES]);
void challenge(poly *c, const uint8_t mu[CRHBYTES],
const polyveck *w1);
int crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
int crypto_sign(uint8_t *sm, int32_t *smlen,
const uint8_t *msg, int32_t len,
const uint8_t *sk);
int crypto_sign_open(uint8_t *m, int32_t *mlen,
const uint8_t *sm, int32_t smlen,
const uint8_t *pk);
#endif
#ifndef API_H
#define API_H
#ifndef MODE
#define MODE 3
#endif
#if MODE == 0
#if CRYPTO_PUBLICKEYBYTES -896U
CRYPTO_PUBLICKEYBYTES size error
#endif
#if CRYPTO_SECRETKEYBYTES -2096U
CRYPTO_SECRETKEYBYTES size error
#endif
#if CRYPTO_BYTES -1387U
CRYPTO_BYTES size error
#endif
#elif MODE == 1
#if CRYPTO_PUBLICKEYBYTES -1184U
CRYPTO_PUBLICKEYBYTES size error
#endif
#if CRYPTO_SECRETKEYBYTES -2800U
CRYPTO_SECRETKEYBYTES size error
#endif
#if CRYPTO_BYTES -2044U
CRYPTO_BYTES size error
#endif
#elif MODE == 2
#if CRYPTO_PUBLICKEYBYTES -1472U
CRYPTO_PUBLICKEYBYTES size error
#endif
#if CRYPTO_SECRETKEYBYTES -3504U
CRYPTO_SECRETKEYBYTES size error
#endif
#if CRYPTO_BYTES -2701U
CRYPTO_BYTES size error
#endif
#elif MODE == 3
#if CRYPTO_PUBLICKEYBYTES -1760U
CRYPTO_PUBLICKEYBYTES size error
#endif
#if CRYPTO_SECRETKEYBYTES -3856U
CRYPTO_SECRETKEYBYTES size error
#endif
#if CRYPTO_BYTES -3366U
CRYPTO_BYTES size error
#endif
#endif
#define CRYPTO_ALGNAME "Dilithium"
int crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
int crypto_sign(uint8_t *sm, int32_t *smlen,
const uint8_t *msg, int32_t len,
const uint8_t *sk);
int crypto_sign_open(uint8_t *m, int32_t *mlen,
const uint8_t *sm, int32_t smlen,
const uint8_t *pk);
#endif

View File

@@ -85,6 +85,7 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
CCinit(cp,ecode);
cp->didinit = 1;
}
switch ( ecode )
{
case EVAL_IMPORTPAYOUT:
@@ -153,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<unsigned char> scriptVec = std::vector<unsigned char>(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<nNotaries; i++) {
if (!seenNotaries[i]) {
if (memcmp(pk, notaries[i], 33) == 0) {
seenNotaries[i] = 1;
goto found;
}
}
}
return false;
found:;
}
return true;
return CheckTxAuthority(tx, auth);
}
/*
* Get MoM from a notarisation tx hash (on KMD)
*/

View File

@@ -56,7 +56,8 @@
EVAL(EVAL_MARMARA, 0xef) \
EVAL(EVAL_PAYMENTS, 0xf0) \
EVAL(EVAL_GATEWAYS, 0xf1) \
EVAL(EVAL_TOKENS, 0xf2)
EVAL(EVAL_TOKENS, 0xf2) \
EVAL(EVAL_IMPORTGATEWAY, 0xf3) \
// evalcodes 0x10 to 0x7f are reserved for cclib dynamic CC

View File

@@ -118,15 +118,15 @@ bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
else if ( (hash[0] & 0xff) != 0 || (hash[31] & 0xff) != 0 )
return eval->Invalid("invalid faucetget txid");
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
SetCCtxids(txids,destaddr);
SetCCtxids(txids,destaddr,tx.vout[i].scriptPubKey.IsPayToCryptoCondition());
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
{
//int height = it->first.blockHeight;
if ( CCduration(numblocks,it->first.txhash) > 0 && numblocks > 3 )
{
//fprintf(stderr,"would return error %s numblocks.%d ago\n",uint256_str(str,it->first.txhash),numblocks);
return eval->Invalid("faucet is only for brand new addresses");
}
//fprintf(stderr,"txid %s numblocks.%d ago\n",uint256_str(str,it->first.txhash),numblocks);
}
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
if ( retval != 0 )
@@ -145,8 +145,12 @@ int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
SetCCunspents(unspentOutputs,coinaddr,true);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -157,7 +161,7 @@ int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsFaucetvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsFaucetvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));

View File

@@ -126,7 +126,7 @@ int64_t AddFSMInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;

289
src/cc/games/prices.c Normal file
View File

@@ -0,0 +1,289 @@
#include "prices.h"
#include <time.h>
#include <unistd.h>
#ifdef BUILD_GAMESCC
#include "../rogue/cursesd.h"
#else
#include <curses.h>
#endif
#define SATOSHIDEN ((uint64_t)100000000L)
#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"prices",cmdstr,0,0,0)
extern int64_t Net_change,Betsize;
int random_tetromino(struct games_state *rs)
{
rs->seed = _games_rngnext(rs->seed);
return(rs->seed % NUM_TETROMINOS);
}
int32_t pricesdata(struct games_player *P,void *ptr)
{
tetris_game *tg = (tetris_game *)ptr;
P->gold = tg->points;
P->dungeonlevel = tg->level;
//fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level);
return(0);
}
void sleep_milli(int milliseconds)
{
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = milliseconds * 1000 * 1000;
nanosleep(&ts, NULL);
}
struct games_state globalR;
extern char Gametxidstr[];
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c);
uint64_t get_btcusd();
int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize);
void *gamesiterate(struct games_state *rs)
{
bool running = true; uint32_t eventid = 0; int64_t price;
if ( rs->guiflag != 0 || rs->sleeptime != 0 )
{
initscr(); // initialize curses
cbreak(); // pass key presses to program, but not signals
noecho(); // don't echo key presses to screen
timeout(0);
}
while ( running != 0 )
{
//running = tg_tick(rs,tg,move);
if ( rs->guiflag != 0 || rs->sleeptime != 0 )
{
}
if ( rs->guiflag != 0 )
{
#ifdef STANDALONE
price = get_btcusd();
//fprintf(stderr,"%llu -> t%u %.4f\n",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000);
//issue_games_events(rs,Gametxidstr,eventid,price);
issue_bet(rs,price,Betsize);
eventid++;
doupdate();
sleep(10);
switch ( getch() )
{
case '+': Net_change++; break;
case '-': Net_change--; break;
case '0': Net_change = 0; break;
case '$': Betsize = SATOSHIDEN; break;
case '^': Betsize += (Betsize >> 3); break;
case '/': Betsize -= (Betsize >> 3); break;
}
/*if ( (counter++ % 10) == 0 )
doupdate();
c = games_readevent(rs);
if ( c <= 0x7f || skipcount == 0x3fff )
{
if ( skipcount > 0 )
issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000);
if ( c <= 0x7f )
issue_games_events(rs,Gametxidstr,eventid,c);
if ( tg->level != prevlevel )
{
flushkeystrokes(rs,0);
prevlevel = tg->level;
}
skipcount = 0;
} else skipcount++;*/
#endif
}
else
{
if ( rs->replaydone != 0 )
break;
if ( rs->sleeptime != 0 )
{
sleep_milli(1);
}
/*if ( skipcount == 0 )
{
c = games_readevent(rs);
//fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level);
if ( (c & 0x4000) == 0x4000 )
{
skipcount = (c & 0x3fff);
c = 'S';
}
}
if ( skipcount > 0 )
skipcount--;*/
}
eventid++;
}
return(0);
}
#ifdef STANDALONE
#include <ncurses.h>
#include "dapps/dappstd.c"
int64_t Net_change,Betsize = SATOSHIDEN;
char *send_curl(char *url,char *fname)
{
char *retstr;
retstr = issue_curl(url);
return(retstr);
}
cJSON *get_urljson(char *url,char *fname)
{
char *jsonstr; cJSON *json = 0;
if ( (jsonstr= send_curl(url,fname)) != 0 )
{
//printf("(%s) -> (%s)\n",url,jsonstr);
json = cJSON_Parse(jsonstr);
free(jsonstr);
}
return(json);
}
//////////////////////////////////////////////
// start of dapp
//////////////////////////////////////////////
uint64_t get_btcusd()
{
cJSON *pjson,*bpi,*usd; char str[512]; uint64_t x,newprice,mult,btcusd = 0;
if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json",(char *)"/tmp/oraclefeed.json")) != 0 )
{
if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 )
{
btcusd = jdouble(usd,(char *)"rate_float") * SATOSHIDEN;
mult = 10000 + Net_change*10;
newprice = (btcusd * mult) / 10000;
x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff);
sprintf(str,"BTC/USD %.4f -> Betsize %.8f (^ / to change) && %.4f Net %.1f%% [+ - to change]\n",dstr(btcusd),dstr(Betsize),dstr(newprice),(double)100*(mult-10000)/10000);
mvaddstr(0, 0, str);
clrtoeol();
doupdate();
}
free_json(pjson);
}
return(x);
}
char *clonestr(char *str)
{
char *clone; int32_t len;
if ( str == 0 || str[0] == 0 )
{
printf("warning cloning nullstr.%p\n",str);
#ifdef __APPLE__
while ( 1 ) sleep(1);
#endif
str = (char *)"<nullstr>";
}
len = strlen(str);
clone = (char *)calloc(1,len+16);
strcpy(clone,str);
return(clone);
}
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c)
{
static FILE *fp;
char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1;
if ( fp == 0 )
fp = fopen("events.log","wb");
rs->buffered[rs->num++] = c;
if ( 1 )
{
if ( sizeof(c) == 1 )
sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",(uint8_t)c&0xff,gametxidstr,eventid);
else if ( sizeof(c) == 2 )
sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",(uint16_t)c&0xffff,gametxidstr,eventid);
else if ( sizeof(c) == 4 )
sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",(uint32_t)c&0xffffffff,gametxidstr,eventid);
else if ( sizeof(c) == 8 )
sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid);
if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 )
{
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( (resobj= jobj(retjson,(char *)"result")) != 0 )
{
retval = 0;
if ( fp != 0 )
{
fprintf(fp,"%s\n",jprint(resobj,0));
fflush(fp);
}
}
free_json(retjson);
} else fprintf(fp,"error parsing %s\n",retstr);
free(retstr);
} else fprintf(fp,"error issuing method %s\n",params);
return(retval);
} else return(0);
}
int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize)
{
char params[512],hexstr[64],*retstr; cJSON *retjson,*resobj; int32_t i,retval = -1;
memset(hexstr,0,sizeof(hexstr));
for (i=0; i<8; i++)
{
sprintf(&hexstr[i<<1],"%02x",(uint8_t)(x & 0xff));
x >>= 8;
}
sprintf(params,"[\"bet\",\"17\",\"[%.8f,%%22%s%%22]\"]",dstr(betsize),hexstr);
if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 )
{
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( (resobj= jobj(retjson,(char *)"result")) != 0 )
{
retval = 0;
//fprintf(stderr,"%s\n",jprint(resobj,0));
}
free_json(retjson);
}
free(retstr);
}
return(retval);
}
int prices(int argc, char **argv)
{
struct games_state *rs = &globalR;
int32_t c,skipcount=0; uint32_t eventid = 0;
memset(rs,0,sizeof(*rs));
rs->guiflag = 1;
rs->sleeptime = 1; // non-zero to allow refresh()
if ( argc >= 2 && strlen(argv[2]) == 64 )
{
#ifdef _WIN32
#ifdef _MSC_VER
rs->origseed = _strtoui64(argv[1], NULL, 10);
#else
rs->origseed = atol(argv[1]); // windows, but not MSVC
#endif // _MSC_VER
#else
rs->origseed = atol(argv[1]); // non-windows
#endif // _WIN32
rs->seed = rs->origseed;
if ( argc >= 3 )
{
strcpy(Gametxidstr,argv[2]);
fprintf(stderr,"setplayerdata %s\n",Gametxidstr);
if ( games_setplayerdata(rs,Gametxidstr) < 0 )
{
fprintf(stderr,"invalid gametxid, or already started\n");
return(-1);
}
}
} else rs->seed = 777;
gamesiterate(rs);
//gamesbailout(rs);
return 0;
}
#endif

281
src/cc/games/prices.cpp Normal file
View File

@@ -0,0 +1,281 @@
/******************************************************************************
* 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. *
* *
******************************************************************************/
std::string MYCCLIBNAME = (char *)"prices";
#define PRICES_BETPERIOD 3
UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag);
extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33];
#define bstr(x) ((double)((uint32_t)x) / 10000.)
struct prices_bar
{
uint64_t open,high,low,close,sum;
int32_t num;
};
int32_t prices_barupdate(struct prices_bar *bar,uint64_t pricebits)
{
uint32_t uprice,timestamp;
timestamp = (uint32_t)(pricebits >> 32);
uprice = (uint32_t)pricebits;
bar->sum += uprice, bar->num++;
if ( bar->open == 0 )
bar->open = bar->high = bar->low = pricebits;
if ( uprice > (uint32_t)bar->high )
bar->high = pricebits;
else if ( uprice < (uint32_t)bar->low )
bar->low = pricebits;
bar->close = pricebits;
return(0);
}
int64_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebits)
{
int64_t a,dist = 0;
if ( aveprice != 0 )
{
a = (pricebits & 0xffffffff);
dist = (a - aveprice);
dist *= dist;
//fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice);
}
return(dist);
}
void prices_bardisp(struct prices_bar *bar)
{
if ( bar->num == 0 )
fprintf(stderr,"BAR null\n");
else fprintf(stderr,"BAR ave %.4f (O %.4f, H %.4f, L %.4f, C %.4f)\n",bstr(bar->sum/bar->num),bstr(bar->open),bstr(bar->high),bstr(bar->low),bstr(bar->close));
}
int64_t prices_blockinfo(int32_t height,char *acaddr)
{
std::vector<uint8_t> vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t dist,mindist=(1LL<<60),prizefund = 0; int32_t mini=-1,i,n,vini,numvouts,iter; struct prices_bar refbar;
if ( (pindex= komodo_chainactive(height)) != 0 )
{
if ( komodo_blockload(block,pindex) == 0 )
{
n = block.vtx.size();
vini = 0;
memset(&refbar,0,sizeof(refbar));
for (iter=0; iter<2; iter++)
{
for (i=0; i<n; i++)
{
tx = block.vtx[i];
if ( myGetTransaction(tx.vin[vini].prevout.hash,vintx,hashBlock) == 0 )
continue;
else if ( tx.vin[vini].prevout.n >= vintx.vout.size() || Getscriptaddress(destaddr,vintx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 )
continue;
else if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a )
{
GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
if ( vopret.size() == 8 )
{
E_UNMARSHAL(vopret,ss >> pricebits);
timestamp = (uint32_t)(pricebits >> 32);
uprice = (uint32_t)pricebits;
if ( iter == 0 )
{
prizefund += tx.vout[0].nValue;
if ( strcmp(acaddr,destaddr) == 0 )
{
//fprintf(stderr,"REF ");
prices_barupdate(&refbar,pricebits);
}
}
else if ( strcmp(acaddr,destaddr) != 0 )
{
dist = prices_bardist(&refbar,aveprice,pricebits);
if ( dist < mindist )
{
mindist = dist;
mini = i;
}
fprintf(stderr,"mini.%d i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%lld\n",mini,i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,(long long)dist);
}
} else return(-3);
}
}
if ( iter == 0 )
{
prices_bardisp(&refbar);
if ( refbar.num != 0 )
aveprice = (uint32_t)refbar.sum / refbar.num;
}
}
return(prizefund);
} else return(-2);
} else return(-1);
}
UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result(UniValue::VOBJ); char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight();
if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error"," no -ac_pubkey for price reference"));
return(result);
}
mypk = pubkey2pk(Mypubkey());
gamespk = GetUnspendable(cp,0);
acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33);
Getscriptaddress(acaddr,CScript() << ParseHex(HexStr(acpk)) << OP_CHECKSIG);
if ( params != 0 && cJSON_GetArraySize(params) == 1 )
{
height = juint(jitem(params,0),0);
result.push_back(Pair("height",(int64_t)height));
if ( (prizefund= prices_blockinfo(height,acaddr)) < 0 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("errorcode",prizefund));
result.push_back(Pair("error","blockinfo error"));
}
else
{
// display bets
if ( height <= nextheight-PRICES_BETPERIOD )
{
// settle bets by first nonzero reference bar
}
result.push_back(Pair("prizefund",ValueFromAmount(prizefund)));
result.push_back(Pair("result","success"));
}
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt parse"));
}
return(result);
}
UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; uint64_t price; CPubKey gamespk,mypk,acpk;
if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error"," no -ac_pubkey for price reference"));
return(result);
}
mypk = pubkey2pk(Mypubkey());
gamespk = GetUnspendable(cp,0);
acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33);
if ( params != 0 && cJSON_GetArraySize(params) == 2 )
{
amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049;
if ( cclib_parsehash((uint8_t *)&price,jitem(params,1),8) < 0 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt parsehash"));
return(result);
}
if ( mypk == acpk )
{
amount = 0; // i am the reference price feed
//fprintf(stderr,"i am the reference\n");
}
//fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price);
if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk));
rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,CScript() << OP_RETURN << price);
return(games_rawtxresult(result,rawtx,1));
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","not enough funds"));
}
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt parse"));
}
return(result);
}
void prices_update(uint32_t timestamp,uint32_t uprice,int32_t ismine)
{
//fprintf(stderr,"%s t%u %.4f %16llx\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000,(long long)((uint64_t)timestamp<<32) | uprice);
}
// game specific code for daemon
void games_packitemstr(char *packitemstr,struct games_packitem *item)
{
strcpy(packitemstr,"");
}
int64_t games_cashout(struct games_player *P)
{
int32_t dungeonlevel = P->dungeonlevel; int64_t mult=1000,cashout = 0;
cashout = (uint64_t)P->gold * mult * dungeonlevel * dungeonlevel;
return(cashout);
}
void pricesplayerjson(UniValue &obj,struct games_player *P)
{
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));
}
int32_t disp_gamesplayer(char *str,struct games_player *P)
{
str[0] = 0;
//if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 )
// return(-1);
sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel);
return(0);
}
int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector<uint8_t> payload)
{
uint256 gametxid; int32_t i,len; char str[67]; int64_t price; uint32_t eventid = 0;
if ( (len= payload.size()) > 36 )
{
len -= 36;
for (i=0; i<32; i++)
((uint8_t *)&gametxid)[i] = payload[len+i];
eventid = (uint32_t)payload[len+32];
eventid |= (uint32_t)payload[len+33] << 8;
eventid |= (uint32_t)payload[len+34] << 16;
eventid |= (uint32_t)payload[len+35] << 24;
for (i=0; i<len&&i<sizeof(price); i++)
((uint8_t *)&price)[7-i] = payload[i];
prices_update((uint32_t)(price >> 32),(uint32_t)(price & 0xffffffff),pk == pubkey2pk(Mypubkey()));
//fprintf(stderr,"%llu -> t%u %.4f ",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000);
//fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid);
return(0);
} else return(-1);
}
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
{
return(true);
}

208
src/cc/games/prices.h Normal file
View File

@@ -0,0 +1,208 @@
#ifndef H_PRICES_H
#define H_PRICES_H
/***************************************************************************/
/** 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.
*******************************************************************************/
/*
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;
/*
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;
char board[];
} 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 const 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 const int GRAVITY_LEVEL[MAX_LEVEL+1];
// Data structure manipulation.
void tg_init(tetris_game *obj, int rows, int cols);
tetris_game *tg_create(struct games_state *rs,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(struct games_state *rs,tetris_game *obj, tetris_move move);
void tg_print(tetris_game *obj, FILE *f);
/******************************************************************************
* 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. *
* *
******************************************************************************/
#define GAMENAME "prices" // name of executable
#define GAMEMAIN prices // main program of game
#define GAMEPLAYERJSON pricesplayerjson // displays game specific json
#define GAMEDATA pricesdata // extracts data from game specific variables into games_state
#define CHAINNAME "PRICES" // -ac_name=
typedef uint64_t gamesevent; // can be 8, 16, 32, or 64 bits
#define MAXPACK 23
struct games_packitem
{
int32_t type,launch,count,which,hplus,dplus,arm,flags,group;
char damage[8],hurldmg[8];
};
struct games_player
{
int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet;
struct games_packitem gamespack[MAXPACK];
};
struct games_state
{
uint64_t seed,origseed;
char *keystrokeshex;
uint32_t needflush,replaydone;
int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum;
FILE *logfp;
struct games_player P;
gamesevent buffered[5000],*keystrokes;
uint8_t playerdata[8192];
};
extern struct games_state globalR;
void *gamesiterate(struct games_state *rs);
int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag);
void games_packitemstr(char *packitemstr,struct games_packitem *item);
uint64_t _games_rngnext(uint64_t initseed);
int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis);
gamesevent games_revendian(gamesevent revx);
int32_t disp_gamesplayer(char *str,struct games_player *P);
#endif

904
src/cc/games/tetris.c Normal file
View File

@@ -0,0 +1,904 @@
#include "tetris.h"
/*
In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure.
also, the standalone game needs to support argv of seed gametxid, along with replay args
*/
int random_tetromino(struct games_state *rs)
{
rs->seed = _games_rngnext(rs->seed);
return(rs->seed % NUM_TETROMINOS);
}
int32_t tetrisdata(struct games_player *P,void *ptr)
{
tetris_game *tg = (tetris_game *)ptr;
P->gold = tg->points;
P->dungeonlevel = tg->level;
//fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level);
return(0);
}
/***************************************************************************/
/** 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.
*******************************************************************************/
#include <stdio.h> // for FILE
#include <stdbool.h> // for bool
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <string.h>
#ifdef BUILD_GAMESCC
#include "../rogue/cursesd.h"
#else
#include <curses.h>
#endif
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
/*******************************************************************************
Array Definitions
*******************************************************************************/
const 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}}},
};
const 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;
}
/*
Create a new falling block and populate the next falling block with a random
one.
*/
static void tg_new_falling(struct games_state *rs,tetris_game *obj)
{
// Put in a new falling tetromino.
obj->falling = obj->next;
obj->next.typ = random_tetromino(rs);
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(struct games_state *rs,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(rs,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(struct games_state *rs,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(rs,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(struct games_state *rs,tetris_game *obj)
{
tg_remove(obj, obj->falling);
if (obj->stored.typ == -1) {
obj->stored = obj->falling;
tg_new_falling(rs,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--;
if (tg_fits(obj, obj->falling)) {
break;
}
obj->falling.loc.col--;
if (tg_fits(obj, obj->falling)) {
break;
}
obj->falling.loc.col += 2;
}
}
tg_put(obj, obj->falling);
}
/*
Perform the action specified by the move.
*/
static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move move)
{
switch (move) {
case TM_LEFT:
//fprintf(stderr,"LEFT ");
tg_move(obj, -1);
break;
case TM_RIGHT:
//fprintf(stderr,"RIGHT ");
tg_move(obj, 1);
break;
case TM_DROP:
tg_down(rs,obj);
break;
case TM_CLOCK:
tg_rotate(obj, 1);
break;
case TM_COUNTER:
tg_rotate(obj, -1);
break;
case TM_HOLD:
tg_hold(rs,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(struct games_state *rs,tetris_game *obj, tetris_move move)
{
int lines_cleared;
// Handle gravity.
tg_do_gravity_tick(rs,obj);
// Handle input.
tg_handle_move(rs,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(struct games_state *rs,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(rs,obj);
tg_new_falling(rs,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(struct games_state *rs,int rows, int cols)
{
tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game) + rows*cols);
tg_init(rs,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, (char *)"Score\n%d\n", tg->points);
wprintw(w, (char *)"Level\n%d\n", tg->level);
wprintw(w, (char *)"Lines\n%d\n", tg->lines_remaining);
wnoutrefresh(w);
}
/*
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, (char *)"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();
fprintf(stderr,"Game saved to \"tetris.save\".\n");
fprintf(stderr,"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);
}
struct games_state globalR;
extern char Gametxidstr[];
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c);
gamesevent games_readevent(struct games_state *rs);
void *gamesiterate(struct games_state *rs)
{
uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE;
gamesevent c; uint16_t skipcount=0; int32_t prevlevel; uint32_t eventid = 0; tetris_game *tg;
WINDOW *board, *next, *hold, *score;
if ( rs->guiflag != 0 || rs->sleeptime != 0 )
{
// 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
}
tg = tg_create(rs,22, 10);
prevlevel = tg->level;
// 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);
while ( running != 0 )
{
running = tg_tick(rs,tg,move);
if ( 1 && (rs->guiflag != 0 || rs->sleeptime != 0) )
{
display_board(board,tg);
display_piece(next,tg->next);
display_piece(hold,tg->stored);
display_score(score,tg);
}
if ( rs->guiflag != 0 )
{
#ifdef STANDALONE
sleep_milli(15);
if ( (counter++ % 10) == 0 )
doupdate();
c = games_readevent(rs);
if ( c <= 0x7f || skipcount == 0x3fff )
{
if ( skipcount > 0 )
issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000);
if ( c <= 0x7f )
issue_games_events(rs,Gametxidstr,eventid,c);
if ( tg->level != prevlevel )
{
flushkeystrokes(rs,0);
prevlevel = tg->level;
}
skipcount = 0;
} else skipcount++;
#endif
}
else
{
if ( rs->replaydone != 0 )
break;
if ( rs->sleeptime != 0 )
{
sleep_milli(1);
if ( (counter++ % 20) == 0 )
doupdate();
}
if ( skipcount == 0 )
{
c = games_readevent(rs);
//fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level);
if ( (c & 0x4000) == 0x4000 )
{
skipcount = (c & 0x3fff);
c = 'S';
}
}
if ( skipcount > 0 )
skipcount--;
}
eventid++;
switch ( c )
{
case 'h':
move = TM_LEFT;
break;
case 'l':
move = TM_RIGHT;
break;
case 'k':
move = TM_CLOCK;
break;
case 'j':
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 's':
save(tg, board);
move = TM_NONE;
break;*/
case ' ':
move = TM_HOLD;
break;
default:
move = TM_NONE;
}
}
return(tg);
}
#ifdef STANDALONE
/*
Main tetris game!
*/
#include "dapps/dappstd.c"
char *clonestr(char *str)
{
char *clone; int32_t len;
if ( str == 0 || str[0] == 0 )
{
printf("warning cloning nullstr.%p\n",str);
#ifdef __APPLE__
while ( 1 ) sleep(1);
#endif
str = (char *)"<nullstr>";
}
len = strlen(str);
clone = (char *)calloc(1,len+16);
strcpy(clone,str);
return(clone);
}
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c)
{
static FILE *fp;
char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1;
if ( fp == 0 )
fp = fopen("events.log","wb");
rs->buffered[rs->num++] = c;
if ( 0 )
{
if ( sizeof(c) == 1 )
sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",(uint8_t)c&0xff,gametxidstr,eventid);
else if ( sizeof(c) == 2 )
sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",(uint16_t)c&0xffff,gametxidstr,eventid);
else if ( sizeof(c) == 4 )
sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",(uint32_t)c&0xffffffff,gametxidstr,eventid);
else if ( sizeof(c) == 8 )
sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid);
if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 )
{
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( (resobj= jobj(retjson,(char *)"result")) != 0 )
{
retval = 0;
if ( fp != 0 )
{
fprintf(fp,"%s\n",jprint(resobj,0));
fflush(fp);
}
}
free_json(retjson);
} else fprintf(fp,"error parsing %s\n",retstr);
free(retstr);
} else fprintf(fp,"error issuing method %s\n",params);
return(retval);
} else return(0);
}
int tetris(int argc, char **argv)
{
struct games_state *rs = &globalR;
int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg = 0;
memset(rs,0,sizeof(*rs));
rs->guiflag = 1;
rs->sleeptime = 1; // non-zero to allow refresh()
if ( argc >= 2 && strlen(argv[2]) == 64 )
{
#ifdef _WIN32
#ifdef _MSC_VER
rs->origseed = _strtoui64(argv[1], NULL, 10);
#else
rs->origseed = atol(argv[1]); // windows, but not MSVC
#endif // _MSC_VER
#else
rs->origseed = atol(argv[1]); // non-windows
#endif // _WIN32
rs->seed = rs->origseed;
if ( argc >= 3 )
{
strcpy(Gametxidstr,argv[2]);
fprintf(stderr,"setplayerdata %s\n",Gametxidstr);
if ( games_setplayerdata(rs,Gametxidstr) < 0 )
{
fprintf(stderr,"invalid gametxid, or already started\n");
return(-1);
}
}
} else rs->seed = 777;
/* 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(rs,22, 10);
}*/
// Game loop
tg = (tetris_game *)gamesiterate(rs);
gamesbailout(rs);
// Deinitialize NCurses
wclear(stdscr);
endwin();
// 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;
}
#endif

87
src/cc/games/tetris.cpp Normal file
View File

@@ -0,0 +1,87 @@
/******************************************************************************
* 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. *
* *
******************************************************************************/
std::string MYCCLIBNAME = (char *)"gamescc";
// game specific code for daemon
void games_packitemstr(char *packitemstr,struct games_packitem *item)
{
strcpy(packitemstr,"");
}
int64_t games_cashout(struct games_player *P)
{
int32_t dungeonlevel = P->dungeonlevel; int64_t mult=10000,cashout = 0;
cashout = (uint64_t)P->gold * mult;
return(cashout);
}
void tetrisplayerjson(UniValue &obj,struct games_player *P)
{
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));
}
int32_t disp_gamesplayer(char *str,struct games_player *P)
{
str[0] = 0;
//if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 )
// return(-1);
sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel);
return(0);
}
int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector<uint8_t> payload)
{
uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0;
if ( (len= payload.size()) > 36 )
{
len -= 36;
for (i=0; i<32; i++)
((uint8_t *)&gametxid)[i] = payload[len+i];
eventid = (uint32_t)payload[len+32];
eventid |= (uint32_t)payload[len+33] << 8;
eventid |= (uint32_t)payload[len+34] << 16;
eventid |= (uint32_t)payload[len+35] << 24;
//for (i=0; i<len; i++)
// fprintf(stderr,"%02x",payload[i]);
//fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid);
return(0);
} else return(-1);
}
UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result;
return(result);
}
UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result;
return(result);
}
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
{
return(true);
}

208
src/cc/games/tetris.h Normal file
View File

@@ -0,0 +1,208 @@
#ifndef H_TETRIS_H
#define H_TETRIS_H
/***************************************************************************/
/** 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.
*******************************************************************************/
/*
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;
/*
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;
char board[];
} 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 const 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 const int GRAVITY_LEVEL[MAX_LEVEL+1];
// Data structure manipulation.
void tg_init(tetris_game *obj, int rows, int cols);
tetris_game *tg_create(struct games_state *rs,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(struct games_state *rs,tetris_game *obj, tetris_move move);
void tg_print(tetris_game *obj, FILE *f);
/******************************************************************************
* 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. *
* *
******************************************************************************/
#define GAMENAME "tetris" // name of executable
#define GAMEMAIN tetris // main program of game
#define GAMEPLAYERJSON tetrisplayerjson // displays game specific json
#define GAMEDATA tetrisdata // extracts data from game specific variables into games_state
#define CHAINNAME "GTEST" // -ac_name=
typedef uint16_t gamesevent; // can be 8, 16, 32, or 64 bits
#define MAXPACK 23
struct games_packitem
{
int32_t type,launch,count,which,hplus,dplus,arm,flags,group;
char damage[8],hurldmg[8];
};
struct games_player
{
int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet;
struct games_packitem gamespack[MAXPACK];
};
struct games_state
{
uint64_t seed,origseed;
char *keystrokeshex;
uint32_t needflush,replaydone;
int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum;
FILE *logfp;
struct games_player P;
gamesevent buffered[5000],*keystrokes;
uint8_t playerdata[8192];
};
extern struct games_state globalR;
void *gamesiterate(struct games_state *rs);
int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag);
void games_packitemstr(char *packitemstr,struct games_packitem *item);
uint64_t _games_rngnext(uint64_t initseed);
int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis);
gamesevent games_revendian(gamesevent revx);
int32_t disp_gamesplayer(char *str,struct games_player *P);
#endif

1811
src/cc/gamescc.cpp Normal file

File diff suppressed because it is too large Load Diff

120
src/cc/gamescc.h Normal file
View File

@@ -0,0 +1,120 @@
#ifndef H_GAMESCC_H
#define H_GAMESCC_H
#include <stdint.h>
#include <stdio.h>
#define GAMES_RNGMULT 11109
#define GAMES_RNGOFFSET 13849
#define GAMES_MAXRNGS 10000
#ifndef STANDALONE
#define ENABLE_WALLET
extern CWallet* pwalletMain;
#include "CCinclude.h"
#include "secp256k1.h"
#define EVAL_GAMES (EVAL_FAUCET2+1)
#define GAMES_TXFEE 10000
#define GAMES_MAXITERATIONS 777
#define GAMES_MAXKEYSTROKESGAP 60
#define GAMES_MAXPLAYERS 64
#define GAMES_REGISTRATIONSIZE (100 * 10000)
#define GAMES_REGISTRATION 1
#define MYCCNAME "games"
std::string Games_pname;
#define RPC_FUNCS \
{ (char *)MYCCNAME, (char *)"rng", (char *)"hash,playerid", 1, 2, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"rngnext", (char *)"seed", 1, 1, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"fund", (char *)"amount", 1, 1, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"players", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"games", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"pending", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"setname", (char *)"pname", 1, 1, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"newgame", (char *)"maxplayers,buyin", 2, 2, 'C', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"playerinfo", (char *)"playertxid", 1, 1, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"gameinfo", (char *)"gametxid", 1, 1, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"keystrokes", (char *)"txid,hexstr", 2, 2, 'K', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"bailout", (char *)"gametxid", 1, 1, 'Q', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"highlander", (char *)"gametxid", 1, 1, 'H', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"events", (char *)"eventshex [gametxid [eventid]]", 1, 3, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"bet", (char *)"amount hexstr", 2, 2, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"settle", (char *)"height", 1, 1, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"register", (char *)"gametxid [playertxid]", 1, 2, 'R', EVAL_GAMES },
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
UniValue games_rng(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_rngnext(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
#define CUSTOM_DISPATCH \
if ( cp->evalcode == EVAL_GAMES ) \
{ \
if ( strcmp(method,"rng") == 0 ) \
return(games_rng(txfee,cp,params)); \
else if ( strcmp(method,"rngnext") == 0 ) \
return(games_rngnext(txfee,cp,params)); \
else if ( strcmp(method,"newgame") == 0 ) \
return(games_newgame(txfee,cp,params)); \
else if ( strcmp(method,"gameinfo") == 0 ) \
return(games_gameinfo(txfee,cp,params)); \
else if ( strcmp(method,"register") == 0 ) \
return(games_register(txfee,cp,params)); \
else if ( strcmp(method,"events") == 0 ) \
return(games_events(txfee,cp,params)); \
else if ( strcmp(method,"players") == 0 ) \
return(games_players(txfee,cp,params)); \
else if ( strcmp(method,"games") == 0 ) \
return(games_games(txfee,cp,params)); \
else if ( strcmp(method,"pending") == 0 ) \
return(games_pending(txfee,cp,params)); \
else if ( strcmp(method,"setname") == 0 ) \
return(games_setname(txfee,cp,params)); \
else if ( strcmp(method,"playerinfo") == 0 ) \
return(games_playerinfo(txfee,cp,params)); \
else if ( strcmp(method,"keystrokes") == 0 ) \
return(games_keystrokes(txfee,cp,params)); \
else if ( strcmp(method,"extract") == 0 ) \
return(games_extract(txfee,cp,params)); \
else if ( strcmp(method,"bailout") == 0 ) \
return(games_bailout(txfee,cp,params)); \
else if ( strcmp(method,"highlander") == 0 ) \
return(games_highlander(txfee,cp,params)); \
else if ( strcmp(method,"fund") == 0 ) \
return(games_fund(txfee,cp,params)); \
else if ( strcmp(method,"bet") == 0 ) \
return(games_bet(txfee,cp,params)); \
else if ( strcmp(method,"settle") == 0 ) \
return(games_settle(txfee,cp,params)); \
else \
{ \
result.push_back(Pair("result","error")); \
result.push_back(Pair("error","invalid gamescc method")); \
return(result); \
} \
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -255,25 +255,25 @@ template <class Helper> 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)
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);
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<uint8_t> vopret, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, 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<uint8_t> 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; \
} \
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) {
@@ -322,84 +322,52 @@ uint8_t _DecodeHeirOpRet(std::vector<uint8_t> vopret, CPubKey& ownerPubkey, CPub
return (uint8_t)0;
}
/* not used, see DecodeHeirOpRet(vopret,...)
// overload for 'F' opret
uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging)
{
uint256 dummytxid;
uint8_t dummyHasHeirSpendingBegun;
std::vector<uint8_t> vopret;
GetOpReturnData(scriptPubKey, vopret);
if (vopret.size() == 0) {
if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl;
return (uint8_t)0;
}
return _DecodeHeirOpRet(vopret, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging);
}*/
/* not used, see DecodeHeirOpRet(vopret,...)
// overload for A, C oprets and AddHeirContractInputs
uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
{
CPubKey dummyOwnerPubkey, dummyHeirPubkey;
int64_t dummyInactivityTime;
std::string dummyHeirName;
std::vector<uint8_t> vopret;
GetOpReturnData(scriptPubKey, vopret);
if (vopret.size() == 0) {
if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl;
return (uint8_t)0;
}
return _DecodeHeirOpRet(vopret, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging);
} */
// decode combined opret:
uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
{
uint8_t evalCodeTokens = 0;
std::vector<CPubKey> voutPubkeysDummy;
std::vector<uint8_t> vopretExtra, vopretStripped;
if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, vopretExtra) != 0) {
if (vopretExtra.size() > 1) {
uint8_t evalCodeTokens = 0;
std::vector<CPubKey> voutPubkeysDummy;
std::vector<std::pair<uint8_t, vscript_t>> oprets;
vscript_t vopretExtra /*, vopretStripped*/;
if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, oprets) != 0 && GetOpretBlob(oprets, OPRETID_HEIRDATA, vopretExtra)) {
/* if (vopretExtra.size() > 1) {
// restore the second opret:
/* unmarshalled in DecodeTokenOpRet:
if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size
if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() could not unmarshal vopretStripped" << std::endl;
return (uint8_t)0;
}
}
else {
if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() empty vopretExtra" << std::endl;
return (uint8_t)0;
}
}
else
GetOpReturnData(scriptPubKey, vopretStripped);
return _DecodeHeirOpRet(vopretStripped, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
} */
if (vopretExtra.size() < 1) {
if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() empty vopretExtra" << std::endl;
return (uint8_t)0;
}
}
else {
GetOpReturnData(scriptPubKey, vopretExtra);
}
return _DecodeHeirOpRet(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
}
// overload to decode opret in fundingtxid:
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) {
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, bool noLogging) {
uint256 dummyFundingTxidInOpret;
uint8_t dummyHasHeirSpendingBegun;
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging);
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging);
}
// overload to decode opret in A and C heir tx:
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) {
CPubKey dummyOwnerPubkey, dummyHeirPubkey;
int64_t dummyInactivityTime;
std::string dummyHeirName;
std::string dummyHeirName, dummyMemo;
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, dummyMemo, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
}
// check if pubkey is in vins
@@ -423,7 +391,7 @@ void CheckVinPubkey(std::vector<CTxIn> vins, CPubKey pubkey, bool &hasPubkey, bo
* find the latest funding tx: it may be the first F tx or one of A or C tx's
* Note: this function is also called from validation code (use non-locking calls)
*/
uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun)
uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun)
{
CTransaction fundingtx;
uint256 hashBlock;
@@ -431,7 +399,7 @@ uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &toke
//char markeraddr[64];
//CCtxidaddr(markeraddr, fundingtxid);
//SetCCunspents(unspentOutputs, markeraddr);
//SetCCunspents(unspentOutputs, markeraddr,true);
hasHeirSpendingBegun = 0;
funcId = 0;
@@ -440,7 +408,7 @@ uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &toke
if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) {
CScript heirScript = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript();
uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
if (funcId != 0) {
// found at least funding tx!
//std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n';
@@ -461,7 +429,7 @@ uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &toke
char coinaddr[64];
GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys'
SetCCunspents(unspentOutputs, coinaddr); // get vector with tx's with unspent vouts of 1of2pubkey address:
SetCCunspents(unspentOutputs, coinaddr,true); // get vector with tx's with unspent vouts of 1of2pubkey address:
//std::cerr << "FindLatestFundingTx() using 1of2address=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n';
int32_t maxBlockHeight = 0; // max block height
@@ -522,17 +490,17 @@ uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRe
CPubKey ownerPubkey;
CPubKey heirPubkey;
int64_t inactivityTime;
std::string heirName;
std::string heirName, memo;
return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun);
return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, opRetScript, hasHeirSpendingBegun);
}
// overload for transaction creation code
uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint8_t &hasHeirSpendingBegun)
uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint8_t &hasHeirSpendingBegun)
{
CScript opRetScript;
return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun);
return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, opRetScript, hasHeirSpendingBegun);
}
// add inputs of 1 of 2 cc address
@@ -546,11 +514,11 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
char coinaddr[64];
Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 of 2 pubkeys'
SetCCunspents(unspentOutputs, coinaddr);
SetCCunspents(unspentOutputs, coinaddr,true);
// char markeraddr[64];
// CCtxidaddr(markeraddr, fundingtxid);
// SetCCunspents(unspentOutputs, markeraddr);
// SetCCunspents(unspentOutputs, markeraddr,true);
std::cerr << "Add1of2AddressInputs() using 1of2addr=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << std::endl;
@@ -561,7 +529,7 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
// no need to prevent dup
// dimxy: maybe it is good to put tx's in cache?
std::cerr << "Add1of2AddressInputs() txid=" << txid.GetHex() << std::endl;
//std::cerr << "Add1of2AddressInputs() txid=" << txid.GetHex() << std::endl;
if (GetTransaction(txid, heirtx, hashBlock, false) != 0) {
uint256 tokenid;
@@ -576,7 +544,7 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
isMyFuncId(funcId) &&
(typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, voutIndex, tokenid) > 0) && // token validation logic
//(voutValue = IsHeirFundingVout<Helper>(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && // heir contract vout validation logic - not used since we moved to 2-eval vouts
!myIsutxo_spentinmempool(txid, voutIndex))
!myIsutxo_spentinmempool(ignoretxid,ignorevin,txid, voutIndex))
{
std::cerr << "Add1of2AddressInputs() satoshis=" << it->second.satoshis << std::endl;
if (total != 0 && maxinputs != 0)
@@ -601,7 +569,7 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys'
std::vector<std::pair<CAddressIndexKey, CAmount>> addressIndexes;
SetCCtxids(addressIndexes, coinaddr);
SetCCtxids(addressIndexes, coinaddr,true);
//fprintf(stderr,"LifetimeHeirContractFunds() scan lifetime of %s\n",coinaddr);
int64_t total = 0;
@@ -626,7 +594,7 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
(txid == fundingtxid || fundingTxidInOpret == fundingtxid) &&
isMyFuncId(funcId) && !isSpendingTx(funcId) &&
(typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, ivout, tokenid) > 0) &&
!myIsutxo_spentinmempool(txid, ivout)) // exclude tx in mempool
!myIsutxo_spentinmempool(ignoretxid,ignorevin,txid, ivout)) // exclude tx in mempool
{
total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change)
//std::cerr << "LifetimeHeirContractFunds() added tx=" << txid.GetHex() << " it->second=" << it->second << " vout[0].nValue=" << tx.vout[ivout].nValue << " opreturn=" << (char)funcId << '\n';
@@ -644,7 +612,7 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
* and also for setting spending plan for the funds' owner and heir
* @return fundingtxid handle for subsequent references to this heir funding plan
*/
template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid)
template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid)
{
UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -657,13 +625,7 @@ template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std
int64_t markerfee = 10000;
//std::cerr << "HeirFund() amount=" << amount << " txfee=" << txfee << " heirPubkey IsValid()=" << heirPubkey.IsValid() << " inactivityTime(sec)=" << inactivityTimeSec << " tokenid=" << tokenid.GetHex() << std::endl;
if (!heirPubkey.IsValid()) {
std::cerr << "HeirFund() heirPubkey is not valid!" << std::endl;
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid heir pubkey"));
}
CPubKey myPubkey = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, myPubkey, markerfee, 3) > 0) {
@@ -711,10 +673,10 @@ template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std
// add change for txfee and opreturn vouts and sign tx:
std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee,
Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName));
Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName, memo));
if (!rawhextx.empty()) {
result.push_back(Pair("result", "success"));
result.push_back(Pair("hextx", rawhextx));
result.push_back(Pair("hex", rawhextx));
}
else {
std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl;
@@ -737,12 +699,12 @@ template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std
}
// if no these callers - it could not link
UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){
return _HeirFund<CoinHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid);
UniValue HeirFundCoinCaller(int64_t txfee, int64_t coins, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo){
return _HeirFund<CoinHelper>(txfee, coins, heirName, heirPubkey, inactivityTimeSec, memo, zeroid);
}
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) {
return _HeirFund<TokenHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid);
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid) {
return _HeirFund<TokenHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, memo, tokenid);
}
/**
@@ -750,7 +712,7 @@ UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirNa
* creates tx to add more funds to cryptocondition address for spending by either funds' owner or heir
* @return result object with raw tx or error text
*/
template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint8_t hasHeirSpendingBegun)
{
UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -835,7 +797,7 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, in
Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun)));
if (!rawhextx.empty()) {
result.push_back(Pair("hextx", rawhextx));
result.push_back(Pair("hex", rawhextx));
}
else {
std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl;
@@ -868,10 +830,10 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount
uint256 latesttxid, tokenid = zeroid;
uint8_t funcId;
std::string heirName;
std::string heirName, memo;
uint8_t hasHeirSpendingBegun = 0;
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) {
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun)) != zeroid) {
if (tokenid == zeroid) {
int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN);
if (amount <= 0) {
@@ -880,8 +842,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirAdd<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
return _HeirAdd<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun);
}
else {
int64_t amount = atoll(strAmount.c_str());
@@ -891,7 +852,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirAdd<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
return _HeirAdd<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun);
}
}
else {
@@ -910,7 +871,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount
* creates tx to spend funds from cryptocondition address by either funds' owner or heir
* @return result object with raw tx or error text
*/
template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint8_t hasHeirSpendingBegun)
{
UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -1008,7 +969,7 @@ template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee
if (!rawhextx.empty()) {
result.push_back(Pair("result", "success"));
result.push_back(Pair("hextx", rawhextx));
result.push_back(Pair("hex", rawhextx));
}
else {
std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl;
@@ -1038,10 +999,10 @@ UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmou
uint256 latesttxid, tokenid = zeroid;
uint8_t funcId;
std::string heirName;
std::string heirName, memo;
uint8_t hasHeirSpendingBegun = 0;
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) {
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun)) != zeroid) {
if (tokenid == zeroid) {
int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN);
if (amount < 0) {
@@ -1050,7 +1011,7 @@ UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmou
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirClaim<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
return _HeirClaim<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun);
}
else {
int64_t amount = atoll(strAmount.c_str());
@@ -1060,7 +1021,7 @@ UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmou
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirClaim<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
return _HeirClaim<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun);
}
}
@@ -1092,14 +1053,14 @@ UniValue HeirInfo(uint256 fundingtxid)
//char markeraddr[64];
//CCtxidaddr(markeraddr, fundingtxid);
//SetCCunspents(unspentOutputs, markeraddr);
//SetCCunspents(unspentOutputs, markeraddr,true);
// get initial funding tx and set it as initial lasttx:
if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) {
CPubKey ownerPubkey, heirPubkey;
uint256 dummyTokenid, tokenid = zeroid; // important to clear tokenid
std::string heirName;
std::string heirName, memo;
int64_t inactivityTimeSec;
const bool noLogging = false;
uint8_t funcId;
@@ -1118,7 +1079,7 @@ UniValue HeirInfo(uint256 fundingtxid)
uint8_t hasHeirSpendingBegun = 0;
uint256 latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
uint256 latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun);
if (latestFundingTxid != zeroid) {
int32_t numblocks;
@@ -1159,12 +1120,22 @@ UniValue HeirInfo(uint256 fundingtxid)
else
total = LifetimeHeirContractFunds<TokenHelper>(cp, fundingtxid, ownerPubkey, heirPubkey);
msg = "type";
if (tokenid == zeroid) {
stream << "coins";
}
else {
stream << "tokens";
}
result.push_back(Pair(msg, stream.str().c_str()));
stream.str("");
stream.clear();
msg = "lifetime";
if (tokenid == zeroid) {
msg = "funding total in coins";
stream << std::fixed << std::setprecision(8) << (double)total / COIN;
}
else {
msg = "funding total in tokens";
stream << total;
}
result.push_back(Pair(msg, stream.str().c_str()));
@@ -1177,12 +1148,11 @@ UniValue HeirInfo(uint256 fundingtxid)
else
inputs = Add1of2AddressInputs<TokenHelper>(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, 0, 60);
msg = "available";
if (tokenid == zeroid) {
msg = "funding available in coins";
stream << std::fixed << std::setprecision(8) << (double)inputs / COIN;
}
else {
msg = "funding available in tokens";
stream << inputs;
}
result.push_back(Pair(msg, stream.str().c_str()));
@@ -1192,14 +1162,14 @@ UniValue HeirInfo(uint256 fundingtxid)
if (tokenid != zeroid) {
int64_t ownerInputs = TokenHelper::addOwnerInputs(tokenid, mtx, ownerPubkey, 0, (int32_t)64);
stream << ownerInputs;
msg = "owner funding available in tokens";
msg = "OwnerRemainderTokens";
result.push_back(Pair(msg, stream.str().c_str()));
stream.str("");
stream.clear();
}
stream << inactivityTimeSec;
result.push_back(Pair("inactivity time setting, sec", stream.str().c_str()));
result.push_back(Pair("InactivityTimeSetting", stream.str().c_str()));
stream.str("");
stream.clear();
@@ -1209,18 +1179,20 @@ UniValue HeirInfo(uint256 fundingtxid)
}
stream << std::boolalpha << (hasHeirSpendingBegun || durationSec > inactivityTimeSec);
result.push_back(Pair("spending allowed for the heir", stream.str().c_str()));
result.push_back(Pair("IsHeirSpendingAllowed", stream.str().c_str()));
stream.str("");
stream.clear();
// adding owner current inactivity time:
if (!hasHeirSpendingBegun && durationSec <= inactivityTimeSec) {
stream << durationSec;
result.push_back(Pair("owner inactivity time, sec", stream.str().c_str()));
result.push_back(Pair("InactivityTime", stream.str().c_str()));
stream.str("");
stream.clear();
}
result.push_back(Pair("memo", memo.c_str()));
result.push_back(Pair("result", "success"));
}
else {
@@ -1246,7 +1218,7 @@ void _HeirList(struct CCcontract_info *cp, UniValue &result)
char markeraddr[64];
GetCCaddress(cp, markeraddr, GetUnspendable(cp, NULL));
SetCCunspents(unspentOutputs, markeraddr);
SetCCunspents(unspentOutputs, markeraddr,true);
//std::cerr << "HeirList() finding heir marker from unspendable addr=" << markeraddr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n';
@@ -1262,18 +1234,18 @@ void _HeirList(struct CCcontract_info *cp, UniValue &result)
CTransaction fundingtx;
if (GetTransaction(txid, fundingtx, hashBlock, false)) {
CPubKey ownerPubkey, heirPubkey;
std::string heirName;
std::string heirName, memo;
int64_t inactivityTimeSec;
const bool noLogging = true;
uint256 tokenid;
CScript opret = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript();
uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, true);
// note: if it is not Heir token funcId would be equal to 0
if (funcId == 'F') {
//result.push_back(Pair("fundingtxid kind name", txid.GetHex() + std::string(" ") + (typeid(Helper) == typeid(TokenHelper) ? std::string("token") : std::string("coin")) + std::string(" ") + heirName));
result.push_back( Pair("fundingtxid", txid.GetHex()) );
result.push_back( txid.GetHex() );
}
else {
std::cerr << "HeirList() this is not the initial F transaction=" << txid.GetHex() << std::endl;
@@ -1288,17 +1260,14 @@ void _HeirList(struct CCcontract_info *cp, UniValue &result)
UniValue HeirList()
{
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "success"));
UniValue result(UniValue::VARR);
//result.push_back(Pair("result", "success"));
//result.push_back(Pair("name", "Heir List"));
struct CCcontract_info *cpHeir, *cpTokens, heirC, tokenC; // NOTE we must use a separate 'C' structure for each CCinit!
struct CCcontract_info *cpHeir, heirC;
cpHeir = CCinit(&heirC, EVAL_HEIR);
//cpTokens = CCinit(&tokenC, EVAL_TOKENS);
_HeirList(cpHeir, result);
//_HeirList<TokenHelper>(cpTokens, result); not used anymore
return result;
}

View File

@@ -7,13 +7,13 @@
#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);
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);
//uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false);
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false);
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, bool noLogging = false);
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging = false);
inline static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); }
@@ -28,14 +28,14 @@ public:
return AddNormalinputs(mtx, ownerPubkey, total, maxinputs);
}
static CScript makeCreateOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) {
return EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName);
static CScript makeCreateOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) {
return CScript() << OP_RETURN << EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo);
}
static CScript makeAddOpRet(uint256 dummyid, std::vector<CPubKey> 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<CPubKey> 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);
@@ -51,8 +51,11 @@ public:
cpHeir = CCinit(&heirC, EVAL_HEIR);
return GetCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey);
}
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) {
CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr);
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr)
{
uint8_t mypriv[32];
Myprivkey(mypriv);
CCaddr1of2set(cp, ownerPubkey, heirPubkey,mypriv, coinaddr);
}
};
@@ -66,17 +69,17 @@ public:
return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs);
}
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) {
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> 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));
std::make_pair(OPRETID_HEIRDATA, EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo)));
}
static CScript makeAddOpRet(uint256 tokenid, std::vector<CPubKey> 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<CPubKey> 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) {
@@ -407,10 +410,10 @@ public:
//std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl;
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTime;
std::string heirName;
std::string heirName, memo;
uint256 tokenid;
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
if (funcId == 0) {
message = m_customMessage + std::string(" invalid opreturn format");
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
@@ -462,13 +465,13 @@ public:
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTime;
std::string heirName;
std::string heirName, memo;
uint256 tokenid;
///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl;
// get both pubkeys:
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
if (funcId == 0) {
message = std::string("invalid opreturn format");
return false;
@@ -522,11 +525,11 @@ public:
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTime;
std::string heirName;
std::string heirName, memo;
uint256 tokenid;
// get heir pubkey:
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
if (funcId == 0) {
message = std::string("invalid opreturn format");
return false;

View File

@@ -19,77 +19,366 @@
#include "crosschain.h"
#include "primitives/transaction.h"
#include "cc/CCinclude.h"
#include <openssl/sha.h>
/*
* CC Eval method for import coin.
*
* This method should control every parameter of the ImportCoin transaction, since it has no signature
* to protect it from malleability.
##### 0xffffffff is a special CCid for single chain/dual daemon imports
*/
#include "key_io.h"
#define CODA_BURN_ADDRESS "KPrrRoPfHOnNpZZQ6laHXdQDkSQDkVHaN0V+LizLlHxz7NaA59sBAAAA"
extern std::string ASSETCHAINS_SELFIMPORT;
extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT;
extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33];
int32_t GetSelfimportProof(std::string source,CMutableTransaction &mtx,CScript &scriptPubKey,TxProof &proof,uint64_t burnAmount,std::vector<uint8_t> rawtx,uint256 txid,std::vector<uint8_t> rawproof) // find burnTx with hash from "other" daemon
// utilities from gateways.cpp
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids);
uint256 GatewaysReverseScan(uint256 &txid, int32_t height, uint256 reforacletxid, uint256 batontxid);
int32_t GatewaysCointxidExists(struct CCcontract_info *cp, uint256 cointxid);
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<CPubKey> &gatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype);
char *nonportable_path(char *str);
char *portable_path(char *str);
void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep);
void *filestr(long *allocsizep,char *_fname);
// ac_import=chain support:
// encode opret for gateways import
CScript EncodeImportTxOpRet(uint32_t targetCCid, std::string coin, std::vector<CPubKey> publishers, std::vector<uint256>txids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vector<uint8_t>proof, CPubKey destpub, int64_t amount)
{
MerkleBranch newBranch; CMutableTransaction tmpmtx; CTransaction tx,vintx; uint256 blockHash; char destaddr[64],pkaddr[64];
tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),komodo_nextheight());
if ( source == "BEAM" )
CScript opret;
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount);
return(opret);
}
CScript EncodeGatewaysImportTxOpRet(uint32_t targetCCid, std::string coin, uint256 bindtxid, std::vector<CPubKey> publishers, std::vector<uint256>txids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vector<uint8_t>proof, CPubKey destpub, int64_t amount)
{
CScript opret;
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount);
return(opret);
}
CScript EncodeCodaImportTxOpRet(uint32_t targetCCid, std::string coin, std::string burntx, uint256 bindtxid, CPubKey destpub, int64_t amount)
{
CScript opret;
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << burntx << bindtxid << destpub << amount);
return(opret);
}
cJSON* CodaRPC(char **retstr,char const *arg0,char const *arg1,char const *arg2,char const *arg3,char const *arg4,char const *arg5)
{
char cmdstr[5000],fname[256],*jsonstr;
long fsize;
cJSON *retjson=NULL;
sprintf(fname,"/tmp/coda.%s",arg0);
sprintf(cmdstr,"coda.exe client %s %s %s %s %s %s > %s 2>&1",arg0,arg1,arg2,arg3,arg4,arg5,fname);
*retstr = 0;
if (system(cmdstr)<0) return (retjson);
if ( (jsonstr=(char *)filestr(&fsize,fname)) != 0 )
{
if ( ASSETCHAINS_BEAMPORT == 0 )
return(-1);
// confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn
// return(0);
jsonstr[strlen(jsonstr)-1]='\0';
if ( (strncmp(jsonstr,"Merkle List of transactions:",28)!=0) || (retjson= cJSON_Parse(jsonstr+29)) == 0)
*retstr=jsonstr;
else free(jsonstr);
}
else if ( source == "CODA" )
return(retjson);
}
bool ImportCoinGatewaysVerify(CTransaction oracletx, int32_t claimvout, std::string refcoin, uint256 burntxid, const std::string rawburntx, std::vector<uint8_t>proof, uint256 merkleroot)
{
std::vector<uint256> txids;
uint256 proofroot;
std::string name, description, format;
int32_t i, numvouts;
if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey, name, description, format) != 'C' || name != refcoin)
{
if ( ASSETCHAINS_CODAPORT == 0 )
return(-1);
// confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn
// return(0);
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched oracle name=" << name.c_str() << " != " << refcoin.c_str() << std::endl);
return false;
}
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in trusted merkleroot" << std::endl);
return true;
}
// make import tx with burntx and its proof of existence
// std::string MakeGatewaysImportTx(uint64_t txfee, uint256 oracletxid, int32_t height, std::string refcoin, std::vector<uint8_t> proof, std::string rawburntx, int32_t ivout, uint256 burntxid,std::string destaddr)
// {
// CMutableTransaction burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
// CTransaction oracletx,regtx; CPubKey regpk;
// uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts;
// std::string name,desc,format; std::vector<CTxOut> vouts;
// std::vector<CPubKey> pubkeys; std::vector<uint256>txids;
// char markeraddr[64]; int64_t datafee;
// std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
// if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx))
// return std::string("");
// CAmount amount = GetCoinImportValue(burntx); // equal to int64_t
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx height=" << height << " coin=" << refcoin << " amount=" << (double)amount / COIN << " pubkeys num=" << pubkeys.size() << std::endl);
// if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0)
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx cant find oracletxid=" << oracletxid.GetHex() << std::endl);
// return("");
// }
// if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C')
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl);
// return("");
// }
// if (name!=refcoin || format!="Ihh")
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl);
// return("");
// }
// CCtxidaddr(markeraddr,oracletxid);
// SetCCunspents(unspentOutputs,markeraddr,true);
// for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
// {
// txid = it->first.txhash;
// if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0
// && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid )
// {
// pubkeys.push_back(regpk);
// n++;
// }
// }
// merkleroot = zeroid;
// for (i = m = 0; i < n; i++)
// {
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx using pubkeys[" << i << "]=" << HexStr(pubkeys[i]) << std::endl);
// if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid)
// {
// if (merkleroot == zeroid)
// merkleroot = mhash, m = 1;
// else if (mhash == merkleroot)
// m ++;
// txids.push_back(txid);
// }
// }
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " nodes m=" << m << " of n=" << n << std::endl);
// if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl );
// return("");
// }
// proofroot = BitcoinGetProofMerkleRoot(proof, txids);
// if (proofroot != merkleroot)
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl);
// return("");
// }
// // check the burntxid is in the proof:
// if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid proof for this burntxid=" << burntxid.GetHex() << std::endl);
// return("");
// }
// burntx.vout.push_back(MakeBurnOutput(amount,0xffffffff,refcoin,vouts,proof,oracletxid,height));
// std::vector<uint256> leaftxids;
// BitcoinGetProofMerkleRoot(proof, leaftxids);
// MerkleBranch newBranch(0, leaftxids);
// TxProof txProof = std::make_pair(burntxid, newBranch);
// CTxDestination dest = DecodeDestination(destaddr.c_str());
// CScript scriptPubKey = GetScriptForDestination(dest);
// vouts.push_back(CTxOut(amount,scriptPubKey));
// return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts)));
// }
// makes source tx for self import tx
std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx)
{
const int64_t txfee = 10000;
int64_t inputs, change;
CPubKey myPubKey = Mypubkey();
struct CCcontract_info *cpDummy, C;
cpDummy = CCinit(&C, EVAL_TOKENS);
mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
if( (inputs = AddNormalinputs(mtx, myPubKey, txfee, 4)) == 0 ) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeSelfImportSourceTx: cannot find normal imputs for txfee" << std::endl);
return std::string("");
}
CScript scriptPubKey = GetScriptForDestination(dest);
mtx.vout.push_back(CTxOut(txfee, scriptPubKey));
change = inputs - txfee;
if( change != 0 )
mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG));
//make opret with amount:
return FinalizeCCTx(0, cpDummy, mtx, myPubKey, txfee, CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN << (uint8_t)'A' << amount));
}
// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33
int32_t CheckVin0PubKey(const CTransaction &sourcetx)
{
CTransaction vintx;
uint256 blockHash;
char destaddr[64], pkaddr[64];
if( !myGetTransaction(sourcetx.vin[0].prevout.hash, vintx, blockHash) ) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() could not load vintx" << sourcetx.vin[0].prevout.hash.GetHex() << std::endl);
return(-1);
}
if( sourcetx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[0].prevout.n].scriptPubKey) != 0 )
{
pubkey2addr(pkaddr, ASSETCHAINS_OVERRIDE_PUBKEY33);
if (strcmp(pkaddr, destaddr) == 0) {
return(0);
}
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() mismatched vin0[prevout.n=" << sourcetx.vin[0].prevout.n << "] -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl);
}
return -1;
}
// ac_import=PUBKEY support:
// prepare a tx for creating import tx and quasi-burn tx
int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount) // find burnTx with hash from "other" daemon
{
MerkleBranch newBranch;
CMutableTransaction tmpmtx;
CTransaction sourcetx;
tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
if (!E_UNMARSHAL(ParseHex(rawsourcetx), ss >> sourcetx)) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: could not unmarshal source tx" << std::endl);
return(-1);
}
if (sourcetx.vout.size() == 0) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: vout size is 0" << std::endl);
return -1;
}
if (ivout < 0) { // "ivout < 0" means "find"
// try to find vout
CPubKey myPubkey = Mypubkey();
ivout = 0;
// skip change:
if (sourcetx.vout[ivout].scriptPubKey == (CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG))
ivout++;
}
if (ivout >= sourcetx.vout.size()) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: needed vout not found" << std::endl);
return -1;
}
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "GetSelfimportProof: using vout[" << ivout << "] of the passed rawtx" << std::endl);
scriptPubKey = sourcetx.vout[ivout].scriptPubKey;
//mtx is template for import tx
mtx = sourcetx;
mtx.fOverwintered = tmpmtx.fOverwintered;
//malleability fix for burn tx:
//mtx.nExpiryHeight = tmpmtx.nExpiryHeight;
mtx.nExpiryHeight = sourcetx.nExpiryHeight;
mtx.nVersionGroupId = tmpmtx.nVersionGroupId;
mtx.nVersion = tmpmtx.nVersion;
mtx.vout.clear();
mtx.vout.resize(1);
mtx.vout[0].nValue = burnAmount;
mtx.vout[0].scriptPubKey = scriptPubKey;
// not sure we need this now as we create sourcetx ourselves:
if (sourcetx.GetHash() != sourcetxid) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: passed source txid incorrect" << std::endl);
return(-1);
}
// check ac_pubkey:
if (CheckVin0PubKey(sourcetx) < 0) {
return -1;
}
proof = std::make_pair(sourcetxid, newBranch);
return 0;
}
// make import tx with burntx and dual daemon
std::string MakeCodaImportTx(uint64_t txfee, std::string receipt, std::string srcaddr, std::vector<CTxOut> vouts)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()),burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk; uint256 codaburntxid; std::vector<unsigned char> dummyproof;
int32_t i,numvouts,n,m; std::string coin,error; struct CCcontract_info *cp, C;
cJSON *result,*tmp,*tmp1; unsigned char hash[SHA256_DIGEST_LENGTH+1];
char out[SHA256_DIGEST_LENGTH*2+1],*retstr,*destaddr,*receiver; TxProof txProof; uint64_t amount;
cp = CCinit(&C, EVAL_GATEWAYS);
if (txfee == 0)
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, receipt.c_str(), receipt.size());
SHA256_Final(hash, &sha256);
for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
sprintf(out + (i * 2), "%02x", hash[i]);
}
out[65]='\0';
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: hash=" << out << std::endl);
codaburntxid.SetHex(out);
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: receipt=" << receipt << " codaburntxid=" << codaburntxid.GetHex().data() << " amount=" << (double)amount / COIN << std::endl);
result=CodaRPC(&retstr,"prove-payment","-address",srcaddr.c_str(),"-receipt-chain-hash",receipt.c_str(),"");
if (result==0)
{
if (retstr!=0)
{
CCerror=std::string("CodaRPC: ")+retstr;
free(retstr);
}
return("");
}
else
{
if ( !E_UNMARSHAL(rawtx, ss >> tx) )
return(-1);
scriptPubKey = tx.vout[0].scriptPubKey;
mtx = tx;
mtx.fOverwintered = tmpmtx.fOverwintered;
mtx.nExpiryHeight = tmpmtx.nExpiryHeight;
mtx.nVersionGroupId = tmpmtx.nVersionGroupId;
mtx.nVersion = tmpmtx.nVersion;
mtx.vout.clear();
mtx.vout.resize(1);
mtx.vout[0].nValue = burnAmount;
mtx.vout[0].scriptPubKey = scriptPubKey;
if ( tx.GetHash() != txid )
return(-1);
if ( source == "PUBKEY" )
if ((tmp=jobj(jitem(jarray(&n,result,(char *)"payments"),0),(char *)"payload"))!=0 && (destaddr=jstr(jobj(tmp,(char *)"common"),(char *)"memo"))!=0 &&
(receiver=jstr(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"receiver"))!=0 && (amount=j64bits(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"amount"))!=0)
{
// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33
if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,blockHash) == 0 )
return(-1);
if ( tx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr,vintx.vout[tx.vin[0].prevout.n].scriptPubKey) != 0 )
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: receiver=" << receiver << " destaddr=" << destaddr << " amount=" << amount << std::endl);
if (strcmp(receiver,CODA_BURN_ADDRESS)!=0)
{
pubkey2addr(pkaddr,ASSETCHAINS_OVERRIDE_PUBKEY33);
if ( strcmp(pkaddr,destaddr) == 0 )
{
proof = std::make_pair(txid,newBranch);
return(0);
}
fprintf(stderr,"mismatched vin0[%d] -> %s vs %s\n",tx.vin[0].prevout.n,destaddr,pkaddr);
CCerror="MakeCodaImportTx: invalid burn address, coins do not go to predefined burn address - ";
CCerror+=CODA_BURN_ADDRESS;
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
free(result);
return("");
}
CTxDestination dest = DecodeDestination(destaddr);
CScript scriptPubKey = GetScriptForDestination(dest);
if (vouts[0]!=CTxOut(amount*COIN,scriptPubKey))
{
CCerror="MakeCodaImportTx: invalid destination address, burnTx memo!=importTx destination";
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
free(result);
return("");
}
if (amount*COIN!=vouts[0].nValue)
{
CCerror="MakeCodaImportTx: invalid amount, burnTx amount!=importTx amount";
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
free(result);
return("");
}
burntx.vin.push_back(CTxIn(codaburntxid,0,CScript()));
burntx.vout.push_back(MakeBurnOutput(amount*COIN,0xffffffff,"CODA",vouts,dummyproof,srcaddr,receipt));
return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof,burntx,vouts)));
}
else if ( source == ASSETCHAINS_SELFIMPORT )
else
{
// source is external coin is the assetchains symbol in the burnTx OP_RETURN
// burnAmount, rawtx and rawproof should be enough for gatewaysdeposit equivalent
CCerror="MakeCodaImportTx: invalid Coda burn tx";
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
free(result);
return("");
}
}
return(-1);
CCerror="MakeCodaImportTx: error fetching Coda tx";
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
free(result);
return("");
}
// use proof from the above functions to validate the import
@@ -100,31 +389,202 @@ int32_t CheckBEAMimport(TxProof proof,std::vector<uint8_t> rawproof,CTransaction
return(-1);
}
int32_t CheckCODAimport(TxProof proof,std::vector<uint8_t> rawproof,CTransaction burnTx,std::vector<CTxOut> payouts)
int32_t CheckCODAimport(CTransaction importTx,CTransaction burnTx,std::vector<CTxOut> payouts,std::string srcaddr,std::string receipt)
{
cJSON *result,*tmp,*tmp1; char *retstr,out[SHA256_DIGEST_LENGTH*2+1]; unsigned char hash[SHA256_DIGEST_LENGTH+1]; int i,n,m;
SHA256_CTX sha256; uint256 codaburntxid; char *destaddr,*receiver; uint64_t amount;
// check with dual-CODA daemon via ASSETCHAINS_CODAPORT for validity of burnTx
return(-1);
SHA256_Init(&sha256);
SHA256_Update(&sha256, receipt.c_str(), receipt.size());
SHA256_Final(hash, &sha256);
for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
sprintf(out + (i * 2), "%02x", hash[i]);
}
out[65]='\0';
codaburntxid.SetHex(out);
result=CodaRPC(&retstr,"prove-payment","-address",srcaddr.c_str(),"-receipt-chain-hash",receipt.c_str(),"");
if (result==0)
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CodaRPC error: " << retstr << std::endl);
free(retstr);
return (-1);
}
else
{
if ((tmp=jobj(jitem(jarray(&n,result,(char *)"payments"),0),(char *)"payload"))==0 || (destaddr=jstr(jobj(tmp,(char *)"common"),(char *)"memo"))==0 ||
(receiver=jstr(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"receiver"))==0 || (amount=j64bits(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"amount"))==0)
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid Coda burn tx" << jprint(result,1) << std::endl);
free(result);
return (-1);
}
CTxDestination dest = DecodeDestination(destaddr);
CScript scriptPubKey = GetScriptForDestination(dest);
if (payouts[0]!=CTxOut(amount*COIN,scriptPubKey));
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Destination address in burn tx does not match destination in import tx" << std::endl);
free(result);
return (-1);
}
if (strcmp(receiver,CODA_BURN_ADDRESS)!=0)
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid burn address " << jstr(tmp1,(char *)"receiver") << std::endl);
free(result);
return (-1);
}
if (amount*COIN!=payouts[0].nValue)
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Burn amount and import amount not matching, " << j64bits(tmp,(char *)"amount") << " - " << payouts[0].nValue/COIN << std::endl);
free(result);
return (-1);
}
if (burnTx.vin[0].prevout.hash!=codaburntxid || importTx.vin[0].prevout.hash!=burnTx.GetHash())
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid import/burn tx vin" << std::endl);
free(result);
return (-1);
}
free(result);
}
return(0);
}
int32_t CheckGATEWAYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransaction burnTx,std::vector<CTxOut> payouts)
int32_t CheckGATEWAYimport(CTransaction importTx,CTransaction burnTx,std::string refcoin,std::vector<uint8_t> proof,
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256> txids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub)
{
// CTransaction oracletx,regtx; CPubKey regpk;
// uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts;
// std::string name,desc,format; std::vector<CTxOut> vouts;
// std::vector<CPubKey> pubkeys; std::vector<uint256>txids;
// char markeraddr[64]; int64_t datafee;
// std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
// ASSETCHAINS_SELFIMPORT is coin
// check for valid burn from external coin blockchain and if valid return(0);
return(-1);
// if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0)
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport cant find oracletxid=" << oracletxid.GetHex() << std::endl);
// return(-1);
// }
// if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C')
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl);
// return(-1);
// }
// if (name!=refcoin || format!="Ihh")
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl);
// return(-1);
// }
// CCtxidaddr(markeraddr,oracletxid);
// SetCCunspents(unspentOutputs,markeraddr,true);
// for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
// {
// txid = it->first.txhash;
// if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0
// && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid )
// {
// pubkeys.push_back(regpk);
// n++;
// }
// }
// merkleroot = zeroid;
// for (i = m = 0; i < n; i++)
// {
// if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid)
// {
// if (merkleroot == zeroid)
// merkleroot = mhash, m = 1;
// else if (mhash == merkleroot)
// m ++;
// txids.push_back(txid);
// }
// }
// if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl );
// return(-1);
// }
// proofroot = BitcoinGetProofMerkleRoot(proof, txids);
// if (proofroot != merkleroot)
// {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl);
// return(-1);
// }
// // check the burntxid is in the proof:
// if (std::find(txids.begin(), txids.end(), burnTx.GetHash()) == txids.end()) {
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid proof for this burntxid=" << burnTx.GetHash().GetHex() << std::endl);
// return(-1);
// }
return(0);
}
int32_t CheckPUBKEYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransaction burnTx,std::vector<CTxOut> payouts)
{
// if burnTx has ASSETCHAINS_PUBKEY vin, it is valid return(0);
fprintf(stderr,"proof txid.%s\n",proof.first.GetHex().c_str());
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "proof txid=" << proof.first.GetHex() << std::endl);
uint256 sourcetxid = proof.first, hashBlock;
CTransaction sourcetx;
if (!myGetTransaction(sourcetxid, sourcetx, hashBlock)) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "could not load source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
if (sourcetx.vout.size() == 0) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "no vouts in source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
// might be malleable:
if (burnTx.nExpiryHeight != sourcetx.nExpiryHeight) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "burntx nExpiryHeight incorrect for source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
//ac_pubkey check:
if (CheckVin0PubKey(sourcetx) < 0) {
return -1;
}
// get source tx opret:
std::vector<uint8_t> vopret;
uint8_t evalCode, funcId;
int64_t amount;
GetOpReturnData(sourcetx.vout.back().scriptPubKey, vopret);
if (vopret.size() == 0 || !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> amount) || evalCode != EVAL_IMPORTCOIN || funcId != 'A') {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "no or incorrect opret to validate in source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "importTx amount=" << payouts[0].nValue << " burnTx amount=" << burnTx.vout[0].nValue << " opret amount=" << amount << " source txid=" << sourcetxid.GetHex() << std::endl);
// amount malleability check with the opret from the source tx:
if (payouts[0].nValue != amount) { // assume that burntx amount is checked in the common code in Eval::ImportCoin()
LOGSTREAM("importcoin", CCLOG_INFO, stream << "importTx amount != amount in the opret of source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
return(0);
return(-1);
}
/*
* CC Eval method for import coin.
*
* This method should control every parameter of the ImportCoin transaction, since it has no signature
* to protect it from malleability.
##### 0xffffffff is a special CCid for single chain/dual daemon imports
*/
bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &importTx,unsigned int nIn)
{
TxProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; uint64_t txfee = 10000;
uint32_t targetCcid; std::string targetSymbol; uint256 payoutsHash; std::vector<uint8_t> rawproof;
TxProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; uint64_t txfee = 10000; int32_t height,burnvout; std::vector<CPubKey> publishers;
uint32_t targetCcid; std::string targetSymbol,srcaddr,destaddr,receipt,rawburntx; uint256 payoutsHash,bindtxid; std::vector<uint8_t> rawproof;
std::vector<uint256> txids; CPubKey destpub;
if ( importTx.vout.size() < 2 )
return Invalid("too-few-vouts");
// params
@@ -132,10 +592,10 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
return Invalid("invalid-params");
// Control all aspects of this transaction
// It should not be at all malleable
if (MakeImportCoinTransaction(proof, burnTx, payouts).GetHash() != importTx.GetHash())
if (MakeImportCoinTransaction(proof, burnTx, payouts, importTx.nExpiryHeight).GetHash() != importTx.GetHash()) // ExistsImportTombstone prevents from duplication
return Invalid("non-canonical");
// burn params
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash,rawproof))
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash, rawproof))
return Invalid("invalid-burn-tx");
// check burn amount
{
@@ -175,7 +635,7 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
{
if ( ASSETCHAINS_CODAPORT == 0 )
return Invalid("CODA-import-without-port");
else if ( CheckCODAimport(proof,rawproof,burnTx,payouts) < 0 )
else if ( UnmarshalBurnTx(burnTx,srcaddr,receipt)==0 || CheckCODAimport(importTx,burnTx,payouts,srcaddr,receipt) < 0 )
return Invalid("CODA-import-failure");
}
else if ( targetSymbol == "PUBKEY" )
@@ -189,11 +649,9 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
{
if ( targetSymbol != ASSETCHAINS_SELFIMPORT )
return Invalid("invalid-gateway-import-coin");
else if ( CheckGATEWAYimport(proof,rawproof,burnTx,payouts) < 0 )
else if ( UnmarshalBurnTx(burnTx,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub)==0 || CheckGATEWAYimport(importTx,burnTx,targetSymbol,rawproof,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub) < 0 )
return Invalid("GATEWAY-import-failure");
}
}
return Valid();
}

1292
src/cc/importgateway.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -35,8 +35,8 @@
* *
******************************************************************************/
#ifndef cJSON__h
#define cJSON__h
#ifndef cJSON__ccih
#define cJSON__ccih
#include <stdio.h>
#include <stdlib.h>

View File

@@ -166,7 +166,7 @@ int64_t AddLottoInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -209,7 +209,7 @@ int64_t LottoPlanFunds(uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,u
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
lockedfunds = 0;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -266,7 +266,7 @@ UniValue LottoList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,hentropy; CTransaction vintx; uint64_t sbits; int32_t ticketsize,odds,firstheight,period; char str[65];
cp = CCinit(&C,EVAL_LOTTO);
SetCCtxids(addressIndex,cp->normaladdr);
SetCCtxids(addressIndex,cp->normaladdr,true);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;

View File

@@ -1 +1,19 @@
gcc -std=c++11 -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../cclib.so cclib.cpp
#!/bin/sh
rm *.so rogue/rogue games/tetris games/prices
echo rogue
make -f Makefile_rogue
./makerogue
echo sudoku/musig/dilithium
gcc -O3 -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 sudokucc.so cclib.cpp
echo games tetris
./maketetris
echo games prices
./makeprices
echo customcc stub
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

7
src/cc/makecustom Executable file
View File

@@ -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

7
src/cc/makegames Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/sh
gcc -O3 -DBUILD_GAMESCC -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 gamescc.so cclib.cpp
cp gamescc.so ../libcc.so
cd ..
make
cd cc

8
src/cc/makeprices Executable file
View File

@@ -0,0 +1,8 @@
echo pricescc.so
gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -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 pricescc.so cclib.cpp
echo prices
cd games
gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE -DBUILD_PRICES ../gamescc.cpp -lncurses -lcurl -o prices
cd ..

37
src/cc/makerogue Executable file
View File

@@ -0,0 +1,37 @@
#!/bin/sh
cd rogue;
make clean;
if [ "$HOST" = "x86_64-w64-mingw32" ]; then
echo building rogue.exe...
./configure --host=x86_64-w64-mingw32
echo $PWD
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
echo $PWD
if make -f Makefile_win "$@"; then
echo rogue.exe build SUCCESSFUL
cd ..
else
echo rogue.exe build FAILED
exit 1
fi
else
echo building rogue...
./configure
if make "$@"; then
echo rogue build SUCCESSFUL
cd ..
else
echo rogue build FAILED
exit 1
fi
fi
if make -f Makefile_rogue "$@"; then
echo ROGUE BUILD SUCCESSFUL
else
echo ROGUE BUILD FAILED
exit 1
fi

7
src/cc/maketetris Executable file
View File

@@ -0,0 +1,7 @@
echo gamescc.so with tetris
gcc -O3 -DBUILD_GAMESCC -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 gamescc.so cclib.cpp
echo tetris dapp
cd games
gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE ../gamescc.cpp -lncurses -lcurl -o tetris
cd ..

View File

@@ -167,7 +167,7 @@ int32_t MarmaraGetbatontxid(std::vector<uint256> &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);
@@ -352,7 +352,7 @@ int64_t AddMarmaraCoinbases(struct CCcontract_info *cp,CMutableTransaction &mtx,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
Marmarapk = GetUnspendable(cp,0);
GetCCaddress1of2(cp,coinaddr,Marmarapk,poolpk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
unlocks = MarmaraUnlockht(firstheight);
//fprintf(stderr,"check coinaddr.(%s)\n",coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
@@ -366,7 +366,7 @@ int64_t AddMarmaraCoinbases(struct CCcontract_info *cp,CMutableTransaction &mtx,
{
if ( DecodeMaramaraCoinbaseOpRet(vintx.vout[1].scriptPubKey,pk,ht,unlockht) == 'C' && unlockht == unlocks && pk == poolpk && ht >= firstheight )
{
if ( (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -387,15 +387,19 @@ int64_t AddMarmarainputs(CMutableTransaction &mtx,std::vector<CPubKey> &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<int64_t> vals;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
SetCCunspents(unspentOutputs,coinaddr,true);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( it->second.satoshis < threshold )
continue;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && vout < numvouts && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && vout < numvouts && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( (funcid= DecodeMaramaraCoinbaseOpRet(tx.vout[numvouts-1].scriptPubKey,pk,ht,unlockht)) == 'C' || funcid == 'P' || funcid == 'L' )
{
@@ -437,7 +441,7 @@ UniValue MarmaraLock(uint64_t txfee,int64_t amount,int32_t height)
mypk = pubkey2pk(Mypubkey());
Marmarapk = GetUnspendable(cp,0);
Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG);
if ( (val= CCaddress_balance(coinaddr)) < amount )
if ( (val= CCaddress_balance(coinaddr,0)) < amount )
val -= txfee;
else val = amount;
if ( val > txfee )
@@ -453,16 +457,18 @@ UniValue MarmaraLock(uint64_t txfee,int64_t amount,int32_t height)
remains = (amount + txfee) - inputsum;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress1of2(cp,coinaddr,Marmarapk,mypk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
threshold = remains / (MARMARA_VINS+1);
CCaddr1of2set(cp,Marmarapk,mypk,coinaddr);
uint8_t mypriv[32];
Myprivkey(mypriv);
CCaddr1of2set(cp,Marmarapk,mypk,mypriv,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( (nValue= it->second.satoshis) < threshold )
continue;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && vout < numvouts && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && vout < numvouts && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( (funcid= DecodeMaramaraCoinbaseOpRet(tx.vout[numvouts-1].scriptPubKey,pk,ht,unlockht)) == 'C' || funcid == 'P' || funcid == 'L' )
{
@@ -660,7 +666,7 @@ int32_t MarmaraGetCreditloops(int64_t &totalamount,std::vector<uint256> &issuanc
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
Marmarapk = GetUnspendable(cp,0);
GetCCaddress(cp,coinaddr,Marmarapk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
// do all txid, conditional on spent/unspent
//fprintf(stderr,"check coinaddr.(%s)\n",coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
@@ -1053,16 +1059,16 @@ UniValue MarmaraInfo(CPubKey refpk,int32_t firstheight,int32_t lastheight,int64_
result.push_back(Pair("result","success"));
Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(Mypubkey())) << OP_CHECKSIG);
result.push_back(Pair("myaddress",coinaddr));
result.push_back(Pair("normal",ValueFromAmount(CCaddress_balance(coinaddr))));
result.push_back(Pair("normal",ValueFromAmount(CCaddress_balance(coinaddr,0))));
GetCCaddress1of2(cp,coinaddr,Marmarapk,Mypubkey());
result.push_back(Pair("myCCactivated",coinaddr));
result.push_back(Pair("activated",ValueFromAmount(CCaddress_balance(coinaddr))));
result.push_back(Pair("activated",ValueFromAmount(CCaddress_balance(coinaddr,1))));
result.push_back(Pair("activated16",ValueFromAmount(AddMarmarainputs(mtx,pubkeys,coinaddr,0,MARMARA_VINS))));
GetCCaddress(cp,coinaddr,Mypubkey());
result.push_back(Pair("myCCaddress",coinaddr));
result.push_back(Pair("CCutxos",ValueFromAmount(CCaddress_balance(coinaddr))));
result.push_back(Pair("CCutxos",ValueFromAmount(CCaddress_balance(coinaddr,1))));
if ( refpk.size() == 33 )
result.push_back(Pair("issuer",HexStr(refpk)));

868
src/cc/musig.cpp Normal file
View File

@@ -0,0 +1,868 @@
/******************************************************************************
* 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. *
* *
******************************************************************************/
/* first make a combined pk:
./komodo-cli -ac_name=MUSIG cclib combine 18 '["02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28","0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4"]'
{
"pkhash": "5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",
"result": "success"
}
the combined_pk and pkhash will be needed for various other rpc calls
second, send 1 coin to the combined_pk
./komodo-cli -ac_name=MUSIG cclib send 18 '["03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",1]'
{
"hex": "0400008085202f8901a980664dffc810725a79ffb89ac48be4c7b6bade9b789732fcf871acf8e81a2e010000006a47304402207e52763661ecd2c34a65d6623950be11794825db71576dc11894c606ddc317800220028fef46dc20630d0fdf22647b5d4ff0f1c47cf75f48702d0a91d5589eff99d001210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ffffffff031008f60500000000302ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cce09aa4350000000023210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac0000000000000000266a2412782103f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b00000000920500000000000000000000000000",
"txid": "5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c",
"result": "success"
}
sendrawtransaction of the above hex.
./komodo-cli -ac_name=MUSIG getrawtransaction 5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c 1
"vout": [
{
"value": 1.00010000,
"valueSat": 100010000,
"n": 0,
"scriptPubKey": {
"asm": "a22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401 OP_CHECKCRYPTOCONDITION",
"hex": "2ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cc",
"reqSigs": 1,
"type": "cryptocondition",
"addresses": [
"RKWS7jxyjPX9iaJttk8iMKf1AumanKypez"
]
}
},
{
"value": 8.99980000,
"valueSat": 899980000,
"n": 1,
"scriptPubKey": {
"asm": "0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4 OP_CHECKSIG",
"hex": "210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac",
"reqSigs": 1,
"type": "pubkey",
"addresses": [
"RVQjvGdRbYLJ49bfH4SAFseipvwE3UdoDw"
]
}
script: 210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac
sendtxid: 5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c
get the msg we need to sign:
./komodo-cli -ac_name=MUSIG cclib calcmsg 18 '["5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c","210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac"]'
{
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75",
"result": "success"
}
the "msg" is what needs to be signed to create a valid spend
now on each signing node, a session needs to be created:
5 args: ind, numsigners, combined_pk, pkhash, message to be signed
on node with pubkey: 02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28
./komodo-cli -ac_name=MUSIG cclib session 18 '[0,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]'
{
"myind": 0,
"numsigners": 2,
"commitment": "bbea1f2562eca01b9a1393c5dc188bdd44551aebf684f4459930f59dde01f7ae",
"result": "success"
}
on node with pubkey: 0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4
./komodo-cli -ac_name=MUSIG cclib session 18 '[1,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]'
{
"myind": 1,
"numsigners": 2,
"commitment": "c2291acb747a75b1a40014d8eb0cc90a1360f74d413f65f78e20a7de45eda851",
"result": "success"
}
now we need to get the commitment from each node to the other one. the session already put the commitment for each node into the global struct. Keep in mind there is a single global struct with session unique to each cclib session call. that means no restarting any deamon in the middle of the process on any of the nodes and only call cclib session a single time. this is an artificial restriction just to simplify the initial implementation of musig
./komodo-cli -ac_name=MUSIG cclib commit 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","c2291acb747a75b1a40014d8eb0cc90a1360f74d413f65f78e20a7de45eda851"]'
{
"added_index": 1,
"myind": 0,
"nonce": "02fec7a9310c959a0a97b86bc3f8c30d392d1fb51793915898c568f73f1f70476b",
"result": "success"
}
./komodo-cli -ac_name=MUSIG cclib commit 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"d242cff13fa8c9b83248e4219fda459ada146b885f2171481f1b0f66c66d94ad"]'
{
"added_index": 0,
"myind": 1,
"nonce": "039365deaaaea089d509ba4c9f846de2baf4aa04cf6b26fa2c1cd818553e47f80c",
"result": "success"
}
Now exchange the revealed nonces to each node:
./komodo-cli -ac_name=MUSIG cclib nonce 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","039365deaaaea089d509ba4c9f846de2baf4aa04cf6b26fa2c1cd818553e47f80c"]'
{
"added_index": 1,
"myind": 0,
"partialsig": "1d65c09cd9bffe4f0604227e66cd7cd221480bbb08262fe885563a9df7cf8f5b",
"result": "success"
}
./komodo-cli -ac_name=MUSIG cclib nonce 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"02fec7a9310c959a0a97b86bc3f8c30d392d1fb51793915898c568f73f1f70476b"]'
{
"added_index": 0,
"myind": 1,
"partialsig": "4a3795e6801b355102c617390cf5a462061e082e35dc2ed8f8b1fab54cc0769e",
"result": "success"
}
Almost there! final step is to exchange the partial sigs between signers
./komodo-cli -ac_name=MUSIG cclib partialsig 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","4a3795e6801b355102c617390cf5a462061e082e35dc2ed8f8b1fab54cc0769e"]'
{
"added_index": 1,
"result": "success",
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"
}
./komodo-cli -ac_name=MUSIG cclib partialsig 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"1d65c09cd9bffe4f0604227e66cd7cd221480bbb08262fe885563a9df7cf8f5b"]'
{
"added_index": 0,
"result": "success",
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"
}
Notice both nodes generated the same combined signature!
Now for a sanity test, we can use the verify call to make sure this sig will work with the msg needed for the spend:
./komodo-cli -ac_name=MUSIG cclib verify 18 '["f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75","03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"]'
{
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75",
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9",
"result": "success"
}
and finally the spend: sendtxid, scriptPubKey, musig
./komodo-cli -ac_name=MUSIG cclib spend 18 '["5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c","210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac","a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"]'
{
"scriptpubkey": "210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac",
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75",
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9",
"hex": "0400008085202f89014c821930f9eb360daaf1a1e12d5a82998b63884e8db4130421ee53a13740e75c000000007b4c79a276a072a26ba067a5658021032d29d6545a2aafad795d9cf50912ecade549137
163934dfb2895ebc0e211ce8a81409671a60db89b3bc58966f3acc80194479b1a43d868e95a11ebc5609646d18710341a8ff92a7817571980307f5d660cc00a2735ac6333e0a7191243f1263f1959a100af03800112
a10001ffffffff0200e1f5050000000023210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac0000000000000000686a4c6512792103f016c348437c7422eed92d865aa9789614f
75327cada463eefc566126b54785b40a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f900000000a805
00000000000000000000000000",
"txid": "910635bf69a047fc90567a83ff12e47b753f470658b6d0855ec96e07e7349a8a",
"result": "success"
}
*/
#define USE_BASIC_CONFIG
#define ENABLE_MODULE_MUSIG
#include "../secp256k1/src/basic-config.h"
#include "../secp256k1/include/secp256k1.h"
#include "../secp256k1/src/ecmult.h"
#include "../secp256k1/src/ecmult_gen.h"
typedef struct { unsigned char data[64]; } secp256k1_schnorrsig;
struct secp256k1_context_struct {
secp256k1_ecmult_context ecmult_ctx;
secp256k1_ecmult_gen_context ecmult_gen_ctx;
secp256k1_callback illegal_callback;
secp256k1_callback error_callback;
};
//#include "../secp256k1/include/secp256k1.h"
//#include "../secp256k1/include/secp256k1_schnorrsig.h"
#include "../secp256k1/include/secp256k1_musig.h"
extern "C" int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n);
extern "C" int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk);
extern "C" int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64);
extern "C" int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys);
extern "C" int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey);
extern "C" int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig);
#define MUSIG_PREVN 0 // for now, just use vout0 for the musig output
#define MUSIG_TXFEE 10000
struct musig_info
{
secp256k1_musig_session session;
secp256k1_pubkey combined_pk;
uint8_t *nonce_commitments,**commitment_ptrs; // 32*N_SIGNERS
secp256k1_musig_session_signer_data *signer_data; //[N_SIGNERS];
secp256k1_pubkey *nonces; //[N_SIGNERS];
secp256k1_musig_partial_signature *partial_sig; //[N_SIGNERS];
int32_t myind,num,numcommits,numnonces,numpartials;
uint8_t msg[32],pkhash[32],combpk[33];
};
std::vector <struct musig_info *> MUSIG;
struct musig_info *musig_infocreate(int32_t myind,int32_t num)
{
int32_t i; struct musig_info *mp = (struct musig_info *)calloc(1,sizeof(*mp));
mp->myind = myind, mp->num = num;
mp->nonce_commitments = (uint8_t *)calloc(num,32);
mp->commitment_ptrs = (uint8_t **)calloc(num,sizeof(*mp->commitment_ptrs));
for (i=0; i<num; i++)
mp->commitment_ptrs[i] = &mp->nonce_commitments[i*32];
mp->signer_data = (secp256k1_musig_session_signer_data *)calloc(num,sizeof(*mp->signer_data));
mp->nonces = (secp256k1_pubkey *)calloc(num,sizeof(*mp->nonces));
mp->partial_sig = (secp256k1_musig_partial_signature *)calloc(num,sizeof(*mp->partial_sig));
return(mp);
}
void musig_infofree(struct musig_info *mp)
{
if ( mp->partial_sig != 0 )
{
GetRandBytes((uint8_t *)mp->partial_sig,mp->num*sizeof(*mp->partial_sig));
free(mp->partial_sig);
}
if ( mp->nonces != 0 )
{
GetRandBytes((uint8_t *)mp->nonces,mp->num*sizeof(*mp->nonces));
free(mp->nonces);
}
if ( mp->signer_data != 0 )
{
GetRandBytes((uint8_t *)mp->signer_data,mp->num*sizeof(*mp->signer_data));
free(mp->signer_data);
}
if ( mp->nonce_commitments != 0 )
{
GetRandBytes((uint8_t *)mp->nonce_commitments,mp->num*32);
free(mp->nonce_commitments);
}
if ( mp->commitment_ptrs != 0 )
{
GetRandBytes((uint8_t *)mp->commitment_ptrs,mp->num*sizeof(*mp->commitment_ptrs));
free(mp->commitment_ptrs);
}
GetRandBytes((uint8_t *)mp,sizeof(*mp));
free(mp);
}
CScript musig_sendopret(uint8_t funcid,CPubKey pk)
{
CScript opret; uint8_t evalcode = EVAL_MUSIG;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk);
return(opret);
}
uint8_t musig_sendopretdecode(CPubKey &pk,CScript scriptPubKey)
{
std::vector<uint8_t> vopret; uint8_t e,f;
GetOpReturnData(scriptPubKey,vopret);
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk) != 0 && e == EVAL_MUSIG && f == 'x' )
{
return(f);
}
return(0);
}
CScript musig_spendopret(uint8_t funcid,CPubKey pk,std::vector<uint8_t> musig64)
{
CScript opret; uint8_t evalcode = EVAL_MUSIG;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk << musig64);
return(opret);
}
uint8_t musig_spendopretdecode(CPubKey &pk,std::vector<uint8_t> &musig64,CScript scriptPubKey)
{
std::vector<uint8_t> vopret; uint8_t e,f;
GetOpReturnData(scriptPubKey,vopret);
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk; ss >> musig64) != 0 && e == EVAL_MUSIG && f == 'y' )
{
return(f);
}
return(0);
}
int32_t musig_parsepubkey(secp256k1_context *ctx,secp256k1_pubkey &spk,cJSON *item)
{
char *hexstr;
if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == 66 )
{
CPubKey pk(ParseHex(hexstr));
if ( secp256k1_ec_pubkey_parse(ctx,&spk,pk.begin(),33) > 0 )
return(1);
} else return(-1);
}
int32_t musig_msghash(uint8_t *msg,uint256 prevhash,int32_t prevn,CTxOut vout,CPubKey pk)
{
CScript data; uint256 hash; int32_t len = 0;
data << E_MARSHAL(ss << prevhash << prevn << vout << pk);
hash = Hash(data.begin(),data.end());
memcpy(msg,&hash,sizeof(hash));
return(0);
}
int32_t musig_prevoutmsg(uint8_t *msg,uint256 sendtxid,CScript scriptPubKey)
{
CTransaction vintx; uint256 hashBlock; int32_t numvouts; CTxOut vout; CPubKey pk;
memset(msg,0,32);
if ( myGetTransaction(sendtxid,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
{
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
{
vout.nValue = vintx.vout[MUSIG_PREVN].nValue - MUSIG_TXFEE;
vout.scriptPubKey = scriptPubKey;
return(musig_msghash(msg,sendtxid,MUSIG_PREVN,vout,pk));
}
}
return(-1);
}
UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result(UniValue::VOBJ); uint256 sendtxid; int32_t i,zeros=0; uint8_t msg[32]; char *scriptstr,str[65]; int32_t n;
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n == 2 )
{
sendtxid = juint256(jitem(params,0));
scriptstr = jstr(jitem(params,1),0);
if ( is_hexstr(scriptstr,0) != 0 )
{
CScript scriptPubKey;
scriptPubKey.resize(strlen(scriptstr)/2);
decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr);
musig_prevoutmsg(msg,sendtxid,scriptPubKey);
for (i=0; i<32; i++)
{
sprintf(&str[i<<1],"%02x",msg[i]);
if ( msg[i] == 0 )
zeros++;
}
str[64] = 0;
if ( zeros != 32 )
{
result.push_back(Pair("msg",str));
result.push_back(Pair("result","success"));
return(result);
} else return(cclib_error(result,"null result, make sure params are sendtxid, scriptPubKey"));
} else return(cclib_error(result,"script is not hex"));
} else return(cclib_error(result,"need exactly 2 parameters: sendtxid, scriptPubKey"));
} else return(cclib_error(result,"couldnt parse params"));
}
UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
UniValue result(UniValue::VOBJ); CPubKey pk; int32_t i,n; uint8_t pkhash[32]; char *hexstr,str[67]; secp256k1_pubkey combined_pk,spk; std::vector<secp256k1_pubkey> pubkeys;
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
//fprintf(stderr,"n.%d args.(%s)\n",n,jprint(params,0));
for (i=0; i<n; i++)
{
if ( musig_parsepubkey(ctx,spk,jitem(params,i)) < 0 )
return(cclib_error(result,"error parsing pk"));
pubkeys.push_back(spk);
}
if ( secp256k1_musig_pubkey_combine(ctx,NULL,&combined_pk,pkhash,&pubkeys[0],n) > 0 )
{
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&combined_pk,SECP256K1_EC_COMPRESSED) > 0 && clen == 33 )
{
for (i=0; i<32; i++)
sprintf(&str[i<<1],"%02x",pkhash[i]);
str[64] = 0;
result.push_back(Pair("pkhash",str));
for (i=0; i<33; i++)
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]);
str[66] = 0;
result.push_back(Pair("combined_pk",str));
result.push_back(Pair("result","success"));
return(result);
} else return(cclib_error(result,"error serializeing combined_pk"));
} else return(cclib_error(result,"error combining pukbeys"));
} else return(cclib_error(result,"need pubkeys params"));
}
UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
UniValue result(UniValue::VOBJ); int32_t i,n,myind,num,musiglocation; char *pkstr,*pkhashstr,*msgstr; uint8_t session[32],msg[32],pkhash[32],privkey[32],pub33[33]; CPubKey pk; char str[67];
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 5 )
{
myind = juint(jitem(params,0),0);
num = juint(jitem(params,1),0);
if ( myind < 0 || myind >= num || num <= 0 )
return(cclib_error(result,"illegal myindex and numsigners"));
if ( n > 5 )
musiglocation = juint(jitem(params,5),0);
else if ( n == 5 )
musiglocation = 0;
//printf("number of params.%i musiglocation.%i\n",n,musiglocation);
if ( MUSIG.size() > musiglocation )
{
for (int i = 0; i < MUSIG.size()-1; i++)
musig_infofree(MUSIG[i]);
MUSIG.clear();
}
struct musig_info *temp_musig = musig_infocreate(myind,num);
MUSIG.push_back(temp_musig);
if ( musig_parsepubkey(ctx,MUSIG[musiglocation]->combined_pk,jitem(params,2)) < 0 )
return(cclib_error(result,"error parsing combined_pubkey"));
else if ( cclib_parsehash(MUSIG[musiglocation]->pkhash,jitem(params,3),32) < 0 )
return(cclib_error(result,"error parsing pkhash"));
else if ( cclib_parsehash(MUSIG[musiglocation]->msg,jitem(params,4),32) < 0 )
return(cclib_error(result,"error parsing msg"));
Myprivkey(privkey);
GetRandBytes(session,32);
/** Initializes a signing session for a signer
*
* Returns: 1: session is successfully initialized
* 0: session could not be initialized: secret key or secret nonce overflow
* Args: ctx: pointer to a context object, initialized for signing (cannot
* be NULL)
* Out: session: the session structure to initialize (cannot be NULL)
* signers: an array of signers' data to be initialized. Array length must
* equal to `n_signers` (cannot be NULL)
* nonce_commitment32: filled with a 32-byte commitment to the generated nonce
* (cannot be NULL)
* In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be
* NULL). If a non-unique session_id32 was given then a partial
* signature will LEAK THE SECRET KEY.
* msg32: the 32-byte message to be signed. Shouldn't be NULL unless you
* require sharing public nonces before the message is known
* because it reduces nonce misuse resistance. If NULL, must be
* set with `musig_session_set_msg` before signing and verifying.
* combined_pk: the combined public key of all signers (cannot be NULL)
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be
* NULL)
* n_signers: length of signers array. Number of signers participating in
* the MuSig. Must be greater than 0 and at most 2^32 - 1.
* my_index: index of this signer in the signers array
* seckey: the signer's 32-byte secret key (cannot be NULL)
*/
//fprintf(stderr, "SESSION: struct_size.%li using struct %i\n",MUSIG.size(), musiglocation);
if ( secp256k1_musig_session_initialize(ctx,&MUSIG[musiglocation]->session,MUSIG[musiglocation]->signer_data, &MUSIG[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind * 32],session,MUSIG[musiglocation]->msg,&MUSIG[musiglocation]->combined_pk,MUSIG[musiglocation]->pkhash,MUSIG[musiglocation]->num,MUSIG[musiglocation]->myind,privkey) > 0 )
{
memset(session,0,sizeof(session));
result.push_back(Pair("myind",(int64_t)myind));
result.push_back(Pair("numsigners",(int64_t)num));
for (i=0; i<32; i++)
sprintf(&str[i<<1],"%02x",MUSIG[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind*32 + i]);
str[64] = 0;
if ( n == 5 )
MUSIG[musiglocation]->numcommits = 1;
result.push_back(Pair("commitment",str));
result.push_back(Pair("result","success"));
return(result);
}
else
{
memset(session,0,sizeof(session));
return(cclib_error(result,"couldnt initialize session"));
}
} else return(cclib_error(result,"wrong number of params, need 5: myindex, numsigners, combined_pk, pkhash, msg32"));
}
UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32]; CPubKey pk; char str[67];
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 )
{
if ( n > 3 )
myind = juint(jitem(params,3),0);
else if ( n == 3 )
myind = 0;
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 )
return(cclib_error(result,"error parsing pkhash"));
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
return(cclib_error(result,"pkhash doesnt match session pkhash"));
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num )
return(cclib_error(result,"illegal ind for session"));
else if ( cclib_parsehash(&MUSIG[myind]->nonce_commitments[ind*32],jitem(params,2),32) < 0 )
return(cclib_error(result,"error parsing commitment"));
/** Gets the signer's public nonce given a list of all signers' data with commitments
*
* Returns: 1: public nonce is written in nonce
* 0: signer data is missing commitments or session isn't initialized
* for signing
* Args: ctx: pointer to a context object (cannot be NULL)
* session: the signing session to get the nonce from (cannot be NULL)
* signers: an array of signers' data initialized with
* `musig_session_initialize`. Array length must equal to
* `n_commitments` (cannot be NULL)
* Out: nonce: the nonce (cannot be NULL)
* In: commitments: array of 32-byte nonce commitments (cannot be NULL)
* n_commitments: the length of commitments and signers array. Must be the total
* number of signers participating in the MuSig.
*/
result.push_back(Pair("added_index",ind));
//fprintf(stderr, "COMMIT: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind);
MUSIG[myind]->numcommits++;
if ( MUSIG[myind]->numcommits >= MUSIG[myind]->num && secp256k1_musig_session_get_public_nonce(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,&MUSIG[myind]->nonces[MUSIG[myind]->myind],MUSIG[myind]->commitment_ptrs,MUSIG[myind]->num) > 0 )
{
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&MUSIG[myind]->nonces[MUSIG[myind]->myind],SECP256K1_EC_COMPRESSED) > 0 && clen == 33 )
{
for (i=0; i<33; i++)
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]);
str[66] = 0;
if ( n == 3 )
MUSIG[myind]->numnonces = 1;
result.push_back(Pair("myind",MUSIG[myind]->myind));
result.push_back(Pair("nonce",str));
result.push_back(Pair("result","success"));
} else return(cclib_error(result,"error serializing nonce (pubkey)"));
}
else
{
result.push_back(Pair("status","not enough commitments"));
result.push_back(Pair("result","success"));
}
return(result);
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, commitment"));
}
UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32],psig[32]; CPubKey pk; char str[67];
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 )
{
if ( n > 3 )
myind = juint(jitem(params,3),0);
else if ( n == 3 )
myind = 0;
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 )
return(cclib_error(result,"error parsing pkhash"));
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
return(cclib_error(result,"pkhash doesnt match session pkhash"));
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num )
return(cclib_error(result,"illegal ind for session"));
else if ( musig_parsepubkey(ctx,MUSIG[myind]->nonces[ind],jitem(params,2)) < 0 )
return(cclib_error(result,"error parsing nonce"));
result.push_back(Pair("added_index",ind));
/** Checks a signer's public nonce against a commitment to said nonce, and update
* data structure if they match
*
* Returns: 1: commitment was valid, data structure updated
* 0: commitment was invalid, nothing happened
* Args: ctx: pointer to a context object (cannot be NULL)
* signer: pointer to the signer data to update (cannot be NULL). Must have
* been used with `musig_session_get_public_nonce` or initialized
* with `musig_session_initialize_verifier`.
* In: nonce: signer's alleged public nonce (cannot be NULL)
*/
MUSIG[myind]->numnonces++;
//fprintf(stderr, "NONCE: struct_size.%li using_struct.%i added_index.%i numnounces.%i num.%i\n",MUSIG.size(), myind, ind, MUSIG[myind]->numnonces, MUSIG[myind]->num);
if ( MUSIG[myind]->numnonces < MUSIG[myind]->num )
{
result.push_back(Pair("status","not enough nonces"));
result.push_back(Pair("result","success"));
return(result);
}
for (i=0; i<MUSIG[myind]->num; i++)
{
if ( secp256k1_musig_set_nonce(ctx,&MUSIG[myind]->signer_data[i],&MUSIG[myind]->nonces[i]) == 0 )
return(cclib_error(result,"error setting nonce"));
}
/** Updates a session with the combined public nonce of all signers. The combined
* public nonce is the sum of every signer's public nonce.
*
* Returns: 1: nonces are successfully combined
* 0: a signer's nonce is missing
* Args: ctx: pointer to a context object (cannot be NULL)
* session: session to update with the combined public nonce (cannot be
* NULL)
* signers: an array of signers' data, which must have had public nonces
* set with `musig_set_nonce`. Array length must equal to `n_signers`
* (cannot be NULL)
* n_signers: the length of the signers array. Must be the total number of
* signers participating in the MuSig.
* Out: nonce_is_negated: a pointer to an integer that indicates if the combined
* public nonce had to be negated.
* adaptor: point to add to the combined public nonce. If NULL, nothing is
* added to the combined nonce.
*/
if ( secp256k1_musig_session_combine_nonces(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,MUSIG[myind]->num,NULL,NULL) > 0 )
{
if ( secp256k1_musig_partial_sign(ctx,&MUSIG[myind]->session,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
{
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
{
for (i=0; i<32; i++)
sprintf(&str[i<<1],"%02x",psig[i]);
str[64] = 0;
result.push_back(Pair("myind",MUSIG[myind]->myind));
result.push_back(Pair("partialsig",str));
result.push_back(Pair("result","success"));
if ( n == 3 )
MUSIG[myind]->numpartials = 1;
return(result);
} else return(cclib_error(result,"error serializing partial sig"));
} else return(cclib_error(result,"error making partial sig"));
} else return(cclib_error(result,"error combining nonces"));
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, nonce"));
}
UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
UniValue result(UniValue::VOBJ); int32_t i,ind,n,myind; uint8_t pkhash[32],psig[32],out64[64]; char str[129]; secp256k1_schnorrsig sig;
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 )
{
if ( n > 3 )
myind = juint(jitem(params,3),0);
else if ( n == 3 )
myind = 0;
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 )
return(cclib_error(result,"error parsing pkhash"));
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
return(cclib_error(result,"pkhash doesnt match session pkhash"));
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num )
return(cclib_error(result,"illegal ind for session"));
else if ( cclib_parsehash(psig,jitem(params,2),32) < 0 )
return(cclib_error(result,"error parsing psig"));
else if ( secp256k1_musig_partial_signature_parse(ctx,&MUSIG[myind]->partial_sig[ind],psig) == 0 )
return(cclib_error(result,"error parsing partialsig"));
result.push_back(Pair("added_index",ind));
//fprintf(stderr, "SIG: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind);
MUSIG[myind]->numpartials++;
if ( MUSIG[myind]->numpartials >= MUSIG[myind]->num && secp256k1_musig_partial_sig_combine(ctx,&MUSIG[myind]->session,&sig,MUSIG[myind]->partial_sig,MUSIG[myind]->num) > 0 )
{
if ( secp256k1_schnorrsig_serialize(ctx,out64,&sig) > 0 )
{
result.push_back(Pair("result","success"));
for (i=0; i<64; i++)
sprintf(&str[i<<1],"%02x",out64[i]);
str[128] = 0;
result.push_back(Pair("combinedsig",str));
} else return(cclib_error(result,"error serializing combinedsig"));
}
else
{
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
{
result.push_back(Pair("myind",ind));
for (i=0; i<32; i++)
sprintf(&str[i<<1],"%02x",psig[i]);
str[64] = 0;
result.push_back(Pair("partialsig",str));
result.push_back(Pair("result","success"));
result.push_back(Pair("status","need more partialsigs"));
} else return(cclib_error(result,"error generating my partialsig"));
}
return(result);
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, partialsig"));
}
//int testmain(void);
UniValue musig_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
UniValue result(UniValue::VOBJ); int32_t i,n; uint8_t msg[32],musig64[64]; secp256k1_pubkey combined_pk; secp256k1_schnorrsig musig; char str[129];
//testmain();
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 )
{
if ( cclib_parsehash(msg,jitem(params,0),32) < 0 )
return(cclib_error(result,"error parsing pkhash"));
else if ( musig_parsepubkey(ctx,combined_pk,jitem(params,1)) < 0 )
return(cclib_error(result,"error parsing combined_pk"));
else if ( cclib_parsehash(musig64,jitem(params,2),64) < 0 )
return(cclib_error(result,"error parsing musig64"));
for (i=0; i<32; i++)
sprintf(&str[i*2],"%02x",msg[i]);
str[64] = 0;
result.push_back(Pair("msg",str));
result.push_back(Pair("combined_pk",jstr(jitem(params,1),0)));
for (i=0; i<64; i++)
sprintf(&str[i*2],"%02x",musig64[i]);
str[128] = 0;
result.push_back(Pair("combinedsig",str));
if ( secp256k1_schnorrsig_parse(ctx,&musig,&musig64[0]) > 0 )
{
if ( secp256k1_schnorrsig_verify(ctx,&musig,msg,&combined_pk) > 0 )
{
result.push_back(Pair("result","success"));
return(result);
} else return(cclib_error(result,"musig didnt verify"));
} else return(cclib_error(result,"couldnt parse musig64"));
} else return(cclib_error(result,"wrong number of params, need 3: msg, combined_pk, combinedsig"));
}
// helpers for rpc calls that generate/validate onchain tx
UniValue musig_rawtxresult(UniValue &result,std::string rawtx)
{
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 musig_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
UniValue result(UniValue::VOBJ); int32_t n; char *hexstr; std::string rawtx; int64_t amount; CPubKey musigpk,mypk;
if ( txfee == 0 )
txfee = MUSIG_TXFEE;
mypk = pubkey2pk(Mypubkey());
musigpk = GetUnspendable(cp,0);
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n == 2 && (hexstr= jstr(jitem(params,0),0)) != 0 && is_hexstr(hexstr,0) == 66 )
{
CPubKey pk(ParseHex(hexstr));
amount = jdouble(jitem(params,1),0) * COIN + 0.0000000049;
if ( amount >= 3*txfee && AddNormalinputs(mtx,mypk,amount+2*txfee,64) >= amount+2*txfee )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount+txfee,musigpk));
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_sendopret('x',pk));
return(musig_rawtxresult(result,rawtx));
} else return(cclib_error(result,"couldnt find funds or less than 0.0003"));
} else return(cclib_error(result,"must have 2 params: pk, amount"));
} else return(cclib_error(result,"not enough parameters"));
}
UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,pk; secp256k1_pubkey combined_pk; char *scriptstr,*musigstr; uint8_t msg[32]; CTransaction vintx; uint256 prevhash,hashBlock; int32_t i,n,numvouts; char str[129]; CTxOut vout; secp256k1_schnorrsig musig;
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n == 3 )
{
prevhash = juint256(jitem(params,0));
scriptstr = jstr(jitem(params,1),0);
musigstr = jstr(jitem(params,2),0);
if ( is_hexstr(scriptstr,0) != 0 && is_hexstr(musigstr,0) == 128 )
{
if ( txfee == 0 )
txfee = MUSIG_TXFEE;
mypk = pubkey2pk(Mypubkey());
std::vector<uint8_t> musig64(ParseHex(musigstr));
CScript scriptPubKey;
scriptPubKey.resize(strlen(scriptstr)/2);
decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr);
if ( myGetTransaction(prevhash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
{
vout.nValue = vintx.vout[0].nValue - txfee;
vout.scriptPubKey = scriptPubKey;
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
{
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 &&
secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 )
{
musig_prevoutmsg(msg,prevhash,vout.scriptPubKey);
{
for (i=0; i<32; i++)
sprintf(&str[i*2],"%02x",msg[i]);
str[64] = 0;
result.push_back(Pair("msg",str));
for (i=0; i<33; i++)
sprintf(&str[i*2],"%02x",((uint8_t *)pk.begin())[i]);
str[66] = 0;
result.push_back(Pair("combined_pk",str));
for (i=0; i<64; i++)
sprintf(&str[i*2],"%02x",musig64[i]);
str[128] = 0;
result.push_back(Pair("combinedsig",str));
}
if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) )
{
return(cclib_error(result,"musig didnt validate"));
}
mtx.vin.push_back(CTxIn(prevhash,MUSIG_PREVN));
mtx.vout.push_back(vout);
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_spendopret('y',pk,musig64));
return(musig_rawtxresult(result,rawtx));
} else return(cclib_error(result,"couldnt parse pk or musig"));
} else return(cclib_error(result,"couldnt decode send opret"));
} else return(cclib_error(result,"couldnt find vin0"));
} else return(cclib_error(result,"script or musig is not hex"));
} else return(cclib_error(result,"need to have exactly 3 params sendtxid, scriptPubKey, musig"));
} else return(cclib_error(result,"params parse error"));
}
bool musig_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
{
static secp256k1_context *ctx;
secp256k1_pubkey combined_pk; CPubKey pk,checkpk; secp256k1_schnorrsig musig; uint256 hashBlock; CTransaction vintx; int32_t numvouts; std::vector<uint8_t> musig64; uint8_t msg[32];
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( tx.vout.size() != 2 )
return eval->Invalid("numvouts != 2");
else if ( tx.vin.size() != 1 )
return eval->Invalid("numvins != 1");
else if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
return eval->Invalid("illegal normal vin0");
else if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
{
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
{
if ( musig_spendopretdecode(checkpk,musig64,tx.vout[tx.vout.size()-1].scriptPubKey) == 'y' )
{
if ( pk == checkpk )
{
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 &&
secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 )
{
musig_prevoutmsg(msg,tx.vin[0].prevout.hash,tx.vout[0].scriptPubKey);
if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) )
return eval->Invalid("failed schnorrsig_verify");
else return(true);
} else return eval->Invalid("couldnt parse pk or musig");
} else return eval->Invalid("combined_pk didnt match send opret");
} else return eval->Invalid("failed decode musig spendopret");
} else return eval->Invalid("couldnt decode send opret");
} else return eval->Invalid("couldnt find vin0 tx");
}

View File

@@ -171,7 +171,7 @@ CPubKey OracleBatonPk(char *batonaddr,struct CCcontract_info *cp)
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
Myprivkey(priv);
cp->evalcode2 = EVAL_ORACLES;
cp->unspendableEvalcode2 = EVAL_ORACLES;
for (i=0; i<32; i++)
cp->unspendablepriv2[i] = (priv[i] ^ cp->CCpriv[i]);
while ( secp256k1_ec_seckey_verify(ctx,cp->unspendablepriv2) == 0 )
@@ -197,7 +197,7 @@ int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publ
{
uint256 txid,oracletxid,hashBlock; int64_t datafee=0,dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,markeraddr);
SetCCunspents(unspentOutputs,markeraddr,false);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -260,7 +260,7 @@ uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 refora
{
uint256 txid,oracletxid,hashBlock,btxid,batontxid = zeroid; int64_t dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk; uint8_t *ptr; std::vector<uint8_t> vopret,data;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,batonaddr);
SetCCunspents(unspentOutputs,batonaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -294,7 +294,7 @@ uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 refora
}
}
}
while ( myIsutxo_spentinmempool(batontxid,1) != 0 )
while ( myIsutxo_spentinmempool(ignoretxid,ignorevin,batontxid,1) != 0 )
batontxid = myIs_baton_spentinmempool(batontxid,1);
return(batontxid);
}
@@ -306,7 +306,7 @@ uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk)
batontxid = zeroid;
cp = CCinit(&C,EVAL_ORACLES);
CCtxidaddr(markeraddr,reforacletxid);
SetCCunspents(unspentOutputs,markeraddr);
SetCCunspents(unspentOutputs,markeraddr,false);
//char str[67]; fprintf(stderr,"markeraddr.(%s) %s\n",markeraddr,pubkey33_str(str,(uint8_t *)&refpk));
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
@@ -525,14 +525,14 @@ int32_t oracleprice_add(std::vector<struct oracleprice_info> &publishers,CPubKey
} else return(0);
}
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
/*int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
{
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
CTransaction regtx; uint256 hash,txid,oracletxid,batontxid; CPubKey pk; int32_t i,ht,maxheight=0; int64_t datafee,price; char batonaddr[64]; std::vector <uint8_t> data; struct CCcontract_info *cp,C; std::vector <struct oracleprice_info> publishers; std::vector <int64_t> prices;
if ( format[0] != 'L' )
return(0);
cp = CCinit(&C,EVAL_ORACLES);
SetCCunspents(unspentOutputs,markeraddr);
SetCCunspents(unspentOutputs,markeraddr,false);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -562,7 +562,7 @@ int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *
return(OracleCorrelatedPrice(height,prices));
}
return(0);
}
}*/
int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
{
@@ -708,7 +708,7 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,uint
char coinaddr[64],funcid; int64_t nValue,price,totalinputs = 0; uint256 tmporacletxid,tmpbatontxid,txid,hashBlock; std::vector<uint8_t> origpubkey,data; CTransaction vintx; int32_t numvouts,vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; CPubKey tmppk; int64_t tmpnum;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
//fprintf(stderr,"addoracleinputs from (%s)\n",coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
@@ -724,7 +724,7 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,uint
else if (tmporacletxid==oracletxid)
{
// get valid CC payments
if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -746,7 +746,7 @@ int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubK
char coinaddr[64]; CPubKey pk; int64_t total=0,num; uint256 txid,hashBlock,subtxid; CTransaction subtx;
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
GetCCaddress(cp,coinaddr,publisher);
SetCCtxids(addressIndex,coinaddr);
SetCCtxids(addressIndex,coinaddr,true);
//fprintf(stderr,"scan lifetime of %s\n",coinaddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
@@ -971,7 +971,8 @@ UniValue OracleInfo(uint256 origtxid)
UniValue result(UniValue::VOBJ),a(UniValue::VARR);
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector <uint8_t> data;
CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk;
struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector <uint8_t> data;
cp = CCinit(&C,EVAL_ORACLES);
CCtxidaddr(markeraddr,origtxid);
if ( GetTransaction(origtxid,tx,hashBlock,false) == 0 )
@@ -991,7 +992,7 @@ UniValue OracleInfo(uint256 origtxid)
result.push_back(Pair("description",description));
result.push_back(Pair("format",format));
result.push_back(Pair("marker",markeraddr));
SetCCunspents(unspentOutputs,markeraddr);
SetCCunspents(unspentOutputs,markeraddr,false);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -1027,7 +1028,7 @@ UniValue OraclesList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction createtx; std::string name,description,format; char str[65];
cp = CCinit(&C,EVAL_ORACLES);
SetCCtxids(addressIndex,cp->normaladdr);
SetCCtxids(addressIndex,cp->normaladdr,true);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;

File diff suppressed because it is too large Load Diff

View File

@@ -16,17 +16,72 @@
#include "CCPegs.h"
/*
Pegs CC builds on top of Prices CC and would bind a pricefeed to a token bid/ask automated marketmaking.
pegs CC is able to create a coin backed (by any supported coin with gateways CC deposits) and pegged to any synthetic price that is able to be calculated based on prices CC
Funds deposited into CC address for a specific peg would then be used to fund the bid/ask as the pricefeed changes the price. Profits/losses would accumulate in the associated address.
First, the prices CC needs to be understood, so the extensive comments at the top of ~/src/cc/prices.cpp needs to be understood.
In the event funds exceed a specified level, it can be spent into a collection address. The idea is that the collection address can further be used for revshares.
The second aspect is the ability to import coins, as used by the crosschain burn/import and the -ac_import chains.
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format);
<one hour later...>
OK, now we are ready to describe the pegs CC. Let us imagine an -ac_import sidechain with KMD gateways CC. Now we have each native coin fungible with the real KMD via the gateways deposit/withdraw mechanism. Let us start with that and make a pegged and backed USD chain.
<alternatively we can start from a CC enabled chain with external value>
Here the native coin is KMD, but we want USD, so there needs to be a way to convert the KMD amounts into USD amounts. Something like "KMDBTC, BTCUSD, *, 1" which is the prices CC syntax to calculate KMD/USD, which is exactly what we need. So now we can assume that we have a block by block usable KMD/USD price. implementationwise, there can be an -ac option like -ac_peg="KMDBTC, BTCUSD, *, 1" and in conjunction with -ac_import=KMD gateways CC sidechain, we now have a chain where deposit of KMD issues the correct USD coins and redeem of USD coins releases the correct number of KMD coins.
Are we done yet?
Not quite, as the prices of KMD will be quite volatile relative to USD, which is good during bull markets, not so happy during bear markets. There are 2 halves to this problem, how to deal with massive price increase (easy to solve), how to solve 90% price drop (a lot harder).
In order to solve both, what is needed is an "account" based tracking which updates based on both price change, coins issued, payments made. So let us create an account that is based on a specific pubkey, where all relevant deposits, issuances, withdraws are tracked via appropriate vin/vout markers.
Let us modify the USD chain above so that only 80% of the possible USD is issued and 20% held in reserve. This 80% should be at least some easily changeable #define, or even an -ac parameter. We want the issued coins to be released without any encumberances, but the residual 20% value is still controlled (owned) but the depositor. This account has the amount of KMD deposited and USD issued. At the moment of deposit, there will still be 20% equity left. Let us start with 1000 KMD deposit, $1.5 per KMD -> 800 KMD converted to 1200 USD into depositor pubkey and the account of (1000 KMD, -1200 USD) = 200 KMD or $300 equity.
Now it becomes easy for the bull market case, which is to allow (for a fee like 1%) issuance of more USD as the equity increases, so let us imagine KMD at $10:
(1000 KMD, -1200 USD, 200KMD reserve) -> $2000 equity, issue 80% -> $1600 using 160 KMD
(1000 KMD, -1200 USD, 200KMD reserve, -160KMD, issue $1600 USD, 40 KMD reserve)
we have $2800 USD in circulation, 40 KMD reserve left against $10000 marketcap of the original deposit. It it easy to see that there are never any problems with lack of KMD to redeem the issued USD in a world where prices only go up. Total USD issuance can be limited by using a decentralized account tracking based on each deposit.
What is evident though is that with the constantly changing price and the various times that all the various deposits issue USD, the global reserves are something that will be hard to predict and in fact needs to be specifically tracked. Let us combine all accounts exposure in to a global reserves factor. This factor will control various max/min/ allowed and fee percentages.
Now we are prepared to handle the price goes down scenario. We can rely on the global equity/reserve ratio to be changing relatively slowly as the reference price is the smooted trustless oracles price. This means there will be enough blocks to adjust the global reserves percentage. What we need to do is liquidate specific positions that have the least reserves.
What does liquidation mean? It means a specific account will be purchased at below its current value and the KMD withdrawn. Let us assume the price drops to $5:
(1000 KMD, -1200 USD, 200KMD reserve, -160KMD, issue $1600 USD, 40 KMD reserve) 1000 KMD with 2800 USD issued so $2200 reserves. Let us assume it can be liquidated at a 10% discount, so for $2000 in addition to the $2800, the 5000 KMD is able to be withdrawn. This removes 4800 USD coins for 1000 KMD, which is a very low reserve amount of 4%. If a low reserve amount is removed from the system, then the global reserve amount must be improved.
In addition to the global reserves calculation, there needs to be a trigger percentage that enables positions to be liquidated. We also want to liquidate the worst positions, so in addition to the trigger percentage, there should be a liquidation threshold, and the liquidator would need to find 3 or more better positions that are beyond the liquidation threshold, to be able to liquidate. This will get us to at most 3 accounts that could be liquidated but are not able to, so some method to allow those to also be liquidated. The liquidating nodes are making instant profits, so they should be expected to do whatever blockchain scanning and proving to make things easy for the rest of the nodes.
One last issue is the normal redemption case where we are not liquidating. In this case, it should be done at the current marketprice, should improve the global reserves metrics and not cause anybody whose position was modified to have cause for complaint. Ideally, there would be an account that has the identical to the global reserve percentage and also at the same price as current marketprice, but this is not realistic, so we need to identify classes of accounts and consider which ones can be fully or partially liquidated to satisfy the constraints.
looking at our example account:
(1000 KMD, -1200 USD, 200KMD reserve, -160KMD, issue $1600 USD, 40 KMD reserve)
OraclePrice is very useful for pegs.
what sort of non-liquidation withdraw would be acceptable? if the base amount 1000 KMD is reduced along with USD owed, then the reserve status will go up for the account. but that would seem to allow extra USD to be able to be issued. there should be no disadvantage from funding a withdraw, but also not any large advantage. it needs to be a neutral event....
*/
One solution is to allow for the chance for any account to be liquidated, but the equity compensated for with a premium based on the account reserves. So in the above case, a premium of 5% on the 40KMD reserve is paid to liquidate its account. Instead of 5% premium, a lower 1% can be done if based on the MAX(correlated[daywindow],smoothed) so we get something that is close to the current marketprice. To prevent people taking advantage of the slowness of the smoothed price to adjust, there would need to be a one day delay in the withdraw.
From a practical sense, it seems a day is a long time, so maybe having a way to pay a premium like 10%, or wait a day to get the MAX(correlated[daywindow],smoothed) price. This price "jumping" might also be taken advantage of in the deposit side, so similar to prices CC it seems good to have the MAX(correlated[daywindow],smoothed) method.
Now, we have a decentralized mechanism to handle the price going lower! Combined with the fully decentralized method new USD coins are issued, makes this argubably the first decentralized blockchain that is both backed and pegged. There is the reliance on the gateways CC multisig signers, so there is a fundamental federated trust for chains without intrinsic value.
Also, notice that the flexibly syntax of prices CC allows to define pegs easily for virtually any type of synthetic, and all the ECB fiats can easily get a backed and pegged coin.
Let us now consider how to enforce a peg onto a specific gateways CC token. If this can also be achieved, then a full DEX for all the different gateways CC supported coins can be created onto a single fiat denominated chain.
I think just having a pegscreate rpc call that binds an existing gateways create to a price CC syntax price will be almost enough to support this. Let us assume a USD stablechain and we have a BTC token, then pegscreate <btc gateways txid> "BTCUSD, 1"
that will specify using the BTCUSD price, so now we need to create a <txid> based way to do tokenbid/tokenask. For a <txid> based price, the smoothed price is substituted.
There is the issue of the one day delay, so it might make sense to allow specific bid/ask to be based on some simple combinations of the three possible prices. it might even be possible to go a bit overboard and make a forth like syntax to define the dynamic price for a bid, which maybe at times wont be valid, like it is only valid if the three prices are within 1% of each other. But all that seems over complex and for initial release it can just use the mined, correlated or smoothed price, with some specified percentage offset
Implementation notes:
make sure that fees and markers that can be sent to an unspendable address are sent to: RNdqHx26GWy9bk8MtmH1UiXjQcXE4RKK2P, this is the address for BOTS
*/
// start of consensus code
@@ -126,7 +181,7 @@ int64_t AddPegsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -134,7 +189,7 @@ int64_t AddPegsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsPegsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsPegsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));

File diff suppressed because it is too large Load Diff

View File

@@ -203,7 +203,7 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
else
{
txid = tx.GetHash();
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 )
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 )
{
if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 )
return eval->Invalid("cant find fundingtxid");
@@ -255,15 +255,23 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
return eval->Invalid("unexpected normal vin for unlock");
}
if ( numvouts == 2 && numvins == 1 )
if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) )
return eval->Invalid("txfee is too high");
amount = vinTx.vout[0].nValue;
reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit);
if ( reward == 0 )
return eval->Invalid("no eligible rewards");
if ( numvins == 1 && tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
{
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 )
return eval->Invalid("unlock recover tx vout.0 is not normal output");
if ( tx.vout[1].nValue != 10000 )
return eval->Invalid("wrong marker vout value");
else if ( tx.vout[1].scriptPubKey != tx.vout[0].scriptPubKey )
return eval->Invalid("unlock recover tx vout.1 mismatched scriptPubKey");
else if ( tx.vout[0].scriptPubKey != vinTx.vout[1].scriptPubKey )
return eval->Invalid("unlock recover tx vout.0 mismatched scriptPubKey");
else if ( tx.vout[0].nValue > vinTx.vout[0].nValue )
return eval->Invalid("unlock recover tx vout.0 mismatched amounts");
else if ( tx.vout[1].nValue > 0 )
else if ( tx.vout[2].nValue > 0 )
return eval->Invalid("unlock recover tx vout.1 nonz amount");
else return(true);
}
@@ -277,8 +285,6 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
return eval->Invalid("unlock tx vout.1 is CC output");
else if ( tx.vout[1].scriptPubKey != vinTx.vout[1].scriptPubKey )
return eval->Invalid("unlock tx vout.1 mismatched scriptPubKey");
amount = vinTx.vout[0].nValue;
reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit);
if ( RewardsExactAmounts(cp,eval,tx,txfee+tx.vout[1].nValue,sbits,fundingtxid) == 0 )
return false;
else if ( tx.vout[1].nValue > amount+reward )
@@ -310,7 +316,7 @@ static uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t r
if ( tx.vout.size() > 0 && tx.vout[0].nValue >= needed )
{
const uint256 &hash = tx.GetHash();
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(hash,0) == 0 )
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,hash,0) == 0 )
{
if ( (funcid= DecodeRewardsOpRet(hash,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) == 'U' && sbits == refsbits && fundingtxid == reffundingtxid )
{
@@ -332,8 +338,12 @@ int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcont
char coinaddr[64],str[65]; uint64_t threshold,sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t numblocks,j,vout,n = 0; uint8_t funcid;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
SetCCunspents(unspentOutputs,coinaddr,true);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -346,7 +356,7 @@ int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcont
break;
if ( j != mtx.vin.size() )
continue;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
{
@@ -393,7 +403,7 @@ int64_t RewardsPlanFunds(uint64_t &lockedfunds,uint64_t refsbits,struct CCcontra
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
lockedfunds = 0;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -423,7 +433,7 @@ bool RewardsPlanExists(struct CCcontract_info *cp,uint64_t refsbits,CPubKey rewa
char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
GetCCaddress(cp,CCaddr,rewardspk);
SetCCtxids(txids,CCaddr);
SetCCtxids(txids,CCaddr,true);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
{
//int height = it->first.blockHeight;
@@ -483,7 +493,7 @@ UniValue RewardsList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits,APR,minseconds,maxseconds,mindeposit; char str[65];
cp = CCinit(&C,EVAL_REWARDS);
SetCCtxids(addressIndex,cp->normaladdr);
SetCCtxids(addressIndex,cp->normaladdr,false);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
@@ -640,7 +650,7 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2
else
{
GetCCaddress(cp,coinaddr,rewardspk);
if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 )
if ( (amount= CCutxovalue(coinaddr,locktxid,0,1)) == 0 )
{
fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr);
CCerror = "locktxid/v0 is spent";
@@ -677,8 +687,7 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2
}
else
{
firstmtx.vout.push_back(CTxOut(amount-txfee,scriptPubKey));
//CCerror = "cant find enough rewards inputs";
firstmtx.vout.push_back(CTxOut(amount-txfee*2,scriptPubKey));
fprintf(stderr,"not enough rewards funds to payout %.8f, recover mode tx\n",(double)(reward+txfee)/COIN);
return(FinalizeCCTx(-1LL,cp,firstmtx,mypk,txfee,EncodeRewardsOpRet('U',sbits,fundingtxid)));
}
@@ -703,4 +712,3 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2
fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN);
return("");
}

93
src/cc/rogue/LICENSE.TXT Normal file
View File

@@ -0,0 +1,93 @@
Rogue: Exploring the Dungeons of Doom
Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
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. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) 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 AUTHOR(S) 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.
===========================================================================
Portions of this software (state.c, mdport.c) are based on the work
of Nicholas J. Kisseberth. Used under license:
Copyright (C) 1999, 2000, 2005 Nicholas J. Kisseberth
All rights reserved.
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. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) 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 AUTHOR(S) 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.
===========================================================================
Portions of this software (xcrypt.c) are based on the work
of David Burren. Used under license:
FreeSec: libcrypt
Copyright (C) 1994 David Burren
All rights reserved.
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. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) 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 AUTHOR(S) OR CONTRIBUTORS BE LIABLE
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.

222
src/cc/rogue/Makefile.in Normal file
View File

@@ -0,0 +1,222 @@
###############################################################################
#
# Makefile for rogue
#
# Rogue: Exploring the Dungeons of Doom
# Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
# All rights reserved.
#
# See the file LICENSE.TXT for full copyright and licensing information.
#
###############################################################################
###############################################################################
# Site configuration occurs beneath this comment
# Typically ./configure (autoconf tools) configures this section
# This section could be manually configured if autoconf/configure fails
###############################################################################
DISTNAME=@PACKAGE_TARNAME@@PACKAGE_VERSION@
PACKAGE_TARNAME = @PACKAGE_TARNAME@-@PACKAGE_VERSION@
PROGRAM=@PROGRAM@
O=o
#CC=gcc
CC = @CC@
#CFLAGS=-O2
CFLAGS= @CFLAGS@ -fPIC
LIBS=-lcurses -lcurl
#LIBS = @LIBS@
#RM=rm -f
RM = rm -f
#GROFF=groff
GROFF = @GROFF@
#NROFF=nroff
NROFF = @NROFF@
#TBL=tbl
TBL = @TBL@
#COLCRT=colcrt
COLCRT = @COLCRT@
#SED=sed
SED = @SED@
#SCOREFILE=rogue54.scr
SCOREFILE = @SCOREFILE@
#LOCKFILE=rogue54.lck
LOCKFILE = @LOCKFILE@
#GROUPOWNER=games
GROUPOWNER = @GROUPOWNER@
#CPPFLAGS=-DHAVE_CONFIG_H
CPPFLAGS =@DEFS@ @CPPFLAGS@
#DISTFILE = $(PROGRAM)
DISTFILE = $(DISTNAME)-@TARGET@
INSTALL=./install-sh
#INSTGROUP=-g games
INSTGROUP=
#INSTOWNER=-u root
INSTOWNER=
CHGRP=chgrp
MKDIR=mkdir
TOUCH=touch
RMDIR=rmdir
CHMOD=chmod
DESTDIR=
prefix=@prefix@
exec_prefix=@exec_prefix@
datarootdir=@datarootdir@
datadir=@datadir@
bindir=@bindir@
mandir=@mandir@
docdir=@docdir@
man6dir = $(mandir)/man6
###############################################################################
# Site configuration occurs above this comment
# It should not be necessary to change anything below this comment
###############################################################################
HDRS = rogue.h extern.h score.h
OBJS1 = vers.$(O) extern.$(O) armor.$(O) chase.$(O) command.$(O) \
daemon.$(O) daemons.$(O) fight.$(O) init.$(O) io.$(O) list.$(O) \
mach_dep.$(O) rogue.$(O) mdport.$(O) misc.$(O) monsters.$(O) \
move.$(O) new_level.$(O)
OBJS2 = options.$(O) pack.$(O) passages.$(O) potions.$(O) rings.$(O) \
rip.$(O) rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) \
things.$(O) weapons.$(O) wizard.$(O) xcrypt.$(O)
OBJS = main.$(O) $(OBJS1) $(OBJS2)
CFILES = vers.c extern.c armor.c chase.c command.c daemon.c \
daemons.c fight.c init.c io.c list.c mach_dep.c \
main.c mdport.c misc.c monsters.c move.c new_level.c \
options.c pack.c passages.c potions.c rings.c rip.c \
rooms.c save.c scrolls.c state.c sticks.c things.c \
weapons.c wizard.c xcrypt.c
MISC_C = findpw.c scedit.c scmisc.c
DOCSRC = rogue.me.in rogue.6.in rogue.doc.in rogue.html.in rogue.cat.in
DOCS = $(PROGRAM).doc $(PROGRAM).html $(PROGRAM).cat $(PROGRAM).me \
$(PROGRAM).6
AFILES = configure Makefile.in configure.ac config.h.in config.sub config.guess \
install-sh rogue.6.in rogue.me.in rogue.html.in rogue.doc.in rogue.cat.in
MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \
rogue.png rogue.desktop
.SUFFIXES: .obj
.c.obj:
$(CC) $(CFLAGS) $(CPPFLAGS) /c $*.c
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $*.c
#$(RM) rogue.so ; $(CC) -shared -o rogue.so cursesd.c $(OBJS1) $(OBJS2); $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
$(PROGRAM): $(HDRS) $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
clean:
$(RM) $(OBJS1); $(RM) main.$(O) ; $(RM) rogue.so
$(RM) $(OBJS2)
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
$(RM) $(DISTNAME)/*
-rmdir $(DISTNAME)
maintainer-clean:
$(RM) config.h
$(RM) Makefile
$(RM) config.status
$(RM) -r autom4te.cache
$(RM) config.log
$(RM) $(PROGRAM).scr $(PROGRAM).lck
stddocs:
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.6.in > rogue.6
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.me.in > rogue.me
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.html.in > rogue,html
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.doc.in > rogue.doc
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.cat.in > rogue.cat
dist.src:
$(MAKE) $(MAKEFILE) clean
mkdir $(DISTNAME)
cp $(CFILES) $(HDRS) $(MISC) $(AFILES) $(DISTNAME)
tar cf $(DISTNAME)-src.tar $(DISTNAME)
gzip -f $(DISTNAME)-src.tar
rm -fr $(DISTNAME)
findpw: findpw.c xcrypt.o mdport.o xcrypt.o
$(CC) -s -o findpw findpw.c xcrypt.o mdport.o -lcurses
scedit: scedit.o scmisc.o vers.o mdport.o xcrypt.o
$(CC) -s -o scedit vers.o scedit.o scmisc.o mdport.o xcrypt.o -lcurses
scmisc.o scedit.o:
$(CC) -O -c $(SF) $*.c
$(PROGRAM).doc: rogue.me
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
$(GROFF) -P-c -t -me -Tascii rogue.me | $(SED) -e 's/.\x08//g' > $(PROGRAM).doc ;\
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
tbl rogue.me | $(NROFF) -me | colcrt - > $(PROGRAM).doc ;\
fi
$(PROGRAM).cat: rogue.6
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
$(GROFF) -Tascii -man rogue.6 | $(SED) -e 's/.\x08//g' > $(PROGRAM).cat ;\
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
$(NROFF) -man rogue.6 | $(COLCRT) - > $(PROGRAM).cat ;\
fi
dist: clean $(PROGRAM)
tar cf $(DISTFILE).tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTFILE).tar
install: $(PROGRAM)
-$(TOUCH) test
-if test ! -f $(DESTDIR)$(SCOREFILE) ; then $(INSTALL) -m 0664 test $(DESTDIR)$(SCOREFILE) ; fi
-$(INSTALL) -m 0755 $(PROGRAM) $(DESTDIR)$(bindir)/$(PROGRAM)
-if test "x$(GROUPOWNER)" != "x" ; then \
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(SCOREFILE) ; \
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(bindir)/$(PROGRAM) ; \
$(CHMOD) 02755 $(DESTDIR)$(bindir)/$(PROGRAM) ; \
$(CHMOD) 0464 $(DESTDIR)$(SCOREFILE) ; \
fi
-if test -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(man6dir)/$(PROGRAM).6 ; fi
-if test ! -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(mandir)/$(PROGRAM).6 ; fi
-$(INSTALL) -m 0644 rogue.doc $(DESTDIR)$(docdir)/$(PROGRAM).doc
-$(INSTALL) -m 0644 rogue.html $(DESTDIR)$(docdir)/$(PROGRAM).html
-$(INSTALL) -m 0644 rogue.cat $(DESTDIR)$(docdir)/$(PROGRAM).cat
-$(INSTALL) -m 0644 LICENSE.TXT $(DESTDIR)$(docdir)/LICENSE.TXT
-$(INSTALL) -m 0644 rogue.me $(DESTDIR)$(docdir)/$(PROGRAM).me
-if test ! -f $(DESTDIR)$(LOCKFILE) ; then $(INSTALL) -m 0666 test $(DESTDIR)$(LOCKFILE) ; $(RM) $(DESTDIR)$(LOCKFILE) ; fi
-$(RM) test
uninstall:
-$(RM) $(DESTDIR)$(bindir)/$(PROGRAM)
-$(RM) $(DESTDIR)$(man6dir)/$(PROGRAM).6
-$(RM) $(DESTDIR)$(docdir)$(PROGRAM)/$(PROGRAM).doc
-$(RM) $(DESTDIR)$(LOCKFILE)
-$(RMDIR) $(DESTDIR)$(docdir)$(PROGRAM)
reinstall: uninstall install

158
src/cc/rogue/Makefile.std Executable file
View File

@@ -0,0 +1,158 @@
#
# Makefile for rogue
# @(#)Makefile 4.21 (Berkeley) 02/04/99
#
# Rogue: Exploring the Dungeons of Doom
# Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
# All rights reserved.
#
# See the file LICENSE.TXT for full copyright and licensing information.
#
DISTNAME = rogue5.4.4
PROGRAM = rogue54
O = o
HDRS = rogue.h extern.h score.h
OBJS1 = vers.$(O) extern.$(O) armor.$(O) chase.$(O) command.$(O) \
daemon.$(O) daemons.$(O) fight.$(O) init.$(O) io.$(O) list.$(O) \
mach_dep.$(O) main.$(O) mdport.$(O) misc.$(O) monsters.$(O) \
move.$(O) new_level.$(O)
OBJS2 = options.$(O) pack.$(O) passages.$(O) potions.$(O) rings.$(O) \
rip.$(O) rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) \
things.$(O) weapons.$(O) wizard.$(O) xcrypt.$(O)
OBJS = $(OBJS1) $(OBJS2)
CFILES = vers.c extern.c armor.c chase.c command.c daemon.c \
daemons.c fight.c init.c io.c list.c mach_dep.c \
main.c mdport.c misc.c monsters.c move.c new_level.c \
options.c pack.c passages.c potions.c rings.c rip.c \
rooms.c save.c scrolls.c state.c sticks.c things.c \
weapons.c wizard.c xcrypt.c
MISC_C = findpw.c scedit.c scmisc.c
DOCSRC = rogue.me.in rogue.6.in rogue.doc.in rogue.html.in rogue.cat.in
DOCS = $(PROGRAM).doc $(PROGRAM).html $(PROGRAM).cat $(PROGRAM).me \
$(PROGRAM).6
AFILES = configure Makefile.in configure.ac config.h.in config.sub config.guess \
install-sh rogue.6.in rogue.me.in rogue.html.in rogue.doc.in rogue.cat.in
MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \
rogue.png rogue.desktop
CC = gcc
FEATURES = -DALLSCORES -DSCOREFILE=\"$(SCOREFILE)\" -DLOCKFILE=\"$(LOCKFILE)\"
CPPFLAGS =
CFLAGS = -O3
LDFLAGS =
LIBS = -lcurses
RM = rm -f
MAKEFILE = -f Makefile.std
SCOREFILE= $(PROGRAM).scr
LOCKFILE = $(PROGRAM).lck
OUTFLAG = -o
EXE =
.SUFFIXES: .obj
.c.obj:
$(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURES) /c $*.c
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURES) -c $*.c
$(PROGRAM): $(HDRS) $(OBJS) fixdocs
$(CC) $(LDFLAGS) $(OBJS) $(LIBS) $(OUTFLAG)$@$(EXE)
clean:
$(RM) $(OBJS1)
$(RM) $(OBJS2)
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe $(PROGRAM).lck
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
$(RM) $(DISTNAME)/*
dist.src:
$(MAKE) $(MAKEFILE) clean
mkdir $(DISTNAME)
cp $(CFILES) $(HDRS) $(MISC) $(AFILES) $(DISTNAME)
tar cf $(DISTNAME)-src.tar $(DISTNAME)
gzip -f $(DISTNAME)-src.tar
rm -fr $(DISTNAME)
findpw: findpw.c xcrypt.o mdport.o xcrypt.o
$(CC) -s -o findpw findpw.c xcrypt.o mdport.o -lcurses
scedit: scedit.o scmisc.o vers.o mdport.o xcrypt.o
$(CC) -s -o scedit vers.o scedit.o scmisc.o mdport.o xcrypt.o -lcurses
scmisc.o scedit.o:
$(CC) -O -c $(SF) $*.c
doc.nroff:
tbl rogue.me | nroff -me | colcrt - > rogue.doc
nroff -man rogue.6 | colcrt - > rogue.cat
doc.groff:
groff -P-c -t -me -Tascii rogue.me | sed -e 's/.\x08//g' > rogue.doc
groff -man rogue.6 | sed -e 's/.\x08//g' > rogue.cat
fixdocs:
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.6.in > $(PROGRAM).6
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.me.in > $(PROGRAM).me
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.html.in > $(PROGRAM).html
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.doc.in > $(PROGRAM).doc
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.cat.in > $(PROGRAM).cat
dist.irix:
$(MAKE) $(MAKEFILE) clean
$(MAKE) $(MAKEFILE) CC=cc $(PROGRAM)
tar cf $(DISTNAME)-irix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-irix.tar
dist.aix:
$(MAKE) $(MAKEFILE) clean
$(MAKE) $(MAKEFILE) CC=xlc CFLAGS="-qmaxmem=16768 -O3 -qstrict" $(PROGRAM)
tar cf $(DISTNAME)-aix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-aix.tar
dist.linux:
$(MAKE) $(MAKEFILE) clean
$(MAKE) $(MAKEFILE) $(PROGRAM)
tar cf $(DISTNAME)-linux.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-linux.tar
dist.interix:
@$(MAKE) $(MAKEFILE) clean
@$(MAKE) $(MAKEFILE) CFLAGS="-ansi" $(PROGRAM)
tar cf $(DISTNAME)-interix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-interix.tar
dist.cygwin:
@$(MAKE) $(MAKEFILE) --no-print-directory clean
@$(MAKE) $(MAKEFILE) CPPFLAGS="-I/usr/include/ncurses" --no-print-directory $(PROGRAM)
tar cf $(DISTNAME)-cygwin.tar $(PROGRAM).exe LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-cygwin.tar
#
# Use MINGW32-MAKE to build this target
#
dist.mingw32:
@$(MAKE) $(MAKEFILE) --no-print-directory RM="cmd /c del" clean
@$(MAKE) $(MAKEFILE) --no-print-directory CPPFLAGS="-I../pdcurses" LIBS="../pdcurses/pdcurses.a" $(PROGRAM)
cmd /c del $(DISTNAME)-mingw32.zip
zip $(DISTNAME)-mingw32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)
dist.djgpp:
@$(MAKE) $(MAKEFILE) --no-print-directory clean
@$(MAKE) $(MAKEFILE) --no-print-directory LDFLAGS="-L$(DJDIR)/LIB" \
LIBS="-lpdcurses" $(PROGRAM)
rm -f $(DISTNAME)-djgpp.zip
zip $(DISTNAME)-djgpp.zip $(PROGRAM) LICENSE.TXT $(DOCS)
#
# Use NMAKE to build this targer
#
dist.win32:
@$(MAKE) $(MAKEFILE) /NOLOGO O="obj" RM="-del" clean
@$(MAKE) $(MAKEFILE) /NOLOGO O="obj" CC="CL" \
LIBS="..\pdcurses\pdcurses.lib shell32.lib user32.lib Advapi32.lib" \
EXE=".exe" OUTFLAG="/Fe" CPPFLAGS="-I..\pdcurses" \
CFLAGS="-nologo -Ox -wd4033 -wd4716" $(PROGRAM)
-del $(DISTNAME)-win32.zip
zip $(DISTNAME)-win32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)

Some files were not shown because too many files have changed in this diff Show More