16
.github/ISSUE_TEMPLATE.md
vendored
16
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,10 +1,8 @@
|
||||
<!--- Remove text and sections that do not apply -->
|
||||
|
||||
This issue tracker is only for technical issues related to zcashd.
|
||||
This issue tracker is only for technical issues related to komodod
|
||||
|
||||
General Zcash questions and/or support requests and are best directed to the [Zcash Forums](https://forum.z.cash) or [Community Rocket.Chat](https://chat.zcashcommunity.com).
|
||||
|
||||
For reporting security vulnerabilities or for sensitive discussions with our security team, please contact [security@z.cash](mailto:security@z.cash). You can use the [GPG key](https://z.cash/gpg-pubkeys/security.asc) (fingerprint: `AF85 0445 546C 18B7 86F9 2C62 88FB 8B86 D8B5 A68C`) to send an encrypted message. The key and fingerprint are duplicated on our [Public Keys page](https://z.cash/support/pubkeys.html).
|
||||
General Komodo questions and/or support requests and are best directed to [Discord](https://komodoplatform.com/discord)
|
||||
|
||||
### Describe the issue
|
||||
Please provide a general summary of the issue you're experiencing
|
||||
@@ -21,8 +19,8 @@ Tell us what should happen
|
||||
### Actual behaviour + errors
|
||||
Tell us what happens instead including any noticable error output (any messages displayed on-screen when e.g. a crash occurred)
|
||||
|
||||
### The version of Zcash you were using:
|
||||
Run `zcashd --version` to find out
|
||||
### The version of Komodo you were using:
|
||||
Run `komodod --version` to find out
|
||||
|
||||
### Machine specs:
|
||||
- OS name + version:
|
||||
@@ -34,9 +32,9 @@ Run `zcashd --version` to find out
|
||||
- Compiler version (gcc -version):
|
||||
|
||||
### Any extra information that might be useful in the debugging process.
|
||||
This includes the relevant contents of `~/.zcash/debug.log`. You can paste raw text, attach the file directly in the issue or link to the text via a pastebin type site.
|
||||
This includes the relevant contents of `~/.komodo/debug.log`. You can paste raw text, attach the file directly in the issue or link to the text via a pastebin type site.
|
||||
Please also include any non-standard things you did during compilation (extra flags, dependency version changes etc.) if applicable.
|
||||
|
||||
### Do you have a backup of `~/.zcash` directory and/or take a VM snapshot?
|
||||
- Backing up / making a copy of the `~/.zcash` directory might help make the problem reproducible. Please redact appropriately.
|
||||
### Do you have a backup of `~/.komodo` directory and/or take a VM snapshot?
|
||||
- Backing up / making a copy of the `~/.komodo` directory might help make the problem reproducible. Please redact appropriately.
|
||||
- Taking a VM snapshot is really helpful for interactively testing fixes
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -120,3 +120,4 @@ src/komodo-cli
|
||||
src/komodod
|
||||
src/komodo-tx
|
||||
src/komodo-test
|
||||
src/wallet-utility
|
||||
|
||||
135
.travis.yml
135
.travis.yml
@@ -1,105 +1,46 @@
|
||||
<<<<<<< HEAD
|
||||
language: cpp
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: xenial
|
||||
sudo: required
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
- gcc
|
||||
before_install:
|
||||
- sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install build-essential pkg-config libcurl3-gnutls-dev libc6-dev libevent-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python zlib1g-dev wget bsdmainutils automake libssl-dev libprotobuf-dev protobuf-compiler libdb++-dev ntp ntpdate
|
||||
#install:
|
||||
|
||||
script:
|
||||
- ./zcutil/build.sh -j 5
|
||||
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update -qq; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libgnutls28-dev; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install build-essential pkg-config libcurl3-gnutls-dev libc6-dev libevent-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python zlib1g-dev wget bsdmainutils automake libssl-dev libprotobuf-dev protobuf-compiler libdb++-dev ntp ntpdate; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then rm '/usr/local/include/c++'; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gcc@6; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew link --overwrite gcc@6; fi
|
||||
script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./zcutil/build.sh -j 5; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./zcutil/build-mac.sh -j 5; fi
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#komodoplatform"
|
||||
- chat.freenode.net#komodoplatform
|
||||
template:
|
||||
- "%{repository}/%{branch} (%{commit} - %{author}): %{message}"
|
||||
- "Alt Message : %{repository_slug} - (%{commit} - %{author}): %{message}, Build Time: %{duration}"
|
||||
- "Change view : %{compare_url}"
|
||||
- "Build details : %{build_url}"
|
||||
=======
|
||||
# errata:
|
||||
# - A travis bug causes caches to trample eachother when using the same
|
||||
# compiler key (which we don't use anyway). This is worked around for now by
|
||||
# replacing the "compilers" with a build name prefixed by the no-op ":"
|
||||
# command. See: https://github.com/travis-ci/travis-ci/issues/4393
|
||||
# - sudo/dist/group are set so as to get Blue Box VMs, necessary for [loopback]
|
||||
# IPv6 support
|
||||
|
||||
sudo: required
|
||||
dist: precise
|
||||
group: legacy
|
||||
|
||||
os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env:
|
||||
global:
|
||||
- MAKEJOBS=-j3
|
||||
- RUN_TESTS=false
|
||||
- BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID
|
||||
- CCACHE_SIZE=100M
|
||||
- CCACHE_TEMPDIR=/tmp/.ccache-temp
|
||||
- CCACHE_COMPRESS=1
|
||||
- BASE_OUTDIR=$TRAVIS_BUILD_DIR/out
|
||||
- SDK_URL=https://bitcoincore.org/depends-sources/sdks
|
||||
- PYTHON_DEBUG=1
|
||||
- WINEDEBUG=fixme-all
|
||||
cache:
|
||||
apt: true
|
||||
directories:
|
||||
- depends/built
|
||||
- depends/sdk-sources
|
||||
- $HOME/.ccache
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- compiler: ": ARM"
|
||||
env: HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="" GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
|
||||
- compiler: ": Win32"
|
||||
env: HOST=i686-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-reduce-exports" MAKEJOBS="-j2"
|
||||
- compiler: ": 32-bit + dash"
|
||||
env: HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc python-zmq" PPA="ppa:chris-lea/zeromq" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash"
|
||||
- compiler: ": Win64"
|
||||
env: HOST=x86_64-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-reduce-exports" MAKEJOBS="-j2"
|
||||
- compiler: ": bitcoind"
|
||||
env: HOST=x86_64-unknown-linux-gnu PACKAGES="bc python-zmq" PPA="ppa:chris-lea/zeromq" DEP_OPTS="DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER"
|
||||
- compiler: ": No wallet"
|
||||
env: HOST=x86_64-unknown-linux-gnu DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
|
||||
- compiler: ": Cross-Mac"
|
||||
env: HOST=x86_64-apple-darwin11 PACKAGES="cmake libcap-dev libz-dev libbz2-dev" BITCOIN_CONFIG="--enable-reduce-exports" OSX_SDK=10.9 GOAL="deploy"
|
||||
exclude:
|
||||
- compiler: gcc
|
||||
install:
|
||||
- if [ -n "$PACKAGES" ]; then sudo rm -f /etc/apt/sources.list.d/travis_ci_zeromq3-source.list; fi
|
||||
- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi
|
||||
- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi
|
||||
before_script:
|
||||
- unset CC; unset CXX
|
||||
- mkdir -p depends/SDKs depends/sdk-sources
|
||||
- if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
|
||||
- if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
|
||||
- make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS
|
||||
script:
|
||||
- if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi
|
||||
- OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST
|
||||
- BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib"
|
||||
- depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE
|
||||
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then export CCACHE_READONLY=1; fi
|
||||
- test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh
|
||||
- ./configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false)
|
||||
- make distdir PACKAGE=bitcoin VERSION=$HOST
|
||||
- cd bitcoin-$HOST
|
||||
- ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false)
|
||||
- make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false )
|
||||
- export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib
|
||||
- if [ "$RUN_TESTS" = "true" ]; then make check; fi
|
||||
- if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.sh; fi
|
||||
after_script:
|
||||
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then (echo "Upload goes here. Something like: scp -r $BASE_OUTDIR server" || echo "upload failed"); fi
|
||||
>>>>>>> zcash/master
|
||||
- "%{repository}/%{branch} (%{commit} - %{author}): %{message}"
|
||||
- 'Alt Message : %{repository_slug} - (%{commit} - %{author}): %{message}, Build
|
||||
Time: %{duration}'
|
||||
- 'Change view : %{compare_url}'
|
||||
- 'Build details : %{build_url}'
|
||||
before_deploy:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git tag "linux-$(date +'%Y%m%d%H%M')-$(git log --format=%h -1)"; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then git tag "osx-$(date +'%Y%m%d%H%M')-$(git log --format=%h -1)"; fi
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: Jms7dz5GMZmuXUCHl5u6iZUtAybv86oW3x36DCJfdzbDiO4B9EWB04z7zA0qvoomefyujHTmQUHxyOKfd4h9/rVMFFv9hgmUxWkrcg7KyLNisOQRaovVOuNtu2lRNXTOSF16Cy+xFGkVh1ObBRhAoMsVKPhMl6PCDiKhNWIekRR9pBtjafKsClQ2ieknUYfqhuvgj7zmqCedeyVaVQyt2W/J65leD0BkfCUESTpANSprHs4bQB65VuQIKKMi+URKx2VgpDdUcWJySt9jAHVPIbI5cT5maAT6RUMnE4oha7Ca1Ox8StBqjQ/hkkMyDbN0keIlN7RjZlwdZQf/qUnT/dPQhsyUCdPXOxmEJ2jekezEK/LGr4Fb+v+vjd9dhLNkD5nVn9zp36biGSCjiMpffQ3fjMeM0YGmVEVRP9kZXLWVRYQoVKrzjyzg5dY8iChbiQEfYpTeBuU+e2rqj4mns+Jvy0zjUbMy6Tyva+iqdZ/PdsBDbiB7c+FIgB1IUTVOD+GgKx6dhCtBZEccn5EyWFwZF9IdQJHZCYV4PA7nuzfm1Ol9SDdZkGHd2OgRCqK/sTwyfTHv8exNqZ1k+epGJp2a0q4IOEknc9aPCAF+m9pHahk7s7VO5gmhO6pvbvuKoeEtEXRZHRzCkGkXfzJlBk+23X5gBexKb6inRdBlj6M=
|
||||
file:
|
||||
- src/komodod
|
||||
- src/komodo-cli
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: KomodoPlatform/komodo
|
||||
|
||||
1
COPYING
1
COPYING
@@ -1,3 +1,4 @@
|
||||
Copyright (c) 2016-2018 The Komodo developers
|
||||
Copyright (c) 2016-2017 The Zcash developers
|
||||
Copyright (c) 2009-2017 The Bitcoin Core developers
|
||||
|
||||
|
||||
219
README.md
219
README.md
@@ -1,26 +1,34 @@
|
||||
## Komodo with Bitcore
|
||||
This version of Komodo contains Bitcore support for komodo and all its assetchains.
|
||||
[](https://travis-ci.org/KomodoPlatform/komodo)
|
||||
---
|
||||

|
||||
|
||||
## Komodod
|
||||
This software is Komodo client, generally you will use this if you want to mine KMD or setup a full node.
|
||||
It downloads and stores the entire history of Komodo transactions; depending on the speed of your computer and network connection, the synchronization process could take a day or more once the blockchain has reached a significant size.
|
||||
|
||||
## Komodo
|
||||
|
||||
This is the official Komodo sourcecode repository based on https://github.com/jl777/komodo.
|
||||
|
||||
## Development Resources
|
||||
- Komodo Web: [https://komodoplatform.com/](https://komodoplatform.com/)
|
||||
- Organization web: [https://komodoplatform.com/](https://komodoplatform.com/)
|
||||
|
||||
- Komodo Website: [https://komodoplatform.com/](https://komodoplatform.com/)
|
||||
- Komodo Blockexplorer: [https://kmdexplorer.io//](https://https://kmdexplorer.io/)
|
||||
- Forum: [https://forum.komodoplatform.com/](https://forum.komodoplatform.com/)
|
||||
- Mail: [info@komodoplatform.com](mailto:info@komodoplatform.com)
|
||||
- Support: [https://support.komodoplatform.com/support/home](https://support.komodoplatform.com/support/home)
|
||||
- Knowledgebase & How-to: [https://komodoplatform.atlassian.net/wiki/spaces/KPSD/pages](https://komodoplatform.atlassian.net/wiki/spaces/KPSD/pages)
|
||||
- API references: [http://docs.supernet.org/](http://docs.supernet.org/) #Not up to date.
|
||||
- API references: [http://docs.komodoplatform.com/](http://docs.komodoplatform.com/)
|
||||
- Blog: [http://blog.komodoplatform.com/](http://blog.komodoplatform.com/)
|
||||
- Whitepaper: [Komodo Whitepaper](https://komodoplatform.com/wp-content/uploads/2018/03/2018-03-12-Komodo-White-Paper-Full.pdf)
|
||||
- Komodo Platform public material: [Komodo Platform public material](https://docs.google.com/document/d/1AbhWrtagu4vYdkl-vsWz-HSNyNvK-W-ZasHCqe7CZy0)
|
||||
|
||||
## List of Komodo Platform Technologies
|
||||
- Delayed Proof of Work (dPoW) - Additional security layer.
|
||||
- zk-SNARKs - Komodo Platform's privacy technology
|
||||
|
||||
- Delayed Proof of Work (dPoW) - Additional security layer and Komodos own consensus algorithm.
|
||||
- zk-SNARKs - Komodo Platform's privacy technology for shielded transactions
|
||||
- Tokens/Assets Technology - create "colored coins" on the Komodo Platform and use them as a layer for securites
|
||||
- Reward API - Komodo CC technology for securities
|
||||
- CC - Crypto Conditions to realize "smart contract" logic on top of the Komodo Platform
|
||||
- Jumblr - Decentralized tumbler for KMD and other cryptocurrencies
|
||||
- Assetchains - Easy way to fork Komodo coin
|
||||
- Assetchains - Create your own Blockchain that inherits all Komodo Platform functionalities and blockchain interoperability
|
||||
- Pegged Assets - Chains that maintain a peg to fiat currencies
|
||||
- Peerchains - Scalability solution where sibling chains form a network of blockchains
|
||||
- More in depth covered [here](https://docs.google.com/document/d/1AbhWrtagu4vYdkl-vsWz-HSNyNvK-W-ZasHCqe7CZy0)
|
||||
@@ -31,77 +39,76 @@ It downloads and stores the entire history of Komodo transactions; depending on
|
||||
- Max Supply: 200 million KMD.
|
||||
- Block Time: 1M 2s
|
||||
- Block Reward: 3KMD
|
||||
- Mining Algorithm: Equihash
|
||||
- Mining Algorithm: Equihash
|
||||
|
||||
## About this Project
|
||||
Komodo is based on Zcash and has been by our innovative consensus algorithm called dPoW which utilizes Bitcoin's hashrate to store Komodo blockchain information into the Bitcoin blockchain. Other new and native Komodo features are the privacy technology called JUMBLR or our assetchain capabilities (one click plug and play blockchain solutions). More details are available under https://komodoplatform.com/.
|
||||
Komodo is based on Zcash and has been extended by our innovative consensus algorithm called dPoW which utilizes Bitcoin's hashrate to store Komodo blockchain information into the Bitcoin blockchain. Other new and native Komodo features are the privacy technology called JUMBLR, our assetchain capabilities (one click plug and play blockchain solutions) and a set of financial decentralization and interoperability technologies. More details are available under https://komodoplatform.com/ and https://blog.komodoplatform.com.
|
||||
|
||||
## Getting started
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
### Dependencies
|
||||
|
||||
```shell
|
||||
#The following packages are needed:
|
||||
sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python python-zmq zlib1g-dev wget libcurl4-openssl-dev bsdmainutils automake curl
|
||||
```
|
||||
|
||||
Komodo
|
||||
------
|
||||
We have a release process that goes through several stages before it reaches master. This allows the most conservative users just use the master branch, which is only updated after the other branches have signed off on a release.
|
||||
### Build Komodo
|
||||
|
||||
99% of the activity is in the dev branch, this is where I am testing each change one by one and there are literally thousands of updates. Only use this branch if you really want to be on the bleeding edge. I try to keep things stable, but there are times where necessarily there are bugs in the dev branch, since I am actively developing and debugging here. A good rule is to wait for at least 4 hours from the last update before using the dev branch (unless you know what you are doing)
|
||||
This software is based on zcash and considered experimental and is continously undergoing heavy development.
|
||||
|
||||
After things look good in the dev branch, it is propagated to the beta branch, this is the version the notary nodes use. They are knowledegable command line server guys and so they have a keen eye for anything that wasnt caught during the dev cycle.
|
||||
|
||||
After the notary nodes verify things are working and the latest release is deemed stable, it is propagated to the dPoW branch. From here an automated Jenkins process builds it for all OS, and since the notary nodes are all unix, it is possible for some issues to be caught at this stage. The dPoW branch is what goes into the GUI installers.
|
||||
|
||||
After the GUI are updated and released and it is verified that no significant support issues were created, the master branch is finally updated.
|
||||
|
||||
Master branch: exchanges and users that build from the repo without changing branches
|
||||
dPoW branch: autobuild into GUI installers, unix, osx, windows
|
||||
beta branch: notary nodes, command line unix
|
||||
dev branch: bleeding edge, possibly wont even compile, multiple updates per hour
|
||||
The dev branch is considered the bleeding edge codebase while the master-branch is considered tested (unit tests, runtime tests, functionality). At no point of time do the Komodo Platform developers take any responsbility for any damage out of the usage of this software.
|
||||
Komodo builds for all operating systems out of the same codebase. Follow the OS specific instructions from below.
|
||||
|
||||
#### Linux
|
||||
```shell
|
||||
git clone https://github.com/jl777/komodo
|
||||
git clone https://github.com/komodoplatform/komodo --branch master --single-branch
|
||||
cd komodo
|
||||
#you might want to: git checkout <branch>; git pull
|
||||
./zcutil/fetch-params.sh
|
||||
# -j8 uses 8 threads - replace 8 with number of threads you want to use
|
||||
# -j8 = using 8 threads for the compilation - replace 8 with number of threads you want to use
|
||||
./zcutil/build.sh -j8
|
||||
#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:
|
||||
```shell
|
||||
brew update && brew install gcc@6
|
||||
git clone https://github.com/komodoplatform/komodo --branch master --single-branch
|
||||
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.
|
||||
```
|
||||
|
||||
#### Windows
|
||||
Use a debian cross-compilation setup with mingw for windows and run:
|
||||
```shell
|
||||
git clone https://github.com/komodoplatform/komodo --branch master --single-branch
|
||||
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-win.sh -j8
|
||||
#This can take some time.
|
||||
```
|
||||
**komodo is experimental and a work-in-progress.** Use at your own risk.
|
||||
|
||||
Deprecation Policy
|
||||
------------------
|
||||
To reset the Komodo blockchain change into the *~/.komodo* data directory and delete the corresponding files by running `rm -rf blocks chainstate debug.log komodostate db.log`
|
||||
|
||||
This release is considered deprecated one year after the release day. There
|
||||
is an automatic deprecation shutdown feature which will halt the node some
|
||||
time after this one year period. The automatic feature is based on block
|
||||
height and can be explicitly disabled.
|
||||
#### Create komodo.conf
|
||||
|
||||
|
||||
# to update an existing version, `git checkout dPoW` if not on that branch already
|
||||
```shell
|
||||
git pull
|
||||
./zcutil/fetch-params.sh
|
||||
./zcutil/build.sh -j8
|
||||
```
|
||||
To reset the blockchain, from *~/.komodo* `rm -rf blocks chainstate debug.log komodostate db.log`
|
||||
|
||||
Create komodo.conf
|
||||
------------------
|
||||
Create a komodo.conf file:
|
||||
|
||||
```
|
||||
cd ~
|
||||
mkdir .komodo
|
||||
cd .komodo
|
||||
pico komodo.conf
|
||||
mkdir ~/.komodo
|
||||
cd ~/.komodo
|
||||
touch komodo.conf
|
||||
|
||||
#Add the following lines to the komodo.conf file:
|
||||
rpcuser=bitcoinrpc
|
||||
rpcpassword=password
|
||||
rpcuser=yourrpcusername
|
||||
rpcpassword=yoursecurerpcpassword
|
||||
rpcbind=127.0.0.1
|
||||
txindex=1
|
||||
addnode=5.9.102.210
|
||||
addnode=78.47.196.146
|
||||
@@ -111,58 +118,22 @@ addnode=5.9.122.241
|
||||
addnode=144.76.94.38
|
||||
addnode=89.248.166.91
|
||||
```
|
||||
### Create your own Blockchain based on Komodo
|
||||
|
||||
Start mining
|
||||
------------
|
||||
Komodo allows anyone to create a runtime fork which represents an independent Blockchain. Below are the detailed instructions:
|
||||
Setup two independent servers with at least 1 server having a static IP and build komodod on those servers.
|
||||
|
||||
#### On server 1 (with static IP) run:
|
||||
```shell
|
||||
#iguana documentation shows how to get the btcpubkey and wifstrs that need to be used
|
||||
#bitcoin also need to be installed with txindex=1 and with rpc enabled
|
||||
cd ~
|
||||
cd komodo
|
||||
#This will return your pubkey eg. "0259e137e5594cf8287195d13aed816af75bd5c04ae673296b51f66e7e8346e8d8" for your address
|
||||
./src/komodo-cli validateaddress <yourwalletaddres>
|
||||
#This will give the privkey of your wallet address
|
||||
./src/komodo-cli dumpprivkey <yourwalletaddres>
|
||||
#This will import the privkey to be sure the mined coins are placed into your wallet address
|
||||
./src/komodo-cli importprivkey <yourwalletprivkey>
|
||||
#To stop the daemon:
|
||||
./src/komodo-cli stop
|
||||
#This starts komodo notary - replace genproclimit with number of threads you want to use and add your pubkey
|
||||
./src/komodod -gen -genproclimit=2 -notary -pubkey="0259e137e5594cf8287195d13aed816af75bd5c04ae673296b51f66e7e8346e8d8" &
|
||||
#This will get the stats:
|
||||
./src/komodo-cli getinfo
|
||||
#To view the process:
|
||||
ps -ef | grep komodod
|
||||
#To stop the daemon:
|
||||
./src/komodo-cli stop
|
||||
|
||||
#To view komodod output:
|
||||
tail -f ~/.komodo/debug.log
|
||||
#To view all command
|
||||
./src/komodo-cli help
|
||||
ASSETCHAINS: -ac_name=name -ac_supply=nnnnn
|
||||
Both komodod and komodo-cli recognize -ac_name=option so you can create fork from the commandline
|
||||
./komodod -ac_name=name_of_your_chain -ac_supply=100000 -bind=ip_of_server_1 &
|
||||
```
|
||||
=======
|
||||
**Zcash is unfinished and highly experimental.** Use at your own risk.
|
||||
|
||||
Where do I begin?
|
||||
-----------------
|
||||
We have a guide for joining the main Zcash network:
|
||||
https://github.com/zcash/zcash/wiki/1.0-User-Guide
|
||||
#### On server 2 run:
|
||||
```shell
|
||||
./komodod -ac_name=name_of_your_chain -ac_supply=100000 -addnode=ip_of_server_1 -gen &
|
||||
```
|
||||
|
||||
### Need Help?
|
||||
* See the documentation at the [Zcash Wiki](https://github.com/zcash/zcash/wiki)
|
||||
for help and more information.
|
||||
* Ask for help on the [Zcash](https://forum.z.cash/) forum.
|
||||
Participation in the Zcash project is subject to a
|
||||
[Code of Conduct](code_of_conduct.md).
|
||||
|
||||
Building
|
||||
--------
|
||||
Build Zcash along with most dependencies from source by running
|
||||
`./zcutil/build.sh`. Currently only Linux is officially supported.
|
||||
**Komodo is based on Zcash which is unfinished and highly experimental.** Use at your own risk.
|
||||
|
||||
License
|
||||
-------
|
||||
@@ -175,11 +146,8 @@ There is a small chance that an outbound transaction will give an error due to m
|
||||
**To change modes:**
|
||||
|
||||
a) backup all privkeys (launch komodod with `-exportdir=<path>` and `dumpwallet`)
|
||||
|
||||
b) start a totally new sync including `wallet.dat`, launch with same `exportdir`
|
||||
|
||||
c) stop it before it gets too far and import all the privkeys from a) using `komodo-cli importwallet filename`
|
||||
|
||||
d) resume sync till it gets to chaintip
|
||||
|
||||
For example:
|
||||
@@ -191,44 +159,11 @@ mv ~/.komodo ~/.komodo.old && mkdir ~/.komodo && cp ~/.komodo.old/komodo.conf ~/
|
||||
./komodod -exchange -exportdir=/tmp &
|
||||
./komodo-cli importwallet /tmp/example
|
||||
```
|
||||
|
||||
## JUMBLR
|
||||
komodod now has `jumblr_deposit` and `jumblr_secret` RPC calls.
|
||||
|
||||
Jumblr works like described previously where all the nodes with jumblr active synchronize their tx activity during the same block to maximize the mixing effect. However, unlike all other mixers/tumblers, you never give up control of your coins to anybody else. JUMBLR uses a one to many allocation of funds, ie. one deposit address and many secret addresses. You can always run multiple komodod daemons to get multiple active deposit addresses.
|
||||
|
||||
JUMBLR implements t -> z, z -> z and z -> t transactions to maximize privacy of the destination t (transparent) address. So while it is transparent, its first activity is funds coming from an untracable z address.
|
||||
|
||||
Which of the three stages is done is randomly selected at each turn. Also when there is more than one possible transaction at the selected stage, a random one is selected. This randomization prevents analyzing incoming z ->t transactions by its size to correlate it to the originating address.
|
||||
|
||||
`jumblr_deposit <depositaddr>` designates the deposit address as the jumblr deposit address for that session. You can select an address that already has funds in it and it will immediately start jumblr process. If there are no funds, it will wait until you send funds to it.
|
||||
|
||||
There are three sizes of a jumblr transaction: 10 KMD, 100 KMD and 1000 KMD. There is also a fixed interval of blocks where all jumblr nodes are active. Currently it is set to be 10, but this is subject to change. Only during every 10*10 blocks are the largest 1000 KMD transactions processed, so this concentrates all the large transactions every N*N blocks.
|
||||
|
||||
`jumblr_secret <secretaddress>` notifies JUMBLR where to send the final z -> t transactions. In order to allow larger accounts to obtain privacy, up to 777 secret addresses are supported. Whenever a z -> t stage is activated, a random secret address from the list of the then active secret addresses is selected.
|
||||
|
||||
#### Practical Advice:
|
||||
Obtaining privacy used to be very difficult. JUMBLR makes it as simple as issuing two command line calls. Higher level layers can be added to help manage the addresses, ie. linking them at the passphrase level. Such matters are left to each implementation.
|
||||
|
||||
Once obtained, it is very easy to lose all the privacy. With a single errant transaction that combines some previously used address and the secretaddress, well, the secretaddress is no longer so private.
|
||||
|
||||
The advice is to setup a totally separate node!
|
||||
|
||||
This might seem a bit drastic, but if you want to maintain privacy, it is best to make it look like all the transactions are coming from a different node. The easiest way for most people to do this is to actually have a different node.
|
||||
|
||||
It can be a dedicated laptop (recommended) or a VPS (for smaller amounts) with a totally fresh komodod wallet. Generate an address on this wallet and use that as the jumblr_secret address on your main node. As the JUMBLR operates funds will teleport into your secret node's address. If you are careful and never use the same IP address for both your nodes, you will be able to maintain very good privacy.
|
||||
|
||||
Of course, don't send emails that link the two accounts together! Dont use secret address funds for home delivery purchases! Etc. There are many ways to lose the privacy, just think about what linkages can be dont at the IP and blockchain level and that should be a useful preparation.
|
||||
|
||||
What if you have 100,000 KMD and you dont want others to know you are such a whale?
|
||||
Instead of generating 1 secret address, generate 100 and make a script file with:
|
||||
```shell
|
||||
./komodo-cli jumblr_secret <addr0>
|
||||
./komodo-cli jumblr_secret <addr1>
|
||||
...
|
||||
./komodo-cli jumblr_secret <addr99>
|
||||
```
|
||||
And make sure to delete all traces of this when the JUMBLR is finished. You will end up with 100 addresses that have an average of 1000 KMD each. So as long as you are careful and dont do a 10,000 KMD transaction (that will link 10 of your secret addresses together), you can appear as 100 different people each with 1000 KMD.
|
||||
---
|
||||
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
140
contrib/debian/examples/komodo.conf
Normal file
140
contrib/debian/examples/komodo.conf
Normal file
@@ -0,0 +1,140 @@
|
||||
##
|
||||
## komodo.conf configuration file. Lines beginning with # are comments.
|
||||
##
|
||||
|
||||
# Network-related settings:
|
||||
|
||||
# Run a regression test network
|
||||
#regtest=0
|
||||
|
||||
# Connect via a SOCKS5 proxy
|
||||
#proxy=127.0.0.1:9050
|
||||
|
||||
# Bind to given address and always listen on it. Use [host]:port notation for IPv6
|
||||
#bind=<addr>
|
||||
|
||||
# Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6
|
||||
#whitebind=<addr>
|
||||
|
||||
##############################################################
|
||||
## Quick Primer on addnode vs connect ##
|
||||
## Let's say for instance you use addnode=4.2.2.4 ##
|
||||
## addnode will connect you to and tell you about the ##
|
||||
## nodes connected to 4.2.2.4. In addition it will tell ##
|
||||
## the other nodes connected to it that you exist so ##
|
||||
## they can connect to you. ##
|
||||
## connect will not do the above when you 'connect' to it. ##
|
||||
## It will *only* connect you to 4.2.2.4 and no one else.##
|
||||
## ##
|
||||
## So if you're behind a firewall, or have other problems ##
|
||||
## finding nodes, add some using 'addnode'. ##
|
||||
## ##
|
||||
## If you want to stay private, use 'connect' to only ##
|
||||
## connect to "trusted" nodes. ##
|
||||
## ##
|
||||
## If you run multiple nodes on a LAN, there's no need for ##
|
||||
## all of them to open lots of connections. Instead ##
|
||||
## 'connect' them all to one node that is port forwarded ##
|
||||
## and has lots of connections. ##
|
||||
## Thanks goes to [Noodle] on Freenode. ##
|
||||
##############################################################
|
||||
|
||||
# Use as many addnode= settings as you like to connect to specific peers
|
||||
#addnode=69.164.218.197
|
||||
#addnode=10.0.0.2:8233
|
||||
|
||||
# Alternatively use as many connect= settings as you like to connect ONLY to specific peers
|
||||
#connect=69.164.218.197
|
||||
#connect=10.0.0.1:8233
|
||||
|
||||
# Listening mode, enabled by default except when 'connect' is being used
|
||||
#listen=1
|
||||
|
||||
# Maximum number of inbound+outbound connections.
|
||||
#maxconnections=
|
||||
|
||||
#
|
||||
# JSON-RPC options (for controlling a running Komodo/komodod process)
|
||||
#
|
||||
|
||||
# server=1 tells komodod to accept JSON-RPC commands (set as default if not specified)
|
||||
#server=1
|
||||
|
||||
# Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6.
|
||||
# This option can be specified multiple times (default: bind to all interfaces)
|
||||
#rpcbind=<addr>
|
||||
|
||||
# You must set rpcuser and rpcpassword to secure the JSON-RPC api
|
||||
#rpcuser=Ulysses
|
||||
#rpcpassword=YourSuperGreatPasswordNumber_DO_NOT_USE_THIS_OR_YOU_WILL_GET_ROBBED_385593
|
||||
|
||||
# How many seconds komodo will wait for a complete RPC HTTP request.
|
||||
# after the HTTP connection is established.
|
||||
#rpcclienttimeout=30
|
||||
|
||||
# By default, only RPC connections from localhost are allowed.
|
||||
# Specify as many rpcallowip= settings as you like to allow connections from other hosts,
|
||||
# either as a single IPv4/IPv6 or with a subnet specification.
|
||||
|
||||
# NOTE: opening up the RPC port to hosts outside your local trusted network is NOT RECOMMENDED,
|
||||
# because the rpcpassword is transmitted over the network unencrypted and also because anyone
|
||||
# that can authenticate on the RPC port can steal your keys + take over the account running komodod
|
||||
# For more information see https://github.com/zcash/zcash/issues/1497
|
||||
|
||||
#rpcallowip=10.1.1.34/255.255.255.0
|
||||
#rpcallowip=1.2.3.4/24
|
||||
#rpcallowip=2001:db8:85a3:0:0:8a2e:370:7334/96
|
||||
|
||||
# Listen for RPC connections on this TCP port:
|
||||
#rpcport=8232
|
||||
|
||||
# You can use Komodo or komodod to send commands to Komodo/komodod
|
||||
# running on another host using this option:
|
||||
#rpcconnect=127.0.0.1
|
||||
|
||||
# Transaction Fee
|
||||
|
||||
# Send transactions as zero-fee transactions if possible (default: 0)
|
||||
#sendfreetransactions=0
|
||||
|
||||
# Create transactions that have enough fees (or priority) so they are likely to # begin confirmation within n blocks (default: 1).
|
||||
# This setting is overridden by the -paytxfee option.
|
||||
#txconfirmtarget=n
|
||||
|
||||
# Miscellaneous options
|
||||
|
||||
# Enable attempt to mine komodo.
|
||||
#gen=0
|
||||
|
||||
# Set the number of threads to be used for mining komodo (-1 = all cores).
|
||||
#genproclimit=1
|
||||
|
||||
# Specify a different Equihash solver (e.g. "tromp") to try to mine komodo
|
||||
# faster when gen=1.
|
||||
#equihashsolver=default
|
||||
|
||||
# Pre-generate this many public/private key pairs, so wallet backups will be valid for
|
||||
# both prior transactions and several dozen future transactions.
|
||||
#keypool=100
|
||||
|
||||
# Pay an optional transaction fee every time you send komodo. Transactions with fees
|
||||
# are more likely than free transactions to be included in generated blocks, so may
|
||||
# be validated sooner. This setting does not affect private transactions created with
|
||||
# 'z_sendmany'.
|
||||
#paytxfee=0.00
|
||||
|
||||
#Rewind the chain to specific block height. This is useful for creating snapshots at a given block height.
|
||||
#rewind=777777
|
||||
|
||||
#Stop the chain a specific block height. This is useful for creating snapshots at a given block height.
|
||||
#stopat=1000000
|
||||
|
||||
#Set an address to use as change address for all transactions. This value must be set to a 33 byte pubkey. All mined coins will also be sent to this address.
|
||||
#pubkey=027dc7b5cfb5efca96674b45e9fda18df069d040b9fd9ff32c35df56005e330392
|
||||
|
||||
#Forfeit all user rewards to miners. Set this to explicitly not claim user rewards.
|
||||
#exchange=1
|
||||
|
||||
#Donate all user rewards to a a specific address. This value must be set to a 33 byte pubkey.
|
||||
#donation=027dc7b5cfb5efca96674b45e9fda18df069d040b9fd9ff32c35df56005e330392
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package=googletest
|
||||
$(package)_version=1.8.0
|
||||
$(package)_download_path=https://github.com/google/$(package)/archive/
|
||||
$(package)_download_path=https://github.com/google/$(package)/archive
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_download_file=release-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=58a6f4277ca2bc8565222b3bbd58a177609e9c488e8a72649359ba51450db7d8
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package=libevent
|
||||
$(package)_version=2.1.8
|
||||
$(package)_download_path=https://github.com/libevent/libevent/archive/
|
||||
$(package)_download_path=https://github.com/libevent/libevent/archive
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_download_file=release-$($(package)_version)-stable.tar.gz
|
||||
$(package)_sha256_hash=316ddb401745ac5d222d7c529ef1eada12f58f6376a66c1118eee803cb70f83d
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package=libgmp
|
||||
|
||||
ifeq ($(host_os),mingw32)
|
||||
$(package)_download_path=https://github.com/joshuayabut/$(package)/archive/
|
||||
$(package)_download_path=https://github.com/joshuayabut/$(package)/archive
|
||||
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
|
||||
$(package)_download_file=$($(package)_git_commit).tar.gz
|
||||
$(package)_sha256_hash=193836c1acc9dc00fe2521205d7bbe1ba13263f6cbef6f02584bf6f8b34b108f
|
||||
@@ -9,7 +9,7 @@ $(package)_git_commit=053c03b1cab347671d936f43ef66b48ab5e380ee
|
||||
$(package)_dependencies=
|
||||
$(package)_config_opts=--enable-cxx --disable-shared
|
||||
else ifeq ($(build_os),darwin)
|
||||
$(package)_download_path=https://github.com/ca333/$(package)/archive/
|
||||
$(package)_download_path=https://github.com/ca333/$(package)/archive
|
||||
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
|
||||
$(package)_download_file=$($(package)_git_commit).tar.gz
|
||||
$(package)_sha256_hash=59b2c2b5d58fdf5943bfde1fa709e9eb53e7e072c9699d28dc1c2cbb3c8cc32c
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package=librustzcash
|
||||
$(package)_version=0.1
|
||||
$(package)_download_path=https://github.com/zcash/$(package)/archive/
|
||||
$(package)_download_path=https://github.com/zcash/$(package)/archive
|
||||
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
|
||||
$(package)_download_file=$($(package)_git_commit).tar.gz
|
||||
$(package)_sha256_hash=a5760a90d4a1045c8944204f29fa2a3cf2f800afee400f88bf89bbfe2cce1279
|
||||
|
||||
@@ -9,7 +9,7 @@ $(package)_config_opts=
|
||||
else
|
||||
package=libsodium
|
||||
$(package)_version=1.0.15
|
||||
$(package)_download_path=https://download.libsodium.org/libsodium/releases/
|
||||
$(package)_download_path=https://download.libsodium.org/libsodium/releases
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=fb6a9e879a2f674592e4328c5d9f79f082405ee4bb05cb6e679b90afe9e178f4
|
||||
$(package)_dependencies=
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ifeq ($(host_os),mingw32)
|
||||
$(package)_version=4.2.2-1
|
||||
$(package)_download_path=https://github.com/ca333/libzmq/archive/
|
||||
$(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
|
||||
|
||||
43
migratecoin.sh
Normal file
43
migratecoin.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# This script makes the neccesary transactions to migrate
|
||||
# coin between 2 assetchains on the same -ac_cc id
|
||||
|
||||
set -e
|
||||
|
||||
source=TXSCL
|
||||
target=TXSCL000
|
||||
address="RFw7byY4xZpZCrtkMk3nFuuG1NTs9rSGgQ"
|
||||
amount=1
|
||||
|
||||
# Alias for running cli on source chain
|
||||
cli_source="komodo-cli -ac_name=$source"
|
||||
|
||||
# Raw tx that we will work with
|
||||
txraw=`$cli_source createrawtransaction "[]" "{\"$address\":$amount}"`
|
||||
|
||||
# Convert to an export tx
|
||||
exportData=`$cli_source migrate_converttoexport $txraw $target $amount`
|
||||
exportRaw=`echo $exportData | jq -r .exportTx`
|
||||
exportPayouts=`echo $exportData | jq -r .payouts`
|
||||
|
||||
# Fund
|
||||
exportFundedData=`$cli_source fundrawtransaction $exportRaw`
|
||||
exportFundedTx=`echo $exportFundedData | jq -r .hex`
|
||||
|
||||
# Sign
|
||||
exportSignedData=`$cli_source signrawtransaction $exportFundedTx`
|
||||
exportSignedTx=`echo $exportSignedData | jq -r .hex`
|
||||
|
||||
# Send
|
||||
echo "Sending export tx"
|
||||
$cli_source sendrawtransaction $exportSignedTx
|
||||
|
||||
read -p "Wait for a notarisation to KMD, and then two more notarisations from the target chain, and then press enter to continue"
|
||||
|
||||
# Create import
|
||||
importTx=`$cli_source migrate_createimporttransaction $exportSignedTx $payouts`
|
||||
importTx=`komodo-cli migrate_completeimporttransaction $importTx`
|
||||
|
||||
# Send import
|
||||
komodo-cli -ac_name=$target sendrawtransaction $importTx
|
||||
@@ -11,6 +11,7 @@ export BITCOIND=${REAL_BITCOIND}
|
||||
#Run the tests
|
||||
|
||||
testScripts=(
|
||||
'cryptoconditions.py'
|
||||
'paymentdisclosure.py'
|
||||
'prioritisetransaction.py'
|
||||
'wallet_treestate.py'
|
||||
|
||||
@@ -13,6 +13,6 @@ EXEEXT="@EXEEXT@"
|
||||
@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=1
|
||||
@ENABLE_PROTON_TRUE@ENABLE_PROTON=1
|
||||
|
||||
REAL_BITCOIND="$BUILDDIR/src/zcashd${EXEEXT}"
|
||||
REAL_BITCOINCLI="$BUILDDIR/src/zcash-cli${EXEEXT}"
|
||||
REAL_BITCOIND="$BUILDDIR/src/komodod${EXEEXT}"
|
||||
REAL_BITCOINCLI="$BUILDDIR/src/komodo-cli${EXEEXT}"
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ Possible options:
|
||||
|
||||
```
|
||||
-h, --help show this help message and exit
|
||||
--nocleanup Leave bitcoinds and test.* datadir on exit or error
|
||||
--noshutdown Don't stop bitcoinds after the test execution
|
||||
--srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli (default:
|
||||
--nocleanup Leave komodods and test.* datadir on exit or error
|
||||
--noshutdown Don't stop komodods after the test execution
|
||||
--srcdir=SRCDIR Source directory containing komodod/komodo-cli (default:
|
||||
../../src)
|
||||
--tmpdir=TMPDIR Root directory for datadirs
|
||||
--tracerpc Print out all RPC calls as they are made
|
||||
@@ -31,7 +31,7 @@ If you set the environment variable `PYTHON_DEBUG=1` you will get some debug out
|
||||
A 200-block -regtest blockchain and wallets for four nodes
|
||||
is created the first time a regression test is run and
|
||||
is stored in the cache/ directory. Each node has the miner
|
||||
subsidy from 25 mature blocks (25*10=250 ZEC) in its wallet.
|
||||
subsidy from 25 mature blocks (25*10=250 KMD) in its wallet.
|
||||
|
||||
After the first run, the cache/ blockchain and wallets are
|
||||
copied into a temporary directory and used as the initial
|
||||
@@ -42,5 +42,5 @@ to recover with:
|
||||
|
||||
```bash
|
||||
rm -rf cache
|
||||
killall zcashd
|
||||
killall komodod
|
||||
```
|
||||
|
||||
605
qa/rpc-tests/cryptoconditions.py
Executable file
605
qa/rpc-tests/cryptoconditions.py
Executable file
@@ -0,0 +1,605 @@
|
||||
#!/usr/bin/env python2
|
||||
# Copyright (c) 2018 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.authproxy import JSONRPCException
|
||||
from test_framework.util import assert_equal, assert_greater_than, \
|
||||
initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \
|
||||
stop_nodes, sync_blocks, sync_mempools, wait_bitcoinds, rpc_port, assert_raises
|
||||
|
||||
import time
|
||||
from decimal import Decimal
|
||||
|
||||
def assert_success(result):
|
||||
assert_equal(result['result'], 'success')
|
||||
|
||||
def assert_error(result):
|
||||
assert_equal(result['result'], 'error')
|
||||
|
||||
class CryptoConditionsTest (BitcoinTestFramework):
|
||||
|
||||
def setup_chain(self):
|
||||
print("Initializing CC test directory "+self.options.tmpdir)
|
||||
self.num_nodes = 1
|
||||
initialize_chain_clean(self.options.tmpdir, self.num_nodes)
|
||||
|
||||
def setup_network(self, split = False):
|
||||
print("Setting up network...")
|
||||
self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D"
|
||||
self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf"
|
||||
self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9"
|
||||
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
|
||||
extra_args=[[
|
||||
# always give -ac_name as first extra_arg
|
||||
'-ac_name=REGTEST',
|
||||
'-conf='+self.options.tmpdir+'/node0/REGTEST.conf',
|
||||
'-port=64367',
|
||||
'-rpcport=64368',
|
||||
'-regtest',
|
||||
'-addressindex=1',
|
||||
'-spentindex=1',
|
||||
'-ac_supply=5555555',
|
||||
'-ac_reward=10000000',
|
||||
'-pubkey=' + self.pubkey,
|
||||
'-ac_cc=2',
|
||||
'-whitelist=127.0.0.1',
|
||||
'-debug',
|
||||
'-daemon',
|
||||
'-rpcuser=rt',
|
||||
'-rpcpassword=rt'
|
||||
]]
|
||||
)
|
||||
self.is_network_split = split
|
||||
self.rpc = self.nodes[0]
|
||||
self.sync_all()
|
||||
print("Done setting up network")
|
||||
|
||||
def send_and_mine(self, xtn):
|
||||
txid = self.rpc.sendrawtransaction(xtn)
|
||||
assert txid, 'got txid'
|
||||
# we need the tx above to be confirmed in the next block
|
||||
self.rpc.generate(1)
|
||||
return txid
|
||||
|
||||
def run_faucet_tests(self):
|
||||
rpc = self.rpc
|
||||
|
||||
# basic sanity tests
|
||||
result = rpc.getwalletinfo()
|
||||
assert_greater_than(result['txcount'], 100)
|
||||
assert_greater_than(result['balance'], 0.0)
|
||||
balance = result['balance']
|
||||
|
||||
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']:
|
||||
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']:
|
||||
assert_equal(result[x][0], 'R')
|
||||
|
||||
# no funds in the faucet yet
|
||||
result = rpc.faucetget()
|
||||
assert_error(result)
|
||||
|
||||
result = rpc.faucetinfo()
|
||||
assert_success(result)
|
||||
|
||||
result = rpc.faucetfund("0")
|
||||
assert_error(result)
|
||||
|
||||
result = rpc.faucetfund("-1")
|
||||
assert_error(result)
|
||||
|
||||
# we need at least 1 + txfee to get
|
||||
result = rpc.faucetfund("2")
|
||||
assert_success(result)
|
||||
assert result['hex'], "hex key found"
|
||||
|
||||
# broadcast the xtn
|
||||
result = rpc.sendrawtransaction(result['hex'])
|
||||
txid = result[0]
|
||||
assert txid, "found txid"
|
||||
|
||||
# we need the tx above to be confirmed in the next block
|
||||
rpc.generate(1)
|
||||
|
||||
result = rpc.getwalletinfo()
|
||||
balance2 = result['balance']
|
||||
# make sure our balance is less now
|
||||
assert_greater_than(balance, balance2)
|
||||
|
||||
result = rpc.faucetinfo()
|
||||
assert_success(result)
|
||||
assert_greater_than( result['funding'], 0 )
|
||||
|
||||
result = rpc.faucetget()
|
||||
assert_success(result)
|
||||
assert result['hex'], "hex key found"
|
||||
|
||||
# try to broadcast the xtn, but we will get 'faucet is only for brand new addresses'
|
||||
assert_raises(JSONRPCException, rpc.sendrawtransaction, [ result['hex'] ])
|
||||
|
||||
newaddr = rpc.getnewaddress()
|
||||
assert newaddr, "got a new address"
|
||||
result = rpc.validateaddress(newaddr)
|
||||
newpubkey = result['pubkey']
|
||||
assert newpubkey, "got a pubkey for new address"
|
||||
|
||||
def run_dice_tests(self):
|
||||
rpc = self.nodes[0]
|
||||
|
||||
dice = rpc.diceaddress()
|
||||
assert_equal(dice['result'], 'success')
|
||||
for x in ['myCCaddress', 'DiceCCaddress', 'Dicemarker', 'myaddress']:
|
||||
assert_equal(dice[x][0], 'R')
|
||||
|
||||
dice = rpc.diceaddress(self.pubkey)
|
||||
assert_equal(dice['result'], 'success')
|
||||
for x in ['myCCaddress', 'DiceCCaddress', 'Dicemarker', 'myaddress', 'CCaddress']:
|
||||
assert_equal(dice[x][0], 'R')
|
||||
|
||||
# no dice created yet
|
||||
result = rpc.dicelist()
|
||||
assert_equal(result, [])
|
||||
|
||||
# creating dice plan with too long name (>8 chars)
|
||||
result = rpc.dicefund("THISISTOOLONG", "10000", "10", "10000", "10", "5")
|
||||
assert_error(result)
|
||||
|
||||
# creating dice plan with < 100 funding
|
||||
result = rpc.dicefund("LUCKY","10","1","10000","10","5")
|
||||
assert_error(result)
|
||||
|
||||
# creating dice plan with 0 blocks timeout
|
||||
result = rpc.dicefund("LUCKY","10","1","10000","10","0")
|
||||
assert_error(result)
|
||||
|
||||
# creating dice plan
|
||||
dicefundtx = rpc.dicefund("LUCKY","1000","1","800","10","5")
|
||||
diceid = self.send_and_mine(dicefundtx['hex'])
|
||||
|
||||
# checking if it in plans list now
|
||||
result = rpc.dicelist()
|
||||
assert_equal(result[0], diceid)
|
||||
|
||||
# set dice name for futher usage
|
||||
dicename = "LUCKY"
|
||||
|
||||
# adding zero funds to plan
|
||||
result = rpc.diceaddfunds(dicename,diceid,"0")
|
||||
assert_error(result)
|
||||
|
||||
# adding negative funds to plan
|
||||
result = rpc.diceaddfunds(dicename,diceid,"-1")
|
||||
assert_error(result)
|
||||
|
||||
# adding funds to plan
|
||||
addfundstx = rpc.diceaddfunds(dicename,diceid,"1100")
|
||||
result = self.send_and_mine(addfundstx['hex'])
|
||||
|
||||
# checking if funds added to plan
|
||||
result = rpc.diceinfo(diceid)
|
||||
assert_equal(result["funding"], "2100.00000000")
|
||||
|
||||
# not valid dice info checking
|
||||
result = rpc.diceinfo("invalid")
|
||||
assert_error(result)
|
||||
|
||||
# placing 0 amount bet
|
||||
result = rpc.dicebet(dicename,diceid,"0","1")
|
||||
assert_error(result)
|
||||
|
||||
# placing negative amount bet
|
||||
result = rpc.dicebet(dicename,diceid,"-1","1")
|
||||
assert_error(result)
|
||||
|
||||
# placing bet more than maxbet
|
||||
result = rpc.dicebet(dicename,diceid,"900","1")
|
||||
assert_error(result)
|
||||
|
||||
# placing bet with amount more than funding
|
||||
result = rpc.dicebet(dicename,diceid,"3000","1")
|
||||
assert_error(result)
|
||||
|
||||
# placing bet with potential won more than funding
|
||||
result = rpc.dicebet(dicename,diceid,"750","9")
|
||||
assert_error(result)
|
||||
|
||||
# placing 0 odds bet
|
||||
result = rpc.dicebet(dicename,diceid,"1","0")
|
||||
assert_error(result)
|
||||
|
||||
# placing negative odds bet
|
||||
result = rpc.dicebet(dicename,diceid,"1","-1")
|
||||
assert_error(result)
|
||||
|
||||
# placing bet with odds more than allowed
|
||||
result = rpc.dicebet(dicename,diceid,"1","11")
|
||||
assert_error(result)
|
||||
|
||||
# placing bet with not correct dice name
|
||||
result = rpc.dicebet("nope",diceid,"100","1")
|
||||
assert_error(result)
|
||||
|
||||
# placing bet with not correct dice id
|
||||
result = rpc.dicebet(dicename,self.pubkey,"100","1")
|
||||
assert_error(result)
|
||||
|
||||
# valid bet placing
|
||||
placebet = rpc.dicebet(dicename,diceid,"100","1")
|
||||
betid = self.send_and_mine(placebet["hex"])
|
||||
assert result, "bet placed"
|
||||
|
||||
# check bet status
|
||||
result = rpc.dicestatus(dicename,diceid,betid)
|
||||
assert_success(result)
|
||||
|
||||
# have to make some entropy for the next test
|
||||
entropytx = 0
|
||||
fundingsum = 1
|
||||
while entropytx < 10:
|
||||
fundingsuminput = str(fundingsum)
|
||||
fundinghex = rpc.diceaddfunds(dicename,diceid,fundingsuminput)
|
||||
result = self.send_and_mine(fundinghex['hex'])
|
||||
entropytx = entropytx + 1
|
||||
fundingsum = fundingsum + 1
|
||||
|
||||
rpc.generate(2)
|
||||
|
||||
# note initial dice funding state at this point.
|
||||
# TODO: track player balance somehow (hard to do because of mining and fees)
|
||||
diceinfo = rpc.diceinfo(diceid)
|
||||
funding = float(diceinfo['funding'])
|
||||
|
||||
# placing same amount bets with amount 1 and odds 1:2, checking if balance changed correct
|
||||
losscounter = 0
|
||||
wincounter = 0
|
||||
betcounter = 0
|
||||
|
||||
while (betcounter < 10):
|
||||
placebet = rpc.dicebet(dicename,diceid,"1","1")
|
||||
betid = self.send_and_mine(placebet["hex"])
|
||||
finish = rpc.dicefinish(dicename,diceid,betid)
|
||||
self.send_and_mine(finish["hex"])
|
||||
betresult = rpc.dicestatus(dicename,diceid,betid)
|
||||
betcounter = betcounter + 1
|
||||
if betresult["status"] == "loss":
|
||||
losscounter = losscounter + 1
|
||||
elif betresult["status"] == "win":
|
||||
wincounter = wincounter + 1
|
||||
|
||||
# funding balance should increase if player loss, decrease if player won
|
||||
fundbalanceguess = funding + losscounter - wincounter
|
||||
fundinfoactual = rpc.diceinfo(diceid)
|
||||
assert_equal(round(fundbalanceguess),round(float(fundinfoactual['funding'])))
|
||||
|
||||
def run_token_tests(self):
|
||||
rpc = self.nodes[0]
|
||||
result = rpc.tokenaddress()
|
||||
assert_success(result)
|
||||
for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress']:
|
||||
assert_equal(result[x][0], 'R')
|
||||
|
||||
result = rpc.tokenaddress(self.pubkey)
|
||||
assert_success(result)
|
||||
for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress', 'CCaddress']:
|
||||
assert_equal(result[x][0], 'R')
|
||||
# there are no tokens created yet
|
||||
result = rpc.tokenlist()
|
||||
assert_equal(result, [])
|
||||
|
||||
# trying to create token with negaive supply
|
||||
result = rpc.tokencreate("NUKE", "-1987420", "no bueno supply")
|
||||
assert_error(result)
|
||||
|
||||
# creating token with name more than 32 chars
|
||||
result = rpc.tokencreate("NUKE123456789012345678901234567890", "1987420", "name too long")
|
||||
assert_error(result)
|
||||
|
||||
# creating valid token
|
||||
result = rpc.tokencreate("DUKE", "1987.420", "Duke's custom token")
|
||||
assert_success(result)
|
||||
|
||||
tokenid = self.send_and_mine(result['hex'])
|
||||
|
||||
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)
|
||||
assert_equal(result['balance'], 198742000000)
|
||||
assert_equal(result['tokenid'], tokenid)
|
||||
|
||||
# get token balance for token without pubkey
|
||||
result = rpc.tokenbalance(tokenid)
|
||||
assert_success(result)
|
||||
assert_equal(result['balance'], 198742000000)
|
||||
assert_equal(result['tokenid'], tokenid)
|
||||
|
||||
# this is not a valid assetid
|
||||
result = rpc.tokeninfo(self.pubkey)
|
||||
assert_error(result)
|
||||
|
||||
# check tokeninfo for valid token
|
||||
result = rpc.tokeninfo(tokenid)
|
||||
assert_success(result)
|
||||
assert_equal(result['tokenid'], tokenid)
|
||||
assert_equal(result['owner'], self.pubkey)
|
||||
assert_equal(result['name'], "DUKE")
|
||||
assert_equal(result['supply'], 198742000000)
|
||||
assert_equal(result['description'], "Duke's custom token")
|
||||
|
||||
# invalid numtokens ask
|
||||
result = rpc.tokenask("-1", tokenid, "1")
|
||||
assert_error(result)
|
||||
|
||||
# invalid numtokens ask
|
||||
result = rpc.tokenask("0", tokenid, "1")
|
||||
assert_error(result)
|
||||
|
||||
# invalid price ask
|
||||
result = rpc.tokenask("1", tokenid, "-1")
|
||||
assert_error(result)
|
||||
|
||||
# invalid price ask
|
||||
result = rpc.tokenask("1", tokenid, "0")
|
||||
assert_error(result)
|
||||
|
||||
# invalid tokenid ask
|
||||
result = rpc.tokenask("100", "deadbeef", "1")
|
||||
assert_error(result)
|
||||
|
||||
# valid ask
|
||||
tokenask = rpc.tokenask("100", tokenid, "7.77")
|
||||
tokenaskhex = tokenask['hex']
|
||||
tokenaskid = self.send_and_mine(tokenask['hex'])
|
||||
result = rpc.tokenorders()
|
||||
order = result[0]
|
||||
assert order, "found order"
|
||||
|
||||
# invalid ask fillunits
|
||||
result = rpc.tokenfillask(tokenid, tokenaskid, "0")
|
||||
assert_error(result)
|
||||
|
||||
# invalid ask fillunits
|
||||
result = rpc.tokenfillask(tokenid, tokenaskid, "-777")
|
||||
assert_error(result)
|
||||
|
||||
# valid ask fillunits
|
||||
fillask = rpc.tokenfillask(tokenid, tokenaskid, "777")
|
||||
result = self.send_and_mine(fillask['hex'])
|
||||
txid = result[0]
|
||||
assert txid, "found txid"
|
||||
|
||||
# should be no token orders
|
||||
result = rpc.tokenorders()
|
||||
assert_equal(result, [])
|
||||
|
||||
# checking ask cancellation
|
||||
testorder = rpc.tokenask("100", tokenid, "7.77")
|
||||
testorderid = self.send_and_mine(testorder['hex'])
|
||||
cancel = rpc.tokencancelask(tokenid, testorderid)
|
||||
self.send_and_mine(cancel["hex"])
|
||||
result = rpc.tokenorders()
|
||||
assert_equal(result, [])
|
||||
|
||||
# invalid numtokens bid
|
||||
result = rpc.tokenbid("-1", tokenid, "1")
|
||||
assert_error(result)
|
||||
|
||||
# invalid numtokens bid
|
||||
result = rpc.tokenbid("0", tokenid, "1")
|
||||
assert_error(result)
|
||||
|
||||
# invalid price bid
|
||||
result = rpc.tokenbid("1", tokenid, "-1")
|
||||
assert_error(result)
|
||||
|
||||
# invalid price bid
|
||||
result = rpc.tokenbid("1", tokenid, "0")
|
||||
assert_error(result)
|
||||
|
||||
# invalid tokenid bid
|
||||
result = rpc.tokenbid("100", "deadbeef", "1")
|
||||
assert_error(result)
|
||||
|
||||
# valid bid
|
||||
tokenbid = rpc.tokenbid("100", tokenid, "10")
|
||||
tokenbidhex = tokenbid['hex']
|
||||
tokenbidid = self.send_and_mine(tokenbid['hex'])
|
||||
result = rpc.tokenorders()
|
||||
order = result[0]
|
||||
assert order, "found order"
|
||||
|
||||
# invalid bid fillunits
|
||||
result = rpc.tokenfillbid(tokenid, tokenbidid, "0")
|
||||
assert_error(result)
|
||||
|
||||
# invalid bid fillunits
|
||||
result = rpc.tokenfillbid(tokenid, tokenbidid, "-777")
|
||||
assert_error(result)
|
||||
|
||||
# valid bid fillunits
|
||||
fillbid = rpc.tokenfillbid(tokenid, tokenbidid, "1000")
|
||||
result = self.send_and_mine(fillbid['hex'])
|
||||
txid = result[0]
|
||||
assert txid, "found txid"
|
||||
|
||||
# should be no token orders
|
||||
result = rpc.tokenorders()
|
||||
assert_equal(result, [])
|
||||
|
||||
# checking bid cancellation
|
||||
testorder = rpc.tokenbid("100", tokenid, "7.77")
|
||||
testorderid = self.send_and_mine(testorder['hex'])
|
||||
cancel = rpc.tokencancelbid(tokenid, testorderid)
|
||||
self.send_and_mine(cancel["hex"])
|
||||
result = rpc.tokenorders()
|
||||
assert_equal(result, [])
|
||||
|
||||
# invalid token transfer amount (have to add status to CC code!)
|
||||
randompubkey = "021a559101e355c907d9c553671044d619769a6e71d624f68bfec7d0afa6bd6a96"
|
||||
result = rpc.tokentransfer(tokenid,randompubkey,"0")
|
||||
assert_error(result)
|
||||
|
||||
# invalid token transfer amount (have to add status to CC code!)
|
||||
result = rpc.tokentransfer(tokenid,randompubkey,"-1")
|
||||
assert_error(result)
|
||||
|
||||
# valid token transfer
|
||||
sendtokens = rpc.tokentransfer(tokenid,randompubkey,"1")
|
||||
self.send_and_mine(sendtokens["hex"])
|
||||
result = rpc.tokenbalance(tokenid,randompubkey)
|
||||
assert_equal(result["balance"], 1)
|
||||
|
||||
|
||||
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')
|
||||
|
||||
result = rpc.rewardsaddress(self.pubkey)
|
||||
for x in ['RewardsCCaddress', 'myCCaddress', 'Rewardsmarker', 'myaddress', 'CCaddress']:
|
||||
assert_equal(result[x][0], 'R')
|
||||
|
||||
# no rewards yet
|
||||
result = rpc.rewardslist()
|
||||
assert_equal(result, [])
|
||||
|
||||
# looking up non-existent reward should return error
|
||||
result = rpc.rewardsinfo("none")
|
||||
assert_error(result)
|
||||
|
||||
# creating rewards plan with name > 8 chars, should return error
|
||||
result = rpc.rewardscreatefunding("STUFFSTUFF", "7777", "25", "0", "10", "10")
|
||||
assert_error(result)
|
||||
|
||||
# creating rewards plan with 0 funding
|
||||
result = rpc.rewardscreatefunding("STUFF", "0", "25", "0", "10", "10")
|
||||
assert_error(result)
|
||||
|
||||
# creating rewards plan with 0 maxdays
|
||||
result = rpc.rewardscreatefunding("STUFF", "7777", "25", "0", "10", "0")
|
||||
assert_error(result)
|
||||
|
||||
# creating rewards plan with > 25% APR
|
||||
result = rpc.rewardscreatefunding("STUFF", "7777", "30", "0", "10", "10")
|
||||
assert_error(result)
|
||||
|
||||
# creating valid rewards plan
|
||||
result = rpc.rewardscreatefunding("STUFF", "7777", "25", "0", "10", "10")
|
||||
assert result['hex'], 'got raw xtn'
|
||||
fundingtxid = rpc.sendrawtransaction(result['hex'])
|
||||
assert fundingtxid, 'got txid'
|
||||
|
||||
# confirm the above xtn
|
||||
rpc.generate(1)
|
||||
result = rpc.rewardsinfo(fundingtxid)
|
||||
assert_success(result)
|
||||
assert_equal(result['name'], 'STUFF')
|
||||
assert_equal(result['APR'], "25.00000000")
|
||||
assert_equal(result['minseconds'], 0)
|
||||
assert_equal(result['maxseconds'], 864000)
|
||||
assert_equal(result['funding'], "7777.00000000")
|
||||
assert_equal(result['mindeposit'], "10.00000000")
|
||||
assert_equal(result['fundingtxid'], fundingtxid)
|
||||
|
||||
# checking if new plan in rewardslist
|
||||
result = rpc.rewardslist()
|
||||
assert_equal(result[0], fundingtxid)
|
||||
|
||||
# creating reward plan with already existing name, should return error
|
||||
result = rpc.rewardscreatefunding("STUFF", "7777", "25", "0", "10", "10")
|
||||
assert_error(result)
|
||||
|
||||
# add funding amount must be positive
|
||||
result = rpc.rewardsaddfunding("STUFF", fundingtxid, "-1")
|
||||
assert_error(result)
|
||||
|
||||
# add funding amount must be positive
|
||||
result = rpc.rewardsaddfunding("STUFF", fundingtxid, "0")
|
||||
assert_error(result)
|
||||
|
||||
# adding valid funding
|
||||
result = rpc.rewardsaddfunding("STUFF", fundingtxid, "555")
|
||||
addfundingtxid = self.send_and_mine(result['hex'])
|
||||
assert addfundingtxid, 'got funding txid'
|
||||
|
||||
# checking if funding added to rewardsplan
|
||||
result = rpc.rewardsinfo(fundingtxid)
|
||||
assert_equal(result['funding'], "8332.00000000")
|
||||
|
||||
# trying to lock funds, locking funds amount must be positive
|
||||
result = rpc.rewardslock("STUFF", fundingtxid, "-5")
|
||||
assert_error(result)
|
||||
|
||||
# trying to lock funds, locking funds amount must be positive
|
||||
result = rpc.rewardslock("STUFF", fundingtxid, "0")
|
||||
assert_error(result)
|
||||
|
||||
# trying to lock less than the min amount is an error
|
||||
result = rpc.rewardslock("STUFF", fundingtxid, "7")
|
||||
assert_error(result)
|
||||
|
||||
# locking funds in rewards plan
|
||||
result = rpc.rewardslock("STUFF", fundingtxid, "10")
|
||||
assert_success(result)
|
||||
locktxid = result['hex']
|
||||
assert locktxid, "got lock txid"
|
||||
|
||||
# locktxid has not been broadcast yet
|
||||
result = rpc.rewardsunlock("STUFF", fundingtxid, locktxid)
|
||||
assert_error(result)
|
||||
|
||||
# broadcast xtn
|
||||
txid = rpc.sendrawtransaction(locktxid)
|
||||
assert txid, 'got txid from sendrawtransaction'
|
||||
|
||||
# confirm the xtn above
|
||||
rpc.generate(1)
|
||||
|
||||
# will not unlock since reward amount is less than tx fee
|
||||
result = rpc.rewardsunlock("STUFF", fundingtxid, locktxid)
|
||||
assert_error(result)
|
||||
|
||||
|
||||
def run_test (self):
|
||||
print("Mining blocks...")
|
||||
rpc = self.nodes[0]
|
||||
|
||||
# utxos from block 1 become mature in block 101
|
||||
rpc.generate(101)
|
||||
self.sync_all()
|
||||
|
||||
# this corresponds to -pubkey above
|
||||
print("Importing privkey")
|
||||
rpc.importprivkey(self.privkey)
|
||||
|
||||
self.run_rewards_tests()
|
||||
self.run_dice_tests()
|
||||
self.run_token_tests()
|
||||
self.run_faucet_tests()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
CryptoConditionsTest ().main ()
|
||||
@@ -90,11 +90,11 @@ class BitcoinTestFramework(object):
|
||||
|
||||
parser = optparse.OptionParser(usage="%prog [options]")
|
||||
parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
|
||||
help="Leave bitcoinds and test.* datadir on exit or error")
|
||||
help="Leave komodods and test.* datadir on exit or error")
|
||||
parser.add_option("--noshutdown", dest="noshutdown", default=False, action="store_true",
|
||||
help="Don't stop bitcoinds after the test execution")
|
||||
help="Don't stop komodods after the test execution")
|
||||
parser.add_option("--srcdir", dest="srcdir", default="../../src",
|
||||
help="Source directory containing bitcoind/bitcoin-cli (default: %default)")
|
||||
help="Source directory containing komodod/komodo-cli (default: %default)")
|
||||
parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
|
||||
help="Root directory for datadirs")
|
||||
parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true",
|
||||
@@ -137,7 +137,7 @@ class BitcoinTestFramework(object):
|
||||
stop_nodes(self.nodes)
|
||||
wait_bitcoinds()
|
||||
else:
|
||||
print("Note: bitcoinds were not stopped and may still be running")
|
||||
print("Note: komodods were not stopped and may still be running")
|
||||
|
||||
if not self.options.nocleanup and not self.options.noshutdown:
|
||||
print("Cleaning up")
|
||||
@@ -151,7 +151,7 @@ class BitcoinTestFramework(object):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Test framework for doing p2p comparison testing, which sets up some bitcoind
|
||||
# Test framework for doing p2p comparison testing, which sets up some komodod
|
||||
# binaries:
|
||||
# 1 binary: test binary
|
||||
# 2 binaries: 1 test binary, 1 ref binary
|
||||
@@ -165,10 +165,10 @@ class ComparisonTestFramework(BitcoinTestFramework):
|
||||
|
||||
def add_options(self, parser):
|
||||
parser.add_option("--testbinary", dest="testbinary",
|
||||
default=os.getenv("BITCOIND", "bitcoind"),
|
||||
default=os.getenv("BITCOIND", "komodod"),
|
||||
help="bitcoind binary to test")
|
||||
parser.add_option("--refbinary", dest="refbinary",
|
||||
default=os.getenv("BITCOIND", "bitcoind"),
|
||||
default=os.getenv("BITCOIND", "komodod"),
|
||||
help="bitcoind binary to use for reference nodes (if any)")
|
||||
|
||||
def setup_chain(self):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copyright (c) 2014 The Bitcoin Core developers
|
||||
# Copyright (c) 2018 The SuperNET developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
@@ -75,38 +76,55 @@ def initialize_datadir(dirname, n):
|
||||
datadir = os.path.join(dirname, "node"+str(n))
|
||||
if not os.path.isdir(datadir):
|
||||
os.makedirs(datadir)
|
||||
with open(os.path.join(datadir, "zcash.conf"), 'w') as f:
|
||||
# kmd AC's don't use this, they use the conf auto-created when the AC is created
|
||||
# plus CLI arguments. This is for komodod tests
|
||||
print("Writing to " + os.path.join(datadir,"komodo.conf"))
|
||||
with open(os.path.join(datadir, "komodo.conf"), 'w') as f:
|
||||
f.write("regtest=1\n");
|
||||
f.write("txindex=1\n");
|
||||
f.write("server=1\n");
|
||||
f.write("showmetrics=0\n");
|
||||
f.write("rpcuser=rt\n");
|
||||
f.write("rpcpassword=rt\n");
|
||||
f.write("port="+str(p2p_port(n))+"\n");
|
||||
f.write("rpcport="+str(rpc_port(n))+"\n");
|
||||
#f.write("port="+str(p2p_port(n))+"\n");
|
||||
#rpcport = str(rpc_port(n))
|
||||
#f.write("rpcport="+rpcport+"\n");
|
||||
#print "RPC port=" + rpcport
|
||||
f.write("listenonion=0\n");
|
||||
# TODO: maybe make these optional, defaulted to on for now
|
||||
f.write("addressindex=1\n");
|
||||
f.write("spentindex=1\n");
|
||||
f.write("timestampindex=1\n");
|
||||
return datadir
|
||||
|
||||
def initialize_chain(test_dir):
|
||||
"""
|
||||
Create (or copy from cache) a 200-block-long chain and
|
||||
4 wallets.
|
||||
bitcoind and bitcoin-cli must be in search path.
|
||||
komodod and komodo-cli must be in search path.
|
||||
"""
|
||||
|
||||
print("initialize_chain")
|
||||
if not os.path.isdir(os.path.join("cache", "node0")):
|
||||
devnull = open("/dev/null", "w+")
|
||||
# Create cache directories, run bitcoinds:
|
||||
# Create cache directories, run komodods:
|
||||
for i in range(4):
|
||||
datadir=initialize_datadir("cache", i)
|
||||
args = [ os.getenv("BITCOIND", "bitcoind"), "-keypool=1", "-datadir="+datadir, "-discover=0" ]
|
||||
args = [ os.getenv("BITCOIND", "komodod"), "-keypool=1", "-datadir="+datadir, "-discover=0" ]
|
||||
if i > 0:
|
||||
args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
|
||||
bitcoind_processes[i] = subprocess.Popen(args)
|
||||
cmd = os.getenv("BITCOINCLI", "komodo-cli")
|
||||
cmd_args = cmd + " -datadir="+datadir + " -rpcwait getblockcount"
|
||||
if os.getenv("PYTHON_DEBUG", ""):
|
||||
print "initialize_chain: bitcoind started, calling bitcoin-cli -rpcwait getblockcount"
|
||||
subprocess.check_call([ os.getenv("BITCOINCLI", "bitcoin-cli"), "-datadir="+datadir,
|
||||
"-rpcwait", "getblockcount"], stdout=devnull)
|
||||
print "initialize_chain: komodod started, calling: " + cmd_args
|
||||
strcmd = cmd + " " + "-datadir="+datadir + " -rpcwait getblockcount"
|
||||
|
||||
print("Running " + strcmd)
|
||||
subprocess.check_call(strcmd, shell=True);
|
||||
#subprocess.check_call([ cmd, "-rpcwait", "getblockcount"], stdout=devnull)
|
||||
if os.getenv("PYTHON_DEBUG", ""):
|
||||
print "initialize_chain: bitcoin-cli -rpcwait getblockcount completed"
|
||||
print "initialize_chain: komodo-cli -rpcwait getblockcount completed"
|
||||
devnull.close()
|
||||
rpcs = []
|
||||
for i in range(4):
|
||||
@@ -144,7 +162,7 @@ def initialize_chain(test_dir):
|
||||
from_dir = os.path.join("cache", "node"+str(i))
|
||||
to_dir = os.path.join(test_dir, "node"+str(i))
|
||||
shutil.copytree(from_dir, to_dir)
|
||||
initialize_datadir(test_dir, i) # Overwrite port/rpcport in zcash.conf
|
||||
initialize_datadir(test_dir, i) # Overwrite port/rpcport in komodo.conf
|
||||
|
||||
def initialize_chain_clean(test_dir, num_nodes):
|
||||
"""
|
||||
@@ -177,34 +195,50 @@ def _rpchost_to_args(rpchost):
|
||||
|
||||
def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
|
||||
"""
|
||||
Start a bitcoind and return RPC connection to it
|
||||
Start a komodod and return RPC connection to it
|
||||
"""
|
||||
datadir = os.path.join(dirname, "node"+str(i))
|
||||
if binary is None:
|
||||
binary = os.getenv("BITCOIND", "bitcoind")
|
||||
binary = os.getenv("BITCOIND", "komodod")
|
||||
args = [ binary, "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest" ]
|
||||
if extra_args is not None: args.extend(extra_args)
|
||||
#print("args=" + ' '.join(args))
|
||||
bitcoind_processes[i] = subprocess.Popen(args)
|
||||
devnull = open("/dev/null", "w+")
|
||||
|
||||
cmd = os.getenv("BITCOINCLI", "komodo-cli")
|
||||
print("cmd=" + cmd)
|
||||
cmd_args = ' '.join(extra_args) + " -rpcwait getblockcount "
|
||||
if os.getenv("PYTHON_DEBUG", ""):
|
||||
print "start_node: bitcoind started, calling bitcoin-cli -rpcwait getblockcount"
|
||||
subprocess.check_call([ os.getenv("BITCOINCLI", "bitcoin-cli"), "-datadir="+datadir] +
|
||||
_rpchost_to_args(rpchost) +
|
||||
["-rpcwait", "getblockcount"], stdout=devnull)
|
||||
print "start_node: komodod started, calling : " + cmd + " " + cmd_args
|
||||
strcmd = cmd + " " + cmd_args
|
||||
|
||||
print("Running " + strcmd)
|
||||
import time
|
||||
time.sleep(2)
|
||||
subprocess.check_call(strcmd, shell=True);
|
||||
#subprocess.check_call([ os.getenv("BITCOINCLI", "komodo-cli"), "-datadir="+datadir] +
|
||||
# _rpchost_to_args(rpchost) +
|
||||
# ["-rpcwait", "-rpcport=6438", "getblockcount"], stdout=devnull)
|
||||
if os.getenv("PYTHON_DEBUG", ""):
|
||||
print "start_node: calling bitcoin-cli -rpcwait getblockcount returned"
|
||||
print "start_node: calling komodo-cli -rpcwait getblockcount returned"
|
||||
devnull.close()
|
||||
url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
|
||||
if extra_args[0] == '-ac_name=REGTEST':
|
||||
url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', 64368)
|
||||
else:
|
||||
url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
|
||||
print("connecting to " + url)
|
||||
if timewait is not None:
|
||||
proxy = AuthServiceProxy(url, timeout=timewait)
|
||||
else:
|
||||
proxy = AuthServiceProxy(url)
|
||||
print("created proxy")
|
||||
proxy.url = url # store URL on proxy for info
|
||||
return proxy
|
||||
|
||||
def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None):
|
||||
"""
|
||||
Start multiple bitcoinds, return RPC connections to them
|
||||
Start multiple komodods, return RPC connections to them
|
||||
"""
|
||||
if extra_args is None: extra_args = [ None for i in range(num_nodes) ]
|
||||
if binary is None: binary = [ None for i in range(num_nodes) ]
|
||||
|
||||
@@ -256,11 +256,22 @@ libbitcoin_server_a_SOURCES = \
|
||||
asyncrpcqueue.cpp \
|
||||
bloom.cpp \
|
||||
cc/eval.cpp \
|
||||
cc/importpayout.cpp \
|
||||
cc/disputepayout.cpp \
|
||||
cc/import.cpp \
|
||||
cc/CCassetsCore.cpp \
|
||||
cc/CCcustom.cpp \
|
||||
cc/CCtx.cpp \
|
||||
cc/CCutils.cpp \
|
||||
cc/assets.cpp \
|
||||
cc/faucet.cpp \
|
||||
cc/rewards.cpp \
|
||||
cc/dice.cpp \
|
||||
cc/lotto.cpp \
|
||||
cc/fsm.cpp \
|
||||
cc/auction.cpp \
|
||||
cc/betprotocol.cpp \
|
||||
chain.cpp \
|
||||
checkpoints.cpp \
|
||||
crosschain.cpp \
|
||||
deprecation.cpp \
|
||||
httprpc.cpp \
|
||||
httpserver.cpp \
|
||||
@@ -272,12 +283,14 @@ libbitcoin_server_a_SOURCES = \
|
||||
miner.cpp \
|
||||
net.cpp \
|
||||
noui.cpp \
|
||||
notarisationdb.cpp \
|
||||
paymentdisclosure.cpp \
|
||||
paymentdisclosuredb.cpp \
|
||||
policy/fees.cpp \
|
||||
pow.cpp \
|
||||
rest.cpp \
|
||||
rpcblockchain.cpp \
|
||||
rpccrosschain.cpp \
|
||||
rpcmining.cpp \
|
||||
rpcmisc.cpp \
|
||||
rpcnet.cpp \
|
||||
@@ -331,6 +344,8 @@ libbitcoin_wallet_a_SOURCES = \
|
||||
paymentdisclosuredb.cpp \
|
||||
wallet/rpcdisclosure.cpp \
|
||||
wallet/rpcdump.cpp \
|
||||
cc/CCassetstx.cpp \
|
||||
cc/CCtx.cpp \
|
||||
wallet/rpcwallet.cpp \
|
||||
wallet/wallet.cpp \
|
||||
wallet/wallet_ismine.cpp \
|
||||
@@ -385,6 +400,7 @@ libbitcoin_common_a_SOURCES = \
|
||||
core_read.cpp \
|
||||
core_write.cpp \
|
||||
hash.cpp \
|
||||
importcoin.cpp \
|
||||
key.cpp \
|
||||
keystore.cpp \
|
||||
netbase.cpp \
|
||||
@@ -605,7 +621,7 @@ endif
|
||||
|
||||
libzcashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
|
||||
libzcashconsensus_la_LIBADD = $(LIBSECP256K1)
|
||||
libzcashconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL
|
||||
libzcashconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -I$(srcdir)/cryptoconditions/include -DBUILD_BITCOIN_INTERNAL
|
||||
libzcashconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
|
||||
endif
|
||||
|
||||
@@ -5,9 +5,13 @@ bin_PROGRAMS += komodo-test
|
||||
# tool for generating our public parameters
|
||||
komodo_test_SOURCES = \
|
||||
test-komodo/main.cpp \
|
||||
test-komodo/testutils.cpp \
|
||||
test-komodo/test_cryptoconditions.cpp \
|
||||
test-komodo/test_coinimport.cpp \
|
||||
test-komodo/test_eval_bet.cpp \
|
||||
test-komodo/test_eval_notarisation.cpp
|
||||
test-komodo/test_eval_notarisation.cpp \
|
||||
test-komodo/test_crosschain.cpp \
|
||||
test-komodo/test_parse_notarisation.cpp
|
||||
|
||||
komodo_test_CPPFLAGS = $(komodod_CPPFLAGS)
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ BITCOIN_TESTS =\
|
||||
test/arith_uint256_tests.cpp \
|
||||
test/bignum.h \
|
||||
test/addrman_tests.cpp \
|
||||
test/alert_tests.cpp \
|
||||
test/allocator_tests.cpp \
|
||||
test/base32_tests.cpp \
|
||||
test/base58_tests.cpp \
|
||||
|
||||
2
src/ac/ccl
Executable file
2
src/ac/ccl
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=CCL $1 $2 $3 $4 $5 $6
|
||||
@@ -1,59 +1,19 @@
|
||||
#!/bin/bash
|
||||
set -eo pipefail
|
||||
|
||||
# You can now add delay line to pubkey.txt file
|
||||
source pubkey.txt
|
||||
args=("$@")
|
||||
overide_args="$@"
|
||||
seed_ip=`getent hosts zero.kolo.supernet.org | awk '{ print $1 }'`
|
||||
komodo_binary='./komodod'
|
||||
delay=20
|
||||
|
||||
function komodo_asset ()
|
||||
{
|
||||
if [ $[RANDOM % 10] == 1 ]
|
||||
then
|
||||
gen=" -gen"
|
||||
else
|
||||
gen=""
|
||||
fi
|
||||
if [ -z "$delay" ]; then delay=20; fi
|
||||
|
||||
if [ -n "$2" ]
|
||||
then
|
||||
supply=" -ac_supply=$2"
|
||||
else
|
||||
supply=" "
|
||||
fi
|
||||
./listassetchainparams | while read args; do
|
||||
gen=""
|
||||
if [ $[RANDOM % 10] == 1 ]; then
|
||||
gen=" -gen"
|
||||
fi
|
||||
|
||||
$komodo_binary -ac_name=$1 $gen $supply $args -pubkey=$pubkey -addnode=$seed_ip &
|
||||
sleep $delay
|
||||
}
|
||||
|
||||
#set -x
|
||||
|
||||
komodo_asset REVS 1300000
|
||||
komodo_asset SUPERNET 816061
|
||||
komodo_asset DEX 999999
|
||||
komodo_asset PANGEA 999999
|
||||
komodo_asset JUMBLR 999999
|
||||
komodo_asset BET 999999
|
||||
komodo_asset CRYPTO 999999
|
||||
komodo_asset HODL 9999999
|
||||
komodo_asset MSHARK 1400000
|
||||
komodo_asset BOTS 999999
|
||||
komodo_asset MGW 999999
|
||||
komodo_asset COQUI 72000000
|
||||
komodo_asset WLC 210000000
|
||||
komodo_asset KV 1000000
|
||||
komodo_asset CEAL 366666666
|
||||
komodo_asset MESH 1000007
|
||||
komodo_asset MNZ 257142858
|
||||
komodo_asset AXO 200000000
|
||||
komodo_asset ETOMIC 100000000
|
||||
komodo_asset BTCH 20998641
|
||||
komodo_asset PIZZA 100000000
|
||||
komodo_asset BEER 100000000
|
||||
komodo_asset NINJA 100000000
|
||||
komodo_asset OOT 216000000
|
||||
komodo_asset BNTN 500000000
|
||||
komodo_asset CHAIN 999999
|
||||
komodo_asset PRLPAY 500000000
|
||||
komodo_asset DSEC 7000000
|
||||
komodo_asset GLXT 100000000
|
||||
komodo_asset EQL 500000000
|
||||
./komodod $gen $args $overide_args -pubkey=$pubkey -addnode=$seed_ip &
|
||||
sleep $delay
|
||||
done
|
||||
|
||||
146
src/assetchains.json
Normal file
146
src/assetchains.json
Normal file
@@ -0,0 +1,146 @@
|
||||
[
|
||||
{
|
||||
"ac_name": "REVS",
|
||||
"ac_supply": "1300000"
|
||||
},
|
||||
{
|
||||
"ac_name": "SUPERNET",
|
||||
"ac_supply": "816061"
|
||||
},
|
||||
{
|
||||
"ac_name": "DEX",
|
||||
"ac_supply": "999999"
|
||||
},
|
||||
{
|
||||
"ac_name": "PANGEA",
|
||||
"ac_supply": "999999"
|
||||
},
|
||||
{
|
||||
"ac_name": "JUMBLR",
|
||||
"ac_supply": "999999"
|
||||
},
|
||||
{
|
||||
"ac_name": "BET",
|
||||
"ac_supply": "999999"
|
||||
},
|
||||
{
|
||||
"ac_name": "CRYPTO",
|
||||
"ac_supply": "999999"
|
||||
},
|
||||
{
|
||||
"ac_name": "HODL",
|
||||
"ac_supply": "9999999"
|
||||
},
|
||||
{
|
||||
"ac_name": "MSHARK",
|
||||
"ac_supply": "1400000"
|
||||
},
|
||||
{
|
||||
"ac_name": "BOTS",
|
||||
"ac_supply": "999999"
|
||||
},
|
||||
{
|
||||
"ac_name": "MGW",
|
||||
"ac_supply": "999999"
|
||||
},
|
||||
{
|
||||
"ac_name": "COQUI",
|
||||
"ac_supply": "72000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "WLC",
|
||||
"ac_supply": "210000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "KV",
|
||||
"ac_supply": "1000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "CEAL",
|
||||
"ac_supply": "366666666"
|
||||
},
|
||||
{
|
||||
"ac_name": "MESH",
|
||||
"ac_supply": "1000007"
|
||||
},
|
||||
{
|
||||
"ac_name": "MNZ",
|
||||
"ac_supply": "257142858"
|
||||
},
|
||||
{
|
||||
"ac_name": "AXO",
|
||||
"ac_supply": "200000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "ETOMIC",
|
||||
"ac_supply": "100000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "BTCH",
|
||||
"ac_supply": "20998641"
|
||||
},
|
||||
{
|
||||
"ac_name": "PIZZA",
|
||||
"ac_supply": "100000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "BEER",
|
||||
"ac_supply": "100000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "NINJA",
|
||||
"ac_supply": "100000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "OOT",
|
||||
"ac_supply": "216000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "BNTN",
|
||||
"ac_supply": "500000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "CHAIN",
|
||||
"ac_supply": "999999"
|
||||
},
|
||||
{
|
||||
"ac_name": "PRLPAY",
|
||||
"ac_supply": "500000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "DSEC",
|
||||
"ac_supply": "7000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "GLXT",
|
||||
"ac_supply": "10000000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "EQL",
|
||||
"ac_supply": "500000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "ZILLA",
|
||||
"ac_supply": "11000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "RFOX",
|
||||
"ac_supply": "1000000000",
|
||||
"ac_reward": "100000000"
|
||||
},
|
||||
{
|
||||
"ac_name": "SEC",
|
||||
"ac_supply": "1000000000",
|
||||
"ac_cc": "333"
|
||||
},
|
||||
{
|
||||
"ac_name": "CCL",
|
||||
"ac_supply": "200000000",
|
||||
"ac_end": "1",
|
||||
"ac_cc": "2",
|
||||
"addressindex": "1",
|
||||
"spentindex": "1",
|
||||
"addnode": "142.93.136.89",
|
||||
"addnode": "195.201.22.89"
|
||||
}
|
||||
]
|
||||
@@ -32,7 +32,10 @@ echo $pubkey
|
||||
./komodod -pubkey=$pubkey -ac_name=CHAIN -ac_supply=999999 -addnode=78.47.146.222 &
|
||||
./komodod -pubkey=$pubkey -ac_name=PRLPAY -ac_supply=500000000 -addnode=13.250.226.125 &
|
||||
./komodod -pubkey=$pubkey -ac_name=DSEC -ac_supply=7000000 -addnode=185.148.147.30 &
|
||||
./komodod -pubkey=$pubkey -ac_name=GLXT -ac_supply=100000000 -addnode=13.230.224.15 &
|
||||
./komodod -pubkey=$pubkey -ac_name=GLXT -ac_supply=10000000000 -addnode=13.230.224.15 &
|
||||
./komodod -pubkey=$pubkey -ac_name=EQL -ac_supply=500000000 -addnode=46.101.124.153 &
|
||||
~/VerusCoin/src/komodod -ac_name=VRSC -ac_algo=verushash -ac_cc=1 -ac_veruspos=50 -ac_supply=0 -ac_eras=3 -ac_reward=0,38400000000,2400000000 -ac_halving=1,43200,1051920 -ac_decay=100000000,0,0 -ac_end=10080,226080,0 -ac_timelockgte=19200000000 -ac_timeunlockfrom=129600 -ac_timeunlockto=1180800 -addnode=185.25.48.236 -addnode=185.64.105.111 &
|
||||
|
||||
./komodod -pubkey=$pubkey -ac_name=ZILLA -ac_supply=11000000 -addnode=54.39.23.248 &
|
||||
./komodod -pubkey=$pubkey -ac_name=RFOX -ac_supply=1000000000 -ac_reward=100000000 -addnode=78.47.196.146 &
|
||||
~/VerusCoin/src/komodod -pubkey=$pubkey -ac_name=VRSC -ac_algo=verushash -ac_cc=1 -ac_veruspos=50 -ac_supply=0 -ac_eras=3 -ac_reward=0,38400000000,2400000000 -ac_halving=1,43200,1051920 -ac_decay=100000000,0,0 -ac_end=10080,226080,0 -ac_timelockgte=19200000000 -ac_timeunlockfrom=129600 -ac_timeunlockto=1180800 -addnode=185.25.48.236 -addnode=185.64.105.111 &
|
||||
./komodod -pubkey=$pubkey -ac_name=SEC -ac_cc=333 -ac_supply=1000000000 -addnode=185.148.145.43 &
|
||||
./komodod -pubkey=$pubkey -ac_name=CCL -ac_supply=200000000 -ac_end=1 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=142.93.136.89 -addnode=195.201.22.89 &
|
||||
|
||||
@@ -1,40 +1,6 @@
|
||||
#!/bin/bash
|
||||
args=("$@")
|
||||
komodo_cli='./komodo-cli'
|
||||
delay=20
|
||||
set -eo pipefail
|
||||
|
||||
function komodo_stop ()
|
||||
{
|
||||
$komodo_cli --ac_name=$1 stop
|
||||
}
|
||||
|
||||
#set -x
|
||||
|
||||
komodo_stop REVS
|
||||
komodo_stop SUPERNET
|
||||
komodo_stop DEX
|
||||
komodo_stop PANGEA
|
||||
komodo_stop JUMBLR
|
||||
komodo_stop BET
|
||||
komodo_stop CRYPTO
|
||||
komodo_stop HODL
|
||||
komodo_stop MSHARK
|
||||
komodo_stop BOTS
|
||||
komodo_stop MGW
|
||||
komodo_stop COQUI
|
||||
komodo_stop WLC
|
||||
komodo_stop KV
|
||||
komodo_stop CEAL
|
||||
komodo_stop MESH
|
||||
komodo_stop MNZ
|
||||
komodo_stop AXO
|
||||
komodo_stop ETOMIC
|
||||
komodo_stop BTCH
|
||||
komodo_stop PIZZA
|
||||
komodo_stop BEER
|
||||
komodo_stop NINJA
|
||||
komodo_stop OOT
|
||||
komodo_stop BNTN
|
||||
komodo_stop CHAIN
|
||||
komodo_stop PRLPAY
|
||||
komodo_stop DSEC
|
||||
./listassetchains | while read chain; do
|
||||
./komodo-cli --ac_name=$chain stop
|
||||
done
|
||||
|
||||
@@ -144,21 +144,21 @@ bool AppInit(int argc, char* argv[])
|
||||
ReadConfigFile(mapArgs, mapMultiArgs);
|
||||
} catch (const missing_zcash_conf& e) {
|
||||
fprintf(stderr,
|
||||
(_("Before starting zcashd, you need to create a configuration file:\n"
|
||||
(_("Before starting komodod, you need to create a configuration file:\n"
|
||||
"%s\n"
|
||||
"It can be completely empty! That indicates you are happy with the default\n"
|
||||
"configuration of zcashd. But requiring a configuration file to start ensures\n"
|
||||
"that zcashd won't accidentally compromise your privacy if there was a default\n"
|
||||
"configuration of komodod. But requiring a configuration file to start ensures\n"
|
||||
"that komodod won't accidentally compromise your privacy if there was a default\n"
|
||||
"option you needed to change.\n"
|
||||
"\n"
|
||||
"You can look at the example configuration file for suggestions of default\n"
|
||||
"options that you may want to change. It should be in one of these locations,\n"
|
||||
"depending on how you installed Zcash:\n") +
|
||||
"depending on how you installed Komodo:\n") +
|
||||
_("- Source code: %s\n"
|
||||
"- .deb package: %s\n")).c_str(),
|
||||
GetConfigFile().string().c_str(),
|
||||
"contrib/debian/examples/zcash.conf",
|
||||
"/usr/share/doc/zcash/examples/zcash.conf");
|
||||
"contrib/debian/examples/komodo.conf",
|
||||
"/usr/share/doc/komodo/examples/komodo.conf");
|
||||
return false;
|
||||
} catch (const std::exception& e) {
|
||||
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
|
||||
|
||||
65
src/cc/CCassets.h
Normal file
65
src/cc/CCassets.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
CCassetstx has the functions that create the EVAL_ASSETS transactions. It is expected that rpc calls would call these functions. For EVAL_ASSETS, the rpc functions are in rpcwallet.cpp
|
||||
|
||||
CCassetsCore has functions that are used in two contexts, both during rpc transaction create time and also during the blockchain validation. Using the identical functions is a good way to prevent them from being mismatched. The must match or the transaction will get rejected.
|
||||
*/
|
||||
|
||||
#ifndef CC_ASSETS_H
|
||||
#define CC_ASSETS_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
// CCcustom
|
||||
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
|
||||
// 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 funcid,uint256 assetid,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,uint256 &assetid,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(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);
|
||||
bool ValidateAskRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice);
|
||||
bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice);
|
||||
bool SetBidFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice);
|
||||
bool SetAskFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice);
|
||||
bool SetSwapFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice);
|
||||
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);
|
||||
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);
|
||||
bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti,int64_t &outputs,Eval* eval,const CTransaction &tx,uint256 assetid);
|
||||
|
||||
// CCassetstx
|
||||
int64_t GetAssetBalance(CPubKey pk,uint256 tokenid);
|
||||
int64_t AddAssetInputs(CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
|
||||
UniValue AssetOrders(uint256 tokenid);
|
||||
UniValue AssetInfo(uint256 tokenid);
|
||||
UniValue AssetList();
|
||||
std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description);
|
||||
std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total);
|
||||
std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal);
|
||||
std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid);
|
||||
std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount);
|
||||
std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal);
|
||||
std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal);
|
||||
std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid);
|
||||
std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillamount);
|
||||
|
||||
#endif
|
||||
484
src/cc/CCassetsCore.cpp
Normal file
484
src/cc/CCassetsCore.cpp
Normal file
@@ -0,0 +1,484 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCassets.h"
|
||||
|
||||
/*
|
||||
The SetAssetFillamounts() and ValidateAssetRemainder() work in tandem to calculate the vouts for a fill and to validate the vouts, respectively.
|
||||
|
||||
This pair of functions are critical to make sure the trading is correct and is the trickiest part of the assets contract.
|
||||
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
//vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue
|
||||
//vout.0: remaining amount of bid to unspendable
|
||||
//vout.1: vin.1 value to signer of vin.2
|
||||
//vout.2: vin.2 assetoshis to original pubkey
|
||||
//vout.3: CC output for assetoshis change (if any)
|
||||
//vout.4: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey]
|
||||
ValidateAssetRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,totalunits);
|
||||
|
||||
Yes, this is quite confusing...
|
||||
|
||||
In ValudateAssetRemainder the naming convention is nValue is the coin/asset with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or assets, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits.
|
||||
|
||||
We assume that the effective unit cost in the orderbook is valid and that that amount was paid and also that any remainder will be close enough in effective unit cost to not matter. At the edge cases, this will probably be not true and maybe some orders wont be practically fillable when reduced to fractional state. However, the original pubkey that created the offer can always reclaim it.
|
||||
*/
|
||||
|
||||
bool ValidateBidRemainder(int64_t remaining_units,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidunits,int64_t totalunits)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//unitprice = (orig_nValue * COIN) / totalunits;
|
||||
//recvunitprice = (received_nValue * COIN) / paidunits;
|
||||
//if ( remaining_units != 0 )
|
||||
// newunitprice = (remaining_nValue * COIN) / remaining_units;
|
||||
unitprice = (orig_nValue / totalunits);
|
||||
recvunitprice = (received_nValue / paidunits);
|
||||
if ( remaining_units != 0 )
|
||||
newunitprice = (remaining_nValue / remaining_units);
|
||||
if ( recvunitprice < unitprice )
|
||||
{
|
||||
fprintf(stderr,"error recvunitprice %.16f < %.16f unitprice, new unitprice %.16f\n",(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
|
||||
return(false);
|
||||
}
|
||||
fprintf(stderr,"orig %llu total %llu, recv %llu paid %llu,recvunitprice %.16f >= %.16f unitprice, new unitprice %.16f\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);
|
||||
}
|
||||
|
||||
bool SetBidFillamounts(int64_t &received_nValue,int64_t &remaining_units,int64_t orig_nValue,int64_t &paidunits,int64_t totalunits)
|
||||
{
|
||||
int64_t remaining_nValue,unitprice; double dprice;
|
||||
if ( totalunits == 0 )
|
||||
{
|
||||
received_nValue = remaining_units = paidunits = 0;
|
||||
return(false);
|
||||
}
|
||||
if ( paidunits >= totalunits )
|
||||
{
|
||||
paidunits = totalunits;
|
||||
received_nValue = orig_nValue;
|
||||
remaining_units = 0;
|
||||
fprintf(stderr,"totally filled!\n");
|
||||
return(true);
|
||||
}
|
||||
remaining_units = (totalunits - paidunits);
|
||||
//unitprice = (orig_nValue * COIN) / totalunits;
|
||||
//received_nValue = (paidunits * unitprice) / COIN;
|
||||
unitprice = (orig_nValue / totalunits);
|
||||
received_nValue = (paidunits * unitprice);
|
||||
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);
|
||||
return(ValidateBidRemainder(remaining_units,remaining_nValue,orig_nValue,received_nValue,paidunits,totalunits));
|
||||
} else return(false);
|
||||
}
|
||||
|
||||
bool SetAskFillamounts(int64_t &received_assetoshis,int64_t &remaining_nValue,int64_t orig_assetoshis,int64_t &paid_nValue,int64_t total_nValue)
|
||||
{
|
||||
int64_t remaining_assetoshis; double dunitprice;
|
||||
if ( total_nValue == 0 )
|
||||
{
|
||||
received_assetoshis = remaining_nValue = paid_nValue = 0;
|
||||
return(false);
|
||||
}
|
||||
if ( paid_nValue >= total_nValue )
|
||||
{
|
||||
paid_nValue = total_nValue;
|
||||
received_assetoshis = orig_assetoshis;
|
||||
remaining_nValue = 0;
|
||||
fprintf(stderr,"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);
|
||||
if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
|
||||
{
|
||||
remaining_assetoshis = (orig_assetoshis - received_assetoshis);
|
||||
return(ValidateAskRemainder(remaining_nValue,remaining_assetoshis,orig_assetoshis,received_assetoshis,paid_nValue,total_nValue));
|
||||
} else return(false);
|
||||
}
|
||||
|
||||
bool ValidateAskRemainder(int64_t remaining_nValue,int64_t remaining_assetoshis,int64_t orig_assetoshis,int64_t received_assetoshis,int64_t paid_nValue,int64_t total_nValue)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
unitprice = (total_nValue / orig_assetoshis);
|
||||
recvunitprice = (paid_nValue / received_assetoshis);
|
||||
if ( remaining_nValue != 0 )
|
||||
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);
|
||||
return(false);
|
||||
}
|
||||
fprintf(stderr,"got recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool SetSwapFillamounts(int64_t &received_assetoshis,int64_t &remaining_assetoshis2,int64_t orig_assetoshis,int64_t &paid_assetoshis2,int64_t total_assetoshis2)
|
||||
{
|
||||
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);
|
||||
received_assetoshis = remaining_assetoshis2 = paid_assetoshis2 = 0;
|
||||
return(false);
|
||||
}
|
||||
if ( paid_assetoshis2 >= total_assetoshis2 )
|
||||
{
|
||||
paid_assetoshis2 = total_assetoshis2;
|
||||
received_assetoshis = orig_assetoshis;
|
||||
remaining_assetoshis2 = 0;
|
||||
fprintf(stderr,"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);
|
||||
if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
|
||||
{
|
||||
remaining_assetoshis = (orig_assetoshis - received_assetoshis);
|
||||
return(ValidateAskRemainder(remaining_assetoshis2,remaining_assetoshis,orig_assetoshis,received_assetoshis,paid_assetoshis2,total_assetoshis2));
|
||||
} else return(false);
|
||||
}
|
||||
|
||||
bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidunits,int64_t totalunits)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
unitprice = (orig_nValue * COIN) / totalunits;
|
||||
recvunitprice = (received_nValue * COIN) / paidunits;
|
||||
if ( remaining_price != 0 )
|
||||
newunitprice = (remaining_nValue * COIN) / remaining_price;
|
||||
if ( recvunitprice < unitprice )
|
||||
{
|
||||
fprintf(stderr,"error recvunitprice %.16f < %.16f unitprice, new unitprice %.16f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
|
||||
return(false);
|
||||
}
|
||||
fprintf(stderr,"recvunitprice %.16f >= %.16f unitprice, new unitprice %.16f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,std::string name,std::string description)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_ASSETS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector<uint8_t> origpubkey)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_ASSETS;
|
||||
assetid = revuint256(assetid);
|
||||
switch ( funcid )
|
||||
{
|
||||
case 't': case 'x': case 'o':
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid);
|
||||
break;
|
||||
case 's': case 'b': case 'S': case 'B':
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << price << origpubkey);
|
||||
break;
|
||||
case 'E': case 'e':
|
||||
assetid2 = revuint256(assetid2);
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << assetid2 << price << origpubkey);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"EncodeOpRet: illegal funcid.%02x\n",funcid);
|
||||
opret << OP_RETURN;
|
||||
break;
|
||||
}
|
||||
return(opret);
|
||||
}
|
||||
|
||||
bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t evalcode,funcid,*script;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( script != 0 && vopret.size() > 2 && script[0] == EVAL_ASSETS && script[1] == 'c' )
|
||||
{
|
||||
if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description) != 0 )
|
||||
return(true);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector<uint8_t> &origpubkey)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t funcid=0,*script,e,f;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
memset(&assetid,0,sizeof(assetid));
|
||||
memset(&assetid2,0,sizeof(assetid2));
|
||||
price = 0;
|
||||
if ( script != 0 && script[0] == EVAL_ASSETS )
|
||||
{
|
||||
funcid = script[1];
|
||||
//fprintf(stderr,"decode.[%c]\n",funcid);
|
||||
switch ( funcid )
|
||||
{
|
||||
case 'c': return(funcid);
|
||||
break;
|
||||
case 't': case 'x': case 'o':
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid) != 0 )
|
||||
{
|
||||
assetid = revuint256(assetid);
|
||||
return(funcid);
|
||||
}
|
||||
break;
|
||||
case 's': case 'b': case 'S': case 'B':
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> price; ss >> origpubkey) != 0 )
|
||||
{
|
||||
assetid = revuint256(assetid);
|
||||
//fprintf(stderr,"got price %llu\n",(long long)price);
|
||||
return(funcid);
|
||||
}
|
||||
break;
|
||||
case 'E': case 'e':
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"got price %llu\n",(long long)price);
|
||||
assetid = revuint256(assetid);
|
||||
assetid2 = revuint256(assetid2);
|
||||
return(funcid);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"DecodeAssetOpRet: illegal funcid.%02x\n",funcid);
|
||||
funcid = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(funcid);
|
||||
}
|
||||
|
||||
bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx)
|
||||
{
|
||||
uint256 assetid,assetid2;
|
||||
if ( tx.vout.size() > 0 && DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 )
|
||||
return(true);
|
||||
else return(false);
|
||||
}
|
||||
|
||||
bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,const CTransaction& tx)
|
||||
{
|
||||
uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector<uint8_t> origpubkey; CScript script;
|
||||
n = tx.vout.size();
|
||||
if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
|
||||
return(false);
|
||||
if ( GetCCaddress(cp,CCaddr,pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr,CScript() << origpubkey << OP_CHECKSIG) != 0 )
|
||||
return(true);
|
||||
else return(false);
|
||||
}
|
||||
|
||||
int64_t IsAssetvout(int64_t &price,std::vector<uint8_t> &origpubkey,const CTransaction& tx,int32_t v,uint256 refassetid)
|
||||
{
|
||||
uint256 assetid,assetid2; int64_t nValue=0; int32_t n; uint8_t funcid;
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) // maybe check address too?
|
||||
{
|
||||
n = tx.vout.size();
|
||||
nValue = tx.vout[v].nValue;
|
||||
//fprintf(stderr,"CC vout v.%d of n.%d %.8f\n",v,n,(double)nValue/COIN);
|
||||
if ( v >= n-1 )
|
||||
return(0);
|
||||
if ( (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
|
||||
{
|
||||
fprintf(stderr,"null decodeopret\n");
|
||||
return(0);
|
||||
}
|
||||
else if ( funcid == 'c' )
|
||||
{
|
||||
if ( refassetid == tx.GetHash() && v == 0 )
|
||||
return(nValue);
|
||||
}
|
||||
else if ( (funcid == 'b' || funcid == 'B') && v == 0 ) // critical! 'b'/'B' vout0 is NOT asset
|
||||
return(0);
|
||||
else if ( funcid != 'E' )
|
||||
{
|
||||
if ( assetid == refassetid )
|
||||
return(nValue);
|
||||
}
|
||||
else if ( funcid == 'E' )
|
||||
{
|
||||
if ( v < 2 && assetid == refassetid )
|
||||
return(nValue);
|
||||
else if ( v == 2 && assetid2 == refassetid )
|
||||
return(nValue);
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"Isassetvout: normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx)
|
||||
{
|
||||
uint256 hashBlock; char destaddr[64];
|
||||
origaddr[0] = destaddr[0] = CCaddr[0] = 0;
|
||||
if ( tx.vin.size() < 2 )
|
||||
return eval->Invalid("not enough for CC vins");
|
||||
else if ( tx.vin[vini].prevout.n != 0 )
|
||||
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);
|
||||
return eval->Invalid("always should find CCvin, but didnt");
|
||||
}
|
||||
else if ( Getscriptaddress(destaddr,vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || strcmp(destaddr,(char *)cp->unspendableCCaddr) != 0 )
|
||||
{
|
||||
fprintf(stderr,"%s vs %s\n",destaddr,(char *)cp->unspendableCCaddr);
|
||||
return eval->Invalid("invalid vin AssetsCCaddr");
|
||||
}
|
||||
//else if ( vinTx.vout[0].nValue < 10000 )
|
||||
// return eval->Invalid("invalid dust for buyvin");
|
||||
else if ( GetAssetorigaddrs(cp,CCaddr,origaddr,vinTx) == 0 )
|
||||
return eval->Invalid("couldnt get origaddr for buyvin");
|
||||
fprintf(stderr,"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;
|
||||
CCaddr[0] = origaddr[0] = 0;
|
||||
if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 )
|
||||
return(0);
|
||||
else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("invalid normal vout0 for buyvin");
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"have %.8f checking assetid origaddr.(%s)\n",(double)nValue/COIN,origaddr);
|
||||
if ( vinTx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,assetid,assetid2,tmpprice,tmporigpubkey)) != 'b' && funcid != 'B' )
|
||||
return eval->Invalid("invalid opreturn for buyvin");
|
||||
else if ( refassetid != assetid )
|
||||
return eval->Invalid("invalid assetid for buyvin");
|
||||
//int32_t i; for (i=31; i>=0; i--)
|
||||
// fprintf(stderr,"%02x",((uint8_t *)&assetid)[i]);
|
||||
//fprintf(stderr," AssetValidateBuyvin assetid for %s\n",origaddr);
|
||||
}
|
||||
return(nValue);
|
||||
}
|
||||
|
||||
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");
|
||||
if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 )
|
||||
return(0);
|
||||
if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,vinTx,0,assetid)) == 0 )
|
||||
return eval->Invalid("invalid missing CC vout0 for sellvin");
|
||||
else return(assetoshis);
|
||||
}
|
||||
|
||||
bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti,int64_t &outputs,Eval* eval,const CTransaction &tx,uint256 assetid)
|
||||
{
|
||||
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t assetoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
inputs = outputs = 0;
|
||||
for (i=starti; i<numvins; i++)
|
||||
{
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
|
||||
{
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
{
|
||||
fprintf(stderr,"i.%d starti.%d numvins.%d\n",i,starti,numvins);
|
||||
return eval->Invalid("always should find vin, but didnt");
|
||||
}
|
||||
else if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,vinTx,tx.vin[i].prevout.n,assetid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"vin%d %llu, ",i,(long long)assetoshis);
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<numvouts; i++)
|
||||
{
|
||||
if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,tx,i,assetid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"vout%d %llu, ",i,(long long)assetoshis);
|
||||
outputs += assetoshis;
|
||||
}
|
||||
}
|
||||
if ( inputs != outputs )
|
||||
{
|
||||
fprintf(stderr,"inputs %.8f vs %.8f outputs\n",(double)inputs/COIN,(double)outputs/COIN);
|
||||
return(false);
|
||||
}
|
||||
else return(true);
|
||||
}
|
||||
486
src/cc/CCassetstx.cpp
Normal file
486
src/cc/CCassetstx.cpp
Normal file
@@ -0,0 +1,486 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCassets.h"
|
||||
extern std::string CCerror;
|
||||
|
||||
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs)
|
||||
{
|
||||
char coinaddr[64]; int64_t 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);
|
||||
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;
|
||||
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 )
|
||||
{
|
||||
if ( (nValue= IsAssetvout(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;
|
||||
n++;
|
||||
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
int64_t GetAssetBalance(CPubKey pk,uint256 tokenid)
|
||||
{
|
||||
CMutableTransaction mtx; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
return(AddAssetInputs(cp,mtx,pk,tokenid,0,0));
|
||||
}
|
||||
|
||||
UniValue AssetInfo(uint256 assetid)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description; char str[67],numstr[65];
|
||||
if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
|
||||
{
|
||||
fprintf(stderr,"cant find assetid\n");
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","cant find assetid"));
|
||||
return(result);
|
||||
}
|
||||
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 )
|
||||
{
|
||||
fprintf(stderr,"assetid isnt assetcreation txid\n");
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","assetid isnt assetcreation txid"));
|
||||
}
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("tokenid",uint256_str(str,assetid)));
|
||||
result.push_back(Pair("owner",pubkey33_str(str,origpubkey.data())));
|
||||
result.push_back(Pair("name",name));
|
||||
result.push_back(Pair("supply",vintx.vout[0].nValue));
|
||||
result.push_back(Pair("description",description));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue AssetList()
|
||||
{
|
||||
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description; char str[65];
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
SetCCtxids(addressIndex,cp->normaladdr);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) != 0 )
|
||||
{
|
||||
result.push_back(uint256_str(str,txid));
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue AssetOrders(uint256 refassetid)
|
||||
{
|
||||
static uint256 zero;
|
||||
int64_t price; uint256 txid,hashBlock,assetid,assetid2; std::vector<uint8_t> origpubkey; CTransaction vintx; UniValue result(UniValue::VARR); std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; uint8_t funcid; char numstr[32],funcidstr[16],origaddr[64],assetidstr[65]; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
SetCCunspents(unspentOutputs,(char *)cp->unspendableCCaddr);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( vintx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,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");
|
||||
continue;
|
||||
}
|
||||
if ( vintx.vout[it->first.index].nValue == 0 )
|
||||
continue;
|
||||
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)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));
|
||||
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' )
|
||||
{
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
result.push_back(item);
|
||||
//fprintf(stderr,"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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C;
|
||||
if ( assetsupply < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative assetsupply %lld\n",(long long)assetsupply);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( name.size() > 32 || description.size() > 4096 )
|
||||
{
|
||||
fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
|
||||
return("");
|
||||
}
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,assetsupply+2*txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,assetsupply,mypk));
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(cp->CChexstr) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetCreateOpRet('c',Mypubkey(),name,description)));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk; uint64_t mask; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
|
||||
if ( total < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative total %lld\n",(long long)total);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
|
||||
{
|
||||
/*n = outputs.size();
|
||||
if ( n == amounts.size() )
|
||||
{
|
||||
for (i=0; i<n; i++)
|
||||
total += amounts[i];*/
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
|
||||
{
|
||||
if ( inputs > total )
|
||||
CCchange = (inputs - total);
|
||||
//for (i=0; i<n; i++)
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,total,pubkey2pk(destpubkey)));
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
|
||||
} else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN);
|
||||
//} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description;
|
||||
if ( bidamount < 0 || pricetotal < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n",(long long)bidamount,(long long)pricetotal);
|
||||
return("");
|
||||
}
|
||||
if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
|
||||
{
|
||||
fprintf(stderr,"cant find assetid\n");
|
||||
return("");
|
||||
}
|
||||
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 )
|
||||
{
|
||||
fprintf(stderr,"assetid isnt assetcreation txid\n");
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,bidamount+txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount,GetUnspendable(cp,0)));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('b',assetid,zeroid,pricetotal,Mypubkey())));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
|
||||
if ( askamount < 0 || pricetotal < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
|
||||
{
|
||||
if ( inputs < askamount )
|
||||
askamount = inputs;
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
|
||||
if ( inputs > askamount )
|
||||
CCchange = (inputs - askamount);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
|
||||
} else fprintf(stderr,"need some assets to place ask\n");
|
||||
}
|
||||
fprintf(stderr,"need some native coins to place ask\n");
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
|
||||
fprintf(stderr,"asset swaps disabled\n");
|
||||
return("");
|
||||
if ( askamount < 0 || pricetotal < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
|
||||
{
|
||||
if ( inputs < askamount )
|
||||
askamount = inputs;
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
|
||||
if ( inputs > askamount )
|
||||
CCchange = (inputs - askamount);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
if ( assetid2 == zeroid )
|
||||
opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
|
||||
else
|
||||
{
|
||||
opret = EncodeAssetOpRet('e',assetid,assetid2,pricetotal,Mypubkey());
|
||||
}
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
|
||||
} else fprintf(stderr,"need some assets to place ask\n");
|
||||
}
|
||||
fprintf(stderr,"need some native coins to place ask\n");
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
|
||||
{
|
||||
CMutableTransaction mtx; CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t bidamount; CPubKey mypk; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
bidamount = vintx.vout[0].nValue;
|
||||
mtx.vin.push_back(CTxIn(bidtxid,0,CScript()));
|
||||
mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('o',assetid,zeroid,0,Mypubkey())));
|
||||
}
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
|
||||
{
|
||||
CMutableTransaction mtx; CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
askamount = vintx.vout[0].nValue;
|
||||
mtx.vin.push_back(CTxIn(asktxid,0,CScript()));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,mypk));
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('x',assetid,zeroid,0,Mypubkey())));
|
||||
}
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount)
|
||||
{
|
||||
CTransaction vintx; uint256 hashBlock; CMutableTransaction mtx; CPubKey mypk; std::vector<uint8_t> origpubkey; int32_t bidvout=0; uint64_t mask; int64_t origprice,bidamount,paid_amount,remaining_required,inputs,CCchange=0; struct CCcontract_info *cp,C;
|
||||
if ( fillamount < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative fillamount %lld\n",(long long)fillamount);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
bidamount = vintx.vout[bidvout].nValue;
|
||||
SetAssetOrigpubkey(origpubkey,origprice,vintx);
|
||||
mtx.vin.push_back(CTxIn(bidtxid,bidvout,CScript()));
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,fillamount,60)) > 0 )
|
||||
{
|
||||
if ( inputs < fillamount )
|
||||
fillamount = inputs;
|
||||
SetBidFillamounts(paid_amount,remaining_required,bidamount,fillamount,origprice);
|
||||
if ( inputs > fillamount )
|
||||
CCchange = (inputs - fillamount);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount - paid_amount,GetUnspendable(cp,0)));
|
||||
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,fillamount,pubkey2pk(origpubkey)));
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
fprintf(stderr,"remaining %llu -> origpubkey\n",(long long)remaining_required);
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('B',assetid,zeroid,remaining_required,origpubkey)));
|
||||
} else return("dont have any assets to fill bid\n");
|
||||
}
|
||||
}
|
||||
return("no normal coins left");
|
||||
}
|
||||
|
||||
std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillunits)
|
||||
{
|
||||
CTransaction vintx,filltx; uint256 hashBlock; CMutableTransaction mtx; CPubKey mypk; std::vector<uint8_t> origpubkey; double dprice; uint64_t mask; int32_t askvout=0; int64_t received_assetoshis,total_nValue,orig_assetoshis,paid_nValue,remaining_nValue,inputs,CCchange=0; struct CCcontract_info *cp,C;
|
||||
if ( fillunits < 0 )
|
||||
{
|
||||
CCerror = strprintf("negative fillunits %lld\n",(long long)fillunits);
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
if ( assetid2 != zeroid )
|
||||
{
|
||||
CCerror = "asset swaps disabled";
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
orig_assetoshis = vintx.vout[askvout].nValue;
|
||||
SetAssetOrigpubkey(origpubkey,total_nValue,vintx);
|
||||
dprice = (double)total_nValue / orig_assetoshis;
|
||||
paid_nValue = dprice * fillunits;
|
||||
mtx.vin.push_back(CTxIn(asktxid,askvout,CScript()));
|
||||
if ( assetid2 != zeroid )
|
||||
inputs = AddAssetInputs(cp,mtx,mypk,assetid2,paid_nValue,60);
|
||||
else
|
||||
{
|
||||
inputs = AddNormalinputs(mtx,mypk,paid_nValue,60);
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
}
|
||||
if ( inputs > 0 )
|
||||
{
|
||||
if ( inputs < paid_nValue )
|
||||
paid_nValue = inputs;
|
||||
if ( assetid2 != zeroid )
|
||||
SetSwapFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue);
|
||||
else SetAskFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue);
|
||||
if ( assetid2 != zeroid && inputs > paid_nValue )
|
||||
CCchange = (inputs - paid_nValue);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,orig_assetoshis - received_assetoshis,GetUnspendable(cp,0)));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,received_assetoshis,mypk));
|
||||
if ( assetid2 != zeroid )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,paid_nValue,origpubkey));
|
||||
else mtx.vout.push_back(CTxOut(paid_nValue,CScript() << origpubkey << OP_CHECKSIG));
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet(assetid2!=zeroid?'E':'S',assetid,assetid2,remaining_nValue,origpubkey)));
|
||||
} else {
|
||||
CCerror = strprintf("filltx not enough utxos");
|
||||
fprintf(stderr,"%s\n", CCerror.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
return("");
|
||||
}
|
||||
30
src/cc/CCauction.h
Normal file
30
src/cc/CCauction.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/******************************************************************************
|
||||
* 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_AUCTION_H
|
||||
#define CC_AUCTION_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
#define EVAL_AUCTION 0xe8
|
||||
|
||||
bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
|
||||
std::string AuctionPost(uint64_t txfee,uint256 itemhash,int64_t minbid,char *title,char *description);
|
||||
std::string AuctionBid(uint64_t txfee,uint256 itemhash,int64_t amount);
|
||||
std::string AuctionDeliver(uint64_t txfee,uint256 itemhash,uint256 bidtxid);
|
||||
|
||||
#endif
|
||||
195
src/cc/CCcustom.cpp
Normal file
195
src/cc/CCcustom.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "CCassets.h"
|
||||
#include "CCfaucet.h"
|
||||
#include "CCrewards.h"
|
||||
#include "CCdice.h"
|
||||
#include "CCauction.h"
|
||||
#include "CClotto.h"
|
||||
#include "CCfsm.h"
|
||||
|
||||
/*
|
||||
CCcustom has most of the functions that need to be extended to create a new CC contract.
|
||||
|
||||
A CC scriptPubKey can only be spent if it is properly signed and validated. By constraining the vins and vouts, it is possible to implement a variety of functionality. CC vouts have an otherwise non-standard form, but it is properly supported by the enhanced bitcoin protocol code as a "cryptoconditions" output and the same pubkey will create a different address.
|
||||
|
||||
This allows creation of a special address(es) for each contract type, which has the privkey public. That allows anybody to properly sign and spend it, but with the constraints on what is allowed in the validation code, the contract functionality can be implemented.
|
||||
|
||||
what needs to be done to add a new contract:
|
||||
1. add EVAL_CODE to eval.h
|
||||
2. initialize the variables in the CCinit function below
|
||||
3. write a Validate function to reject any unsanctioned usage of vin/vout
|
||||
4. make helper functions to create rawtx for RPC functions
|
||||
5. add rpc calls to rpcserver.cpp and rpcserver.h and in one of the rpc.cpp files
|
||||
6. add the new .cpp files to src/Makefile.am
|
||||
|
||||
IMPORTANT: make sure that all CC inputs and CC outputs are properly accounted for and reconcile to the satoshi. The built in utxo management will enforce overall vin/vout constraints but it wont know anything about the CC constraints. That is what your Validate function needs to do.
|
||||
|
||||
Generally speaking, there will be normal coins that change into CC outputs, CC outputs that go back to being normal coins, CC outputs that are spent to new CC outputs.
|
||||
|
||||
Make sure both the CC coins and normal coins are preserved and follow the rules that make sense. It is a good idea to define specific roles for specific vins and vouts to reduce the complexity of validation.
|
||||
*/
|
||||
|
||||
//BTCD Address: RAssetsAtGnvwgK9gVHBbAU4sVTah1hAm5
|
||||
//BTCD Privkey: UvtvQVgVScXEYm4J3r4nE4nbFuGXSVM5pKec8VWXwgG9dmpWBuDh
|
||||
//BTCD Address: RSavingsEYcivt2DFsxsKeCjqArV6oVtVZ
|
||||
//BTCD Privkey: Ux6XQekTxokko6gZHz24B7PUsmUQtWFzG2W9nUA8jba7UoVbPBF4
|
||||
|
||||
// Assets, aka Tokens
|
||||
#define FUNCNAME IsAssetsInput
|
||||
#define EVALCODE EVAL_ASSETS
|
||||
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
|
||||
|
||||
// Faucet
|
||||
#define FUNCNAME IsFaucetInput
|
||||
#define EVALCODE EVAL_FAUCET
|
||||
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
|
||||
|
||||
// Rewards
|
||||
#define FUNCNAME IsRewardsInput
|
||||
#define EVALCODE EVAL_REWARDS
|
||||
const char *RewardsCCaddr = "RTsRBYL1HSvMoE3qtBJkyiswdVaWkm8YTK";
|
||||
const char *RewardsNormaladdr = "RMgye9jeczNjQx9Uzq8no8pTLiCSwuHwkz";
|
||||
char RewardsCChexstr[67] = { "03da60379d924c2c30ac290d2a86c2ead128cb7bd571f69211cb95356e2dcc5eb9" };
|
||||
uint8_t RewardsCCpriv[32] = { 0x82, 0xf5, 0xd2, 0xe7, 0xd6, 0x99, 0x33, 0x77, 0xfb, 0x80, 0x00, 0x97, 0x23, 0x3d, 0x1e, 0x6f, 0x61, 0xa9, 0xb5, 0x2e, 0x5e, 0xb4, 0x96, 0x6f, 0xbc, 0xed, 0x6b, 0xe2, 0xbb, 0x7b, 0x4b, 0xb3 };
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
// Dice
|
||||
#define FUNCNAME IsDiceInput
|
||||
#define EVALCODE EVAL_DICE
|
||||
const char *DiceCCaddr = "REabWB7KjFN5C3LFMZ5odExHPenYzHLtVw";
|
||||
const char *DiceNormaladdr = "RLEe8f7Eg3TDuXii9BmNiiiaVGraHUt25c";
|
||||
char DiceCChexstr[67] = { "039d966927cfdadab3ee6c56da63c21f17ea753dde4b3dfd41487103e24b27e94e" };
|
||||
uint8_t DiceCCpriv[32] = { 0x0e, 0xe8, 0xf5, 0xb4, 0x3d, 0x25, 0xcc, 0x35, 0xd1, 0xf1, 0x2f, 0x04, 0x5f, 0x01, 0x26, 0xb8, 0xd1, 0xac, 0x3a, 0x5a, 0xea, 0xe0, 0x25, 0xa2, 0x8f, 0x2a, 0x8e, 0x0e, 0xf9, 0x34, 0xfa, 0x77 };
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
// Lotto
|
||||
#define FUNCNAME IsLottoInput
|
||||
#define EVALCODE EVAL_LOTTO
|
||||
const char *LottoCCaddr = "RNXZxgyWSAE6XS3qGnTaf5dVNCxnYzhPrg";
|
||||
const char *LottoNormaladdr = "RLW6hhRqBZZMBndnyPv29Yg3krh6iBYCyg";
|
||||
char LottoCChexstr[67] = { "03f72d2c4db440df1e706502b09ca5fec73ffe954ea1883e4049e98da68690d98f" };
|
||||
uint8_t LottoCCpriv[32] = { 0xb4, 0xac, 0xc2, 0xd9, 0x67, 0x34, 0xd7, 0x58, 0x80, 0x4e, 0x25, 0x55, 0xc0, 0x50, 0x66, 0x84, 0xbb, 0xa2, 0xe7, 0xc0, 0x39, 0x17, 0xb4, 0xc5, 0x07, 0xb7, 0x3f, 0xca, 0x07, 0xb0, 0x9a, 0xeb };
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
// Finite State Machine
|
||||
#define FUNCNAME IsFSMInput
|
||||
#define EVALCODE EVAL_FSM
|
||||
const char *FSMCCaddr = "RUKTbLBeKgHkm3Ss4hKZP3ikuLW1xx7B2x";
|
||||
const char *FSMNormaladdr = "RWSHRbxnJYLvDjpcQ2i8MekgP6h2ctTKaj";
|
||||
char FSMCChexstr[67] = { "039b52d294b413b07f3643c1a28c5467901a76562d8b39a785910ae0a0f3043810" };
|
||||
uint8_t FSMCCpriv[32] = { 0x11, 0xe1, 0xea, 0x3e, 0xdb, 0x36, 0xf0, 0xa8, 0xc6, 0x34, 0xe1, 0x21, 0xb8, 0x02, 0xb9, 0x4b, 0x12, 0x37, 0x8f, 0xa0, 0x86, 0x23, 0x50, 0xb2, 0x5f, 0xe4, 0xe7, 0x36, 0x0f, 0xda, 0xae, 0xfc };
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
// Auction
|
||||
#define FUNCNAME IsAuctionInput
|
||||
#define EVALCODE EVAL_AUCTION
|
||||
const char *AuctionCCaddr = "RL4YPX7JYG3FnvoPqWF2pn3nQknH5NWEwx";
|
||||
const char *AuctionNormaladdr = "RFtVDNmdTZBTNZdmFRbfBgJ6LitgTghikL";
|
||||
char AuctionCChexstr[67] = { "037eefe050c14cb60ae65d5b2f69eaa1c9006826d729bc0957bdc3024e3ca1dbe6" };
|
||||
uint8_t AuctionCCpriv[32] = { 0x8c, 0x1b, 0xb7, 0x8c, 0x02, 0xa3, 0x9d, 0x21, 0x28, 0x59, 0xf5, 0xea, 0xda, 0xec, 0x0d, 0x11, 0xcd, 0x38, 0x47, 0xac, 0x0b, 0x6f, 0x19, 0xc0, 0x24, 0x36, 0xbf, 0x1c, 0x0a, 0x06, 0x31, 0xfb };
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode)
|
||||
{
|
||||
cp->evalcode = evalcode;
|
||||
switch ( evalcode )
|
||||
{
|
||||
case EVAL_ASSETS:
|
||||
strcpy(cp->unspendableCCaddr,AssetsCCaddr);
|
||||
strcpy(cp->normaladdr,AssetsNormaladdr);
|
||||
strcpy(cp->CChexstr,AssetsCChexstr);
|
||||
memcpy(cp->CCpriv,AssetsCCpriv,32);
|
||||
cp->validate = AssetsValidate;
|
||||
cp->ismyvin = IsAssetsInput;
|
||||
break;
|
||||
case EVAL_FAUCET:
|
||||
strcpy(cp->unspendableCCaddr,FaucetCCaddr);
|
||||
strcpy(cp->normaladdr,FaucetNormaladdr);
|
||||
strcpy(cp->CChexstr,FaucetCChexstr);
|
||||
memcpy(cp->CCpriv,FaucetCCpriv,32);
|
||||
cp->validate = FaucetValidate;
|
||||
cp->ismyvin = IsFaucetInput;
|
||||
break;
|
||||
case EVAL_REWARDS:
|
||||
strcpy(cp->unspendableCCaddr,RewardsCCaddr);
|
||||
strcpy(cp->normaladdr,RewardsNormaladdr);
|
||||
strcpy(cp->CChexstr,RewardsCChexstr);
|
||||
memcpy(cp->CCpriv,RewardsCCpriv,32);
|
||||
cp->validate = RewardsValidate;
|
||||
cp->ismyvin = IsRewardsInput;
|
||||
break;
|
||||
case EVAL_DICE:
|
||||
strcpy(cp->unspendableCCaddr,DiceCCaddr);
|
||||
strcpy(cp->normaladdr,DiceNormaladdr);
|
||||
strcpy(cp->CChexstr,DiceCChexstr);
|
||||
memcpy(cp->CCpriv,DiceCCpriv,32);
|
||||
cp->validate = DiceValidate;
|
||||
cp->ismyvin = IsDiceInput;
|
||||
break;
|
||||
case EVAL_LOTTO:
|
||||
strcpy(cp->unspendableCCaddr,LottoCCaddr);
|
||||
strcpy(cp->normaladdr,LottoNormaladdr);
|
||||
strcpy(cp->CChexstr,LottoCChexstr);
|
||||
memcpy(cp->CCpriv,LottoCCpriv,32);
|
||||
cp->validate = LottoValidate;
|
||||
cp->ismyvin = IsLottoInput;
|
||||
break;
|
||||
case EVAL_FSM:
|
||||
strcpy(cp->unspendableCCaddr,FSMCCaddr);
|
||||
strcpy(cp->normaladdr,FSMNormaladdr);
|
||||
strcpy(cp->CChexstr,FSMCChexstr);
|
||||
memcpy(cp->CCpriv,FSMCCpriv,32);
|
||||
cp->validate = FSMValidate;
|
||||
cp->ismyvin = IsFSMInput;
|
||||
break;
|
||||
case EVAL_AUCTION:
|
||||
strcpy(cp->unspendableCCaddr,AuctionCCaddr);
|
||||
strcpy(cp->normaladdr,AuctionNormaladdr);
|
||||
strcpy(cp->CChexstr,AuctionCChexstr);
|
||||
memcpy(cp->CCpriv,AuctionCCpriv,32);
|
||||
cp->validate = AuctionValidate;
|
||||
cp->ismyvin = IsAuctionInput;
|
||||
break;
|
||||
}
|
||||
return(cp);
|
||||
}
|
||||
|
||||
17
src/cc/CCcustom.inc
Normal file
17
src/cc/CCcustom.inc
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
bool FUNCNAME(CScript const& scriptSig)
|
||||
{
|
||||
CC *cond;
|
||||
if (!(cond = GetCryptoCondition(scriptSig)))
|
||||
return false;
|
||||
// Recurse the CC tree to find asset condition
|
||||
auto findEval = [] (CC *cond, struct CCVisitor _) {
|
||||
bool r = cc_typeId(cond) == CC_Eval && cond->codeLength == 1 && cond->code[0] == EVALCODE;
|
||||
// false for a match, true for continue
|
||||
return r ? 0 : 1;
|
||||
};
|
||||
CCVisitor visitor = {findEval, (uint8_t*)"", 0, NULL};
|
||||
bool out =! cc_visit(cond, visitor);
|
||||
cc_free(cond);
|
||||
return out;
|
||||
}
|
||||
34
src/cc/CCdice.h
Normal file
34
src/cc/CCdice.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/******************************************************************************
|
||||
* 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_DICE_H
|
||||
#define CC_DICE_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
#define EVAL_DICE 0xe6
|
||||
|
||||
bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
|
||||
std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds);
|
||||
std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout);
|
||||
double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid);
|
||||
std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks);
|
||||
std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount);
|
||||
UniValue DiceInfo(uint256 diceid);
|
||||
UniValue DiceList();
|
||||
|
||||
#endif
|
||||
32
src/cc/CCfaucet.h
Normal file
32
src/cc/CCfaucet.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/******************************************************************************
|
||||
* 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_FAUCET_H
|
||||
#define CC_FAUCET_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
#define EVAL_FAUCET 0xe4
|
||||
#define FAUCETSIZE (COIN / 10)
|
||||
|
||||
bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
|
||||
// CCcustom
|
||||
std::string FaucetFund(uint64_t txfee,int64_t funds);
|
||||
std::string FaucetGet(uint64_t txfee);
|
||||
UniValue FaucetInfo();
|
||||
|
||||
#endif
|
||||
30
src/cc/CCfsm.h
Normal file
30
src/cc/CCfsm.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/******************************************************************************
|
||||
* 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_FSM_H
|
||||
#define CC_FSM_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
#define EVAL_FSM 0xe7
|
||||
|
||||
bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
|
||||
std::string FSMList();
|
||||
std::string FSMInfo(uint256 fsmtxid);
|
||||
std::string FSMCreate(uint64_t txfee,std::string name,std::string states);
|
||||
|
||||
#endif
|
||||
107
src/cc/CCinclude.h
Normal file
107
src/cc/CCinclude.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/******************************************************************************
|
||||
* 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_INCLUDE_H
|
||||
#define CC_INCLUDE_H
|
||||
|
||||
#include <cc/eval.h>
|
||||
#include <script/cc.h>
|
||||
#include <script/script.h>
|
||||
#include <cryptoconditions.h>
|
||||
#include "../script/standard.h"
|
||||
#include "../base58.h"
|
||||
#include "../core_io.h"
|
||||
#include "../script/sign.h"
|
||||
#include "../wallet/wallet.h"
|
||||
#include <univalue.h>
|
||||
#include <exception>
|
||||
|
||||
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE;
|
||||
|
||||
#define SMALLVAL 0.000000000000001
|
||||
union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; };
|
||||
typedef union _bits256 bits256;
|
||||
|
||||
struct CC_utxo
|
||||
{
|
||||
uint256 txid;
|
||||
int64_t nValue;
|
||||
int32_t vout;
|
||||
};
|
||||
|
||||
struct CCcontract_info
|
||||
{
|
||||
uint256 prevtxid;
|
||||
char unspendableCCaddr[64],CChexstr[72],normaladdr[64];
|
||||
uint8_t CCpriv[32];
|
||||
bool (*validate)(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
bool (*ismyvin)(CScript const& scriptSig);
|
||||
uint8_t evalcode,didinit;
|
||||
};
|
||||
struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode);
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
extern CWallet* pwalletMain;
|
||||
#endif
|
||||
bool GetAddressUnspent(uint160 addressHash, int type,std::vector<std::pair<CAddressUnspentKey,CAddressUnspentValue> > &unspentOutputs);
|
||||
|
||||
static const uint256 zeroid;
|
||||
bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock);
|
||||
int32_t is_hexstr(char *str,int32_t n);
|
||||
bool myAddtomempool(CTransaction &tx);
|
||||
//uint64_t myGettxout(uint256 hash,int32_t n);
|
||||
bool myIsutxo_spentinmempool(uint256 txid,int32_t vout);
|
||||
int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout);
|
||||
bool mySendrawtransaction(std::string res);
|
||||
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
|
||||
|
||||
// CCcustom
|
||||
CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv);
|
||||
|
||||
// CCutils
|
||||
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk);
|
||||
CC *MakeCCcond1(uint8_t evalcode,CPubKey pk);
|
||||
CC* GetCryptoCondition(CScript const& scriptSig);
|
||||
bool IsCCInput(CScript const& scriptSig);
|
||||
int32_t unstringbits(char *buf,uint64_t bits);
|
||||
uint64_t stringbits(char *str);
|
||||
uint256 revuint256(uint256 txid);
|
||||
char *uint256_str(char *dest,uint256 txid);
|
||||
char *pubkey33_str(char *dest,uint8_t *pubkey33);
|
||||
uint256 Parseuint256(char *hexstr);
|
||||
CPubKey pubkey2pk(std::vector<uint8_t> pubkey);
|
||||
bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk);
|
||||
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);
|
||||
std::vector<uint8_t> Mypubkey();
|
||||
bool Myprivkey(uint8_t myprivkey[]);
|
||||
int64_t CCduration(int32_t &numblocks,uint256 txid);
|
||||
|
||||
// CCtx
|
||||
std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret);
|
||||
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr);
|
||||
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr);
|
||||
int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs);
|
||||
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout);
|
||||
|
||||
// curve25519 and sha256
|
||||
bits256 curve25519_shared(bits256 privkey,bits256 otherpub);
|
||||
bits256 curve25519_basepoint9();
|
||||
bits256 curve25519(bits256 mysecret,bits256 basepoint);
|
||||
void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
|
||||
bits256 bits256_doublesha256(char *deprecated,uint8_t *data,int32_t datalen);
|
||||
|
||||
#endif
|
||||
29
src/cc/CClotto.h
Normal file
29
src/cc/CClotto.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/******************************************************************************
|
||||
* 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_LOTTO_H
|
||||
#define CC_LOTTO_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
#define EVAL_LOTTO 0xe9
|
||||
|
||||
bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
|
||||
std::string LottoTicket(uint64_t txfee,int64_t numtickets);
|
||||
std::string LottoWinner(uint64_t txfee);
|
||||
|
||||
#endif
|
||||
34
src/cc/CCrewards.h
Normal file
34
src/cc/CCrewards.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/******************************************************************************
|
||||
* 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_REWARDS_H
|
||||
#define CC_REWARDS_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
#define EVAL_REWARDS 0xe5
|
||||
#define REWARDSCC_MAXAPR (COIN * 25)
|
||||
|
||||
bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
UniValue RewardsInfo(uint256 rewardid);
|
||||
UniValue RewardsList();
|
||||
|
||||
std::string RewardsCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t APR,int64_t minseconds,int64_t maxseconds,int64_t mindeposit);
|
||||
std::string RewardsAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount);
|
||||
std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount);
|
||||
std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid);
|
||||
|
||||
#endif
|
||||
333
src/cc/CCtx.cpp
Normal file
333
src/cc/CCtx.cpp
Normal file
@@ -0,0 +1,333 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
/*
|
||||
FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn.
|
||||
|
||||
This allows the contract transaction functions to create the appropriate vins and vouts and have FinalizeCCTx create a properly signed transaction.
|
||||
|
||||
By using -addressindex=1, it allows tracking of all the CC addresses
|
||||
*/
|
||||
|
||||
bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey)
|
||||
{
|
||||
#ifdef ENABLE_WALLET
|
||||
CTransaction txNewConst(mtx); SignatureData sigdata; const CKeyStore& keystore = *pwalletMain;
|
||||
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||
if ( ProduceSignature(TransactionSignatureCreator(&keystore,&txNewConst,vini,utxovalue,SIGHASH_ALL),scriptPubKey,sigdata,consensusBranchId) != 0 )
|
||||
{
|
||||
UpdateTransaction(mtx,vini,sigdata);
|
||||
return(true);
|
||||
} else fprintf(stderr,"signing error for SignTx vini.%d %.8f\n",vini,(double)utxovalue/COIN);
|
||||
#else
|
||||
return(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret)
|
||||
{
|
||||
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||
CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[64],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; CC *mycond=0,*othercond=0,*cond; CPubKey unspendablepk;
|
||||
n = mtx.vout.size();
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
if ( mtx.vout[i].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
normaloutputs += mtx.vout[i].nValue;
|
||||
totaloutputs += mtx.vout[i].nValue;
|
||||
}
|
||||
if ( (n= mtx.vin.size()) > 64 )
|
||||
{
|
||||
fprintf(stderr,"FinalizeCCTx: %d is too many vins\n",n);
|
||||
return("0");
|
||||
}
|
||||
Myprivkey(myprivkey);
|
||||
unspendablepk = GetUnspendable(cp,unspendablepriv);
|
||||
GetCCaddress(cp,myaddr,mypk);
|
||||
mycond = MakeCCcond1(cp->evalcode,mypk);
|
||||
GetCCaddress(cp,unspendable,unspendablepk);
|
||||
othercond = MakeCCcond1(cp->evalcode,unspendablepk);
|
||||
//fprintf(stderr,"myCCaddr.(%s) %p vs unspendable.(%s) %p\n",myaddr,mycond,unspendable,othercond);
|
||||
memset(utxovalues,0,sizeof(utxovalues));
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
utxovout = mtx.vin[i].prevout.n;
|
||||
utxovalues[i] = vintx.vout[utxovout].nValue;
|
||||
totalinputs += utxovalues[i];
|
||||
if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
{
|
||||
//fprintf(stderr,"vin.%d is normal %.8f\n",i,(double)utxovalues[i]/COIN);
|
||||
normalinputs += utxovalues[i];
|
||||
vinimask |= (1LL << i);
|
||||
}
|
||||
else
|
||||
{
|
||||
mask |= (1LL << i);
|
||||
}
|
||||
} else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
|
||||
}
|
||||
nmask = (1LL << n) - 1;
|
||||
if ( 0 && (mask & nmask) != (CCmask & nmask) )
|
||||
fprintf(stderr,"mask.%llx vs CCmask.%llx %llx %llx %llx\n",(long long)(mask & nmask),(long long)(CCmask & nmask),(long long)mask,(long long)CCmask,(long long)nmask);
|
||||
if ( totalinputs >= totaloutputs+2*txfee )
|
||||
{
|
||||
change = totalinputs - (totaloutputs+txfee);
|
||||
mtx.vout.push_back(CTxOut(change,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
}
|
||||
if ( opret.size() > 0 )
|
||||
mtx.vout.push_back(CTxOut(0,opret));
|
||||
PrecomputedTransactionData txdata(mtx);
|
||||
n = mtx.vin.size();
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
utxovout = mtx.vin[i].prevout.n;
|
||||
if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
{
|
||||
if ( SignTx(mtx,i,vintx.vout[utxovout].nValue,vintx.vout[utxovout].scriptPubKey) == 0 )
|
||||
fprintf(stderr,"signing error for vini.%d of %llx\n",i,(long long)vinimask);
|
||||
}
|
||||
else
|
||||
{
|
||||
Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey);
|
||||
//fprintf(stderr,"vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr);
|
||||
if ( strcmp(destaddr,myaddr) == 0 )
|
||||
{
|
||||
privkey = myprivkey;
|
||||
cond = mycond;
|
||||
//fprintf(stderr,"my CC addr.(%s)\n",myaddr);
|
||||
}
|
||||
else if ( strcmp(destaddr,unspendable) == 0 )
|
||||
{
|
||||
privkey = unspendablepriv;
|
||||
cond = othercond;
|
||||
//fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"vini.%d has unknown CC address.(%s)\n",i,destaddr);
|
||||
continue;
|
||||
}
|
||||
uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata);
|
||||
if ( cc_signTreeSecp256k1Msg32(cond,privkey,sighash.begin()) != 0 )
|
||||
{
|
||||
//int32_t z;
|
||||
//for (z=0; z<32; z++)
|
||||
// fprintf(stderr,"%02x",((uint8_t *)sighash.begin())[z]);
|
||||
//fprintf(stderr," sighash, ");
|
||||
//for (z=0; z<32; z++)
|
||||
// fprintf(stderr,"%02x",privkey[z]);
|
||||
//fprintf(stderr," signed with privkey\n");
|
||||
mtx.vin[i].scriptSig = CCSig(cond);
|
||||
}
|
||||
else fprintf(stderr,"vini.%d has CC signing error address.(%s)\n",i,destaddr);
|
||||
}
|
||||
} else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
|
||||
}
|
||||
if ( mycond != 0 )
|
||||
cc_free(mycond);
|
||||
if ( othercond != 0 )
|
||||
cc_free(othercond);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
addrstr.resize(n+1);
|
||||
ptr = (char *)addrstr.data();
|
||||
for (i=0; i<=n; i++)
|
||||
ptr[i] = coinaddr[i];
|
||||
CBitcoinAddress address(addrstr);
|
||||
if ( address.GetIndexKey(hashBytes, type) == 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++)
|
||||
{
|
||||
if ( GetAddressUnspent((*it).first, (*it).second, unspentOutputs) == 0 )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr)
|
||||
{
|
||||
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);
|
||||
addrstr.resize(n+1);
|
||||
ptr = (char *)addrstr.data();
|
||||
for (i=0; i<=n; i++)
|
||||
ptr[i] = coinaddr[i];
|
||||
CBitcoinAddress address(addrstr);
|
||||
if ( address.GetIndexKey(hashBytes, type) == 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++)
|
||||
{
|
||||
if ( GetAddressIndex((*it).first, (*it).second, addressIndex) == 0 )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
|
||||
{
|
||||
uint256 txid; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
if ( txid == utxotxid && utxovout == it->first.index )
|
||||
return(it->second.satoshis);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *belowp,struct CC_utxo utxos[],int32_t numunspents,int64_t value)
|
||||
{
|
||||
int32_t i,abovei,belowi; int64_t above,below,gap,atx_value;
|
||||
abovei = belowi = -1;
|
||||
for (above=below=i=0; i<numunspents; i++)
|
||||
{
|
||||
if ( (atx_value= utxos[i].nValue) <= 0 )
|
||||
continue;
|
||||
if ( atx_value == value )
|
||||
{
|
||||
*aboveip = *belowip = i;
|
||||
*abovep = *belowp = 0;
|
||||
return(i);
|
||||
}
|
||||
else if ( atx_value > value )
|
||||
{
|
||||
gap = (atx_value - value);
|
||||
if ( above == 0 || gap < above )
|
||||
{
|
||||
above = gap;
|
||||
abovei = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gap = (value - atx_value);
|
||||
if ( below == 0 || gap < below )
|
||||
{
|
||||
below = gap;
|
||||
belowi = i;
|
||||
}
|
||||
}
|
||||
//printf("value %.8f gap %.8f abovei.%d %.8f belowi.%d %.8f\n",dstr(value),dstr(gap),abovei,dstr(above),belowi,dstr(below));
|
||||
}
|
||||
*aboveip = abovei;
|
||||
*abovep = above;
|
||||
*belowip = belowi;
|
||||
*belowp = below;
|
||||
//printf("above.%d below.%d\n",abovei,belowi);
|
||||
if ( abovei >= 0 && belowi >= 0 )
|
||||
{
|
||||
if ( above < (below >> 1) )
|
||||
return(abovei);
|
||||
else return(belowi);
|
||||
}
|
||||
else if ( abovei >= 0 )
|
||||
return(abovei);
|
||||
else return(belowi);
|
||||
}
|
||||
|
||||
int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs)
|
||||
{
|
||||
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=1024; int64_t 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
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
assert(pwalletMain != NULL);
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
|
||||
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
{
|
||||
if ( out.fSpendable != 0 )
|
||||
{
|
||||
txid = out.tx->GetHash();
|
||||
vout = out.i;
|
||||
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
{
|
||||
if ( mtx.vin.size() > 0 )
|
||||
{
|
||||
for (i=0; i<mtx.vin.size(); i++)
|
||||
if ( txid == mtx.vin[i].prevout.hash && vout == mtx.vin[i].prevout.n )
|
||||
break;
|
||||
if ( i != mtx.vin.size() )
|
||||
continue;
|
||||
}
|
||||
if ( n > 0 )
|
||||
{
|
||||
for (i=0; i<n; i++)
|
||||
if ( txid == utxos[i].txid && vout == utxos[i].vout )
|
||||
break;
|
||||
if ( i != n )
|
||||
continue;
|
||||
}
|
||||
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
{
|
||||
up = &utxos[n++];
|
||||
up->txid = txid;
|
||||
up->nValue = out.tx->vout[out.i].nValue;
|
||||
up->vout = vout;
|
||||
if ( n >= maxutxos )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
remains = total;
|
||||
for (i=0; i<maxinputs && n>0; i++)
|
||||
{
|
||||
below = above = 0;
|
||||
abovei = belowi = -1;
|
||||
if ( CC_vinselect(&abovei,&above,&belowi,&below,utxos,n,remains) < 0 )
|
||||
{
|
||||
printf("error finding unspent i.%d of %d, %.8f vs %.8f\n",i,n,(double)remains/COIN,(double)total/COIN);
|
||||
free(utxos);
|
||||
return(0);
|
||||
}
|
||||
if ( belowi < 0 || abovei >= 0 )
|
||||
ind = abovei;
|
||||
else ind = belowi;
|
||||
if ( ind < 0 )
|
||||
{
|
||||
printf("error finding unspent i.%d of %d, %.8f vs %.8f, abovei.%d belowi.%d ind.%d\n",i,n,(double)remains/COIN,(double)total/COIN,abovei,belowi,ind);
|
||||
free(utxos);
|
||||
return(0);
|
||||
}
|
||||
up = &utxos[ind];
|
||||
mtx.vin.push_back(CTxIn(up->txid,up->vout,CScript()));
|
||||
totalinputs += up->nValue;
|
||||
remains -= up->nValue;
|
||||
utxos[ind] = utxos[--n];
|
||||
memset(&utxos[n],0,sizeof(utxos[n]));
|
||||
if ( totalinputs >= total || (i+1) >= maxinputs )
|
||||
break;
|
||||
}
|
||||
free(utxos);
|
||||
if ( totalinputs >= total )
|
||||
return(totalinputs);
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
318
src/cc/CCutils.cpp
Normal file
318
src/cc/CCutils.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
/*
|
||||
CCutils has low level functions that are universally useful for all contracts.
|
||||
*/
|
||||
|
||||
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeCCcond1(evalcode,pk);
|
||||
vout = CTxOut(nValue,CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
|
||||
CC *MakeCCcond1(uint8_t evalcode,CPubKey pk)
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk));
|
||||
CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
|
||||
CC *Sig = CCNewThreshold(1, pks);
|
||||
return CCNewThreshold(2, {condCC, Sig});
|
||||
}
|
||||
|
||||
CC* GetCryptoCondition(CScript const& scriptSig)
|
||||
{
|
||||
auto pc = scriptSig.begin();
|
||||
opcodetype opcode;
|
||||
std::vector<unsigned char> ffbin;
|
||||
if (scriptSig.GetOp(pc, opcode, ffbin))
|
||||
return cc_readFulfillmentBinary((uint8_t*)ffbin.data(), ffbin.size()-1);
|
||||
}
|
||||
|
||||
bool IsCCInput(CScript const& scriptSig)
|
||||
{
|
||||
CC *cond;
|
||||
if ( (cond= GetCryptoCondition(scriptSig)) == 0 )
|
||||
return false;
|
||||
cc_free(cond);
|
||||
return true;
|
||||
}
|
||||
|
||||
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(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 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);
|
||||
}
|
||||
|
||||
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
|
||||
{
|
||||
CTxDestination address; txnouttype whichType;
|
||||
if ( ExtractDestination(scriptPubKey,address) != 0 )
|
||||
{
|
||||
strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str());
|
||||
return(true);
|
||||
}
|
||||
fprintf(stderr,"ExtractDestination failed\n");
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
|
||||
{
|
||||
CC *payoutCond;
|
||||
destaddr[0] = 0;
|
||||
if ( pk.size() == 0 )
|
||||
pk = GetUnspendable(cp,0);
|
||||
if ( (payoutCond= MakeCCcond1(cp->evalcode,pk)) != 0 )
|
||||
{
|
||||
Getscriptaddress(destaddr,CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
}
|
||||
return(destaddr[0] != 0);
|
||||
}
|
||||
|
||||
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag )
|
||||
{
|
||||
fprintf(stderr,"constrain vout error isCC %d vs %d CCflag\n",vout.scriptPubKey.IsPayToCryptoCondition(),CCflag);
|
||||
return(false);
|
||||
}
|
||||
else if ( cmpaddr != 0 && (Getscriptaddress(destaddr,vout.scriptPubKey) == 0 || strcmp(destaddr,cmpaddr) != 0) )
|
||||
{
|
||||
fprintf(stderr,"constrain vout error addr %s vs %s\n",cmpaddr!=0?cmpaddr:"",destaddr!=0?destaddr:"");
|
||||
return(false);
|
||||
}
|
||||
else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || (
|
||||
{
|
||||
fprintf(stderr,"constrain vout error nValue %.8f vs %.8f\n",(double)nValue/COIN,(double)vout.nValue/COIN);
|
||||
return(false);
|
||||
}
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t numvins,int32_t preventCCvouts,int32_t numvouts)
|
||||
{
|
||||
int32_t i;
|
||||
if ( preventCCvins >= 0 )
|
||||
{
|
||||
for (i=preventCCvins; i<numvins; i++)
|
||||
{
|
||||
if ( IsCCInput(tx.vin[i].scriptSig) != 0 )
|
||||
return eval->Invalid("invalid CC vin");
|
||||
}
|
||||
}
|
||||
if ( preventCCvouts >= 0 )
|
||||
{
|
||||
for (i=preventCCvouts; i<numvouts; i++)
|
||||
{
|
||||
if ( tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
fprintf(stderr,"vout.%d is CC\n",i);
|
||||
return eval->Invalid("invalid CC vout");
|
||||
}
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Mypubkey()
|
||||
{
|
||||
extern uint8_t NOTARY_PUBKEY33[33];
|
||||
std::vector<uint8_t> pubkey; int32_t i; uint8_t *dest,*pubkey33;
|
||||
pubkey33 = NOTARY_PUBKEY33;
|
||||
pubkey.resize(33);
|
||||
dest = pubkey.data();
|
||||
for (i=0; i<33; i++)
|
||||
dest[i] = pubkey33[i];
|
||||
return(pubkey);
|
||||
}
|
||||
|
||||
bool Myprivkey(uint8_t myprivkey[])
|
||||
{
|
||||
char coinaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret;
|
||||
if ( Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG) != 0 )
|
||||
{
|
||||
n = (int32_t)strlen(coinaddr);
|
||||
strAddress.resize(n+1);
|
||||
dest = (char *)strAddress.data();
|
||||
for (i=0; i<n; i++)
|
||||
dest[i] = coinaddr[i];
|
||||
dest[i] = 0;
|
||||
if ( address.SetString(strAddress) != 0 && address.GetKeyID(keyID) != 0 )
|
||||
{
|
||||
#ifdef ENABLE_WALLET
|
||||
if ( pwalletMain->GetKey(keyID,vchSecret) != 0 )
|
||||
{
|
||||
memcpy(myprivkey,vchSecret.begin(),32);
|
||||
if ( 0 )
|
||||
{
|
||||
for (i=0; i<32; i++)
|
||||
fprintf(stderr,"0x%02x, ",myprivkey[i]);
|
||||
fprintf(stderr," found privkey!\n");
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"privkey for the -pubkey= address is not in the wallet, importprivkey!\n");
|
||||
return(false);
|
||||
}
|
||||
|
||||
CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv)
|
||||
{
|
||||
if ( unspendablepriv != 0 )
|
||||
memcpy(unspendablepriv,cp->CCpriv,32);
|
||||
return(pubkey2pk(ParseHex(cp->CChexstr)));
|
||||
}
|
||||
|
||||
bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn)
|
||||
{
|
||||
CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t height,i,n,from_mempool = 0; int64_t amount; std::vector<uint8_t> origpubkey;
|
||||
height = KOMODO_CONNECTING;
|
||||
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
|
||||
return(true);
|
||||
if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
|
||||
return eval->Invalid("CC are disabled or not active yet");
|
||||
if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
|
||||
{
|
||||
from_mempool = 1;
|
||||
height &= ((1<<30) - 1);
|
||||
}
|
||||
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();
|
||||
//if ( txid == cp->prevtxid )
|
||||
// return(true);
|
||||
//fprintf(stderr,"process CC %02x\n",cp->evalcode);
|
||||
if ( paramsNull.size() != 0 ) // Don't expect params
|
||||
return eval->Invalid("Cannot have params");
|
||||
else if ( ctx.vout.size() == 0 )
|
||||
return eval->Invalid("no-vouts");
|
||||
else if ( (*cp->validate)(cp,eval,ctx) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"done CC %02x\n",cp->evalcode);
|
||||
//cp->prevtxid = txid;
|
||||
return(true);
|
||||
}
|
||||
//fprintf(stderr,"invalid CC %02x\n",cp->evalcode);
|
||||
return(false);
|
||||
}
|
||||
|
||||
int64_t CCduration(int32_t &numblocks,uint256 txid)
|
||||
{
|
||||
CTransaction tx; uint256 hashBlock; uint32_t txheight,txtime=0; char str[65]; CBlockIndex *pindex; int64_t duration = 0;
|
||||
numblocks = 0;
|
||||
if ( myGetTransaction(txid,tx,hashBlock) == 0 )
|
||||
{
|
||||
fprintf(stderr,"CCduration cant find duration txid %s\n",uint256_str(str,txid));
|
||||
return(0);
|
||||
}
|
||||
else if ( hashBlock == zeroid )
|
||||
{
|
||||
fprintf(stderr,"CCduration no hashBlock for txid %s\n",uint256_str(str,txid));
|
||||
return(0);
|
||||
}
|
||||
else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txtime= pindex->nTime) == 0 || (txheight= pindex->nHeight) <= 0 )
|
||||
{
|
||||
fprintf(stderr,"CCduration no txtime %u or txheight.%d %p for txid %s\n",txtime,txheight,pindex,uint256_str(str,txid));
|
||||
return(0);
|
||||
}
|
||||
else if ( (pindex= chainActive.LastTip()) == 0 || pindex->nTime < txtime || pindex->nHeight <= txheight )
|
||||
{
|
||||
fprintf(stderr,"CCduration backwards timestamps %u %u for txid %s hts.(%d %d)\n",(uint32_t)pindex->nTime,txtime,uint256_str(str,txid),txheight,(int32_t)pindex->nHeight);
|
||||
return(0);
|
||||
}
|
||||
numblocks = (pindex->nHeight - txheight);
|
||||
duration = (pindex->nTime - txtime);
|
||||
fprintf(stderr,"duration %d (%u - %u) numblocks %d (%d - %d)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime,numblocks,pindex->nHeight,txheight);
|
||||
return(duration);
|
||||
}
|
||||
|
||||
379
src/cc/assets.cpp
Normal file
379
src/cc/assets.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCassets.h"
|
||||
|
||||
/*
|
||||
Assets can be created or transferred.
|
||||
|
||||
native coins are also locked in the EVAL_ASSETS address, so we need a strict rule on when utxo in the special address are native coins and when they are assets. The specific rule that must not be violated is that vout0 for 'b'/'B' funcid are native coins. All other utxo locked in the special address are assets.
|
||||
|
||||
To create an asset use CC EVAL_ASSETS to create a transaction where vout[0] funds the assets. Externally each satoshi can be interpreted to represent 1 asset, or 100 million satoshis for one asset with 8 decimals, and the other decimals in between. The interpretation of the number of decimals is left to the higher level usages.
|
||||
|
||||
Once created, the assetid is the txid of the create transaction and using the assetid/0 it can spend the assets to however many outputs it creates. The restriction is that the last output must be an opreturn with the assetid. The sum of all but the first output needs to add up to the total assetoshis input. The first output is ignored and used for change from txfee.
|
||||
|
||||
What this means is that vout 0 of the creation txid and vouts 1 ... n-2 for transfer vouts are assetoshi outputs.
|
||||
|
||||
There is a special type of transfer to an unspendable address, that locks the asset and creates an offer for all. The details specified in the opreturn. In order to be compatible with the signing restrictions, the "unspendable" address is actually an address whose privkey is known to all. Funds sent to this address can only be spent if the swap parameters are fulfilled, or if the original pubkey cancels the offer by spending it.
|
||||
|
||||
Types of transactions:
|
||||
create name:description -> txid for assetid
|
||||
transfer <pubkey> <assetid> -> [{address:amount}, ... ] // like withdraw api
|
||||
selloffer <pubkey> <txid/vout> <amount> -> cancel or fillsell -> mempool txid or rejected, might not confirm
|
||||
buyoffer <amount> <assetid> <required> -> cancelbuy or fillbuy -> mempool txid or rejected, might not confirm
|
||||
exchange <pubkey> <txid/vout> <required> <required assetid> -> cancel or fillexchange -> mempool txid or rejected, might not confirm
|
||||
|
||||
assetsaddress <pubkey> // all assets end up in a special address for each pubkey
|
||||
assetbalance <pubkey> <assetid>
|
||||
assetutxos <pubkey> <assetid>
|
||||
assetsbalances <pubkey>
|
||||
asks <assetid>
|
||||
bids <assetid>
|
||||
swaps <assetid>
|
||||
|
||||
valid CC output: create or transfer or buyoffer or selloffer or exchange or cancel or fill
|
||||
|
||||
create
|
||||
vin.0: normal input
|
||||
vout.0: issuance assetoshis to CC
|
||||
vout.1: tag sent to normal address of AssetsCCaddress
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['c'] [origpubkey] "<assetname>" "<description>"
|
||||
|
||||
transfer
|
||||
vin.0: normal input
|
||||
vin.1 .. vin.n-1: valid CC outputs
|
||||
vout.0 to n-2: assetoshis output to CC
|
||||
vout.n-2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid]
|
||||
|
||||
buyoffer:
|
||||
vins.*: normal inputs (bid + change)
|
||||
vout.0: amount of bid to unspendable
|
||||
vout.1: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
|
||||
|
||||
cancelbuy:
|
||||
vin.0: normal input
|
||||
vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey]
|
||||
vout.1: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['o'] [assetid]
|
||||
|
||||
fillbuy:
|
||||
vin.0: normal input
|
||||
vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue
|
||||
vout.0: remaining amount of bid to unspendable
|
||||
vout.1: vin.1 value to signer of vin.2
|
||||
vout.2: vin.2 assetoshis to original pubkey
|
||||
vout.3: CC output for assetoshis change (if any)
|
||||
vout.4: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey]
|
||||
|
||||
selloffer:
|
||||
vin.0: normal input
|
||||
vin.1+: valid CC output for sale
|
||||
vout.0: vin.1 assetoshis output to CC to unspendable
|
||||
vout.1: CC output for change (if any)
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey]
|
||||
|
||||
exchange:
|
||||
vin.0: normal input
|
||||
vin.1+: valid CC output
|
||||
vout.0: vin.1 assetoshis output to CC to unspendable
|
||||
vout.1: CC output for change (if any)
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey]
|
||||
|
||||
cancel:
|
||||
vin.0: normal input
|
||||
vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx
|
||||
vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
|
||||
vout.1: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
|
||||
|
||||
fillsell:
|
||||
vin.0: normal input
|
||||
vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0]
|
||||
vin.2+: normal output that satisfies selloffer (*tx.vin[2])->nValue
|
||||
vout.0: remaining assetoshis -> unspendable
|
||||
vout.1: vin.1 assetoshis to signer of vin.2 sellTx.vout[0].nValue -> any
|
||||
vout.2: vin.2 value to original pubkey [origpubkey]
|
||||
vout.3: CC asset for change (if any)
|
||||
vout.4: CC asset2 for change (if any) 'E' only
|
||||
vout.5: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey]
|
||||
|
||||
fillexchange:
|
||||
vin.0: normal input
|
||||
vin.1: unspendable.(vout.0 assetoshis from exchange) exchangeTx.vout[0]
|
||||
vin.2+: valid CC assetid2 output that satisfies exchange (*tx.vin[2])->nValue
|
||||
vout.0: remaining assetoshis -> unspendable
|
||||
vout.1: vin.1 assetoshis to signer of vin.2 exchangeTx.vout[0].nValue -> any
|
||||
vout.2: vin.2 assetoshis2 to original pubkey [origpubkey]
|
||||
vout.3: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey]
|
||||
*/
|
||||
|
||||
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
|
||||
{
|
||||
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; uint8_t funcid; char destaddr[64],origaddr[64],CCaddr[64];
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
outputs = inputs = 0;
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( (funcid= DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,remaining_price,origpubkey)) == 0 )
|
||||
return eval->Invalid("Invalid opreturn payload");
|
||||
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 )
|
||||
return eval->Invalid("illegal asset vin0");
|
||||
else if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else if ( funcid != 'c' )
|
||||
{
|
||||
if ( funcid == 't' )
|
||||
starti = 0;
|
||||
else starti = 1;
|
||||
if ( assetid == zero )
|
||||
return eval->Invalid("illegal assetid");
|
||||
else if ( AssetExactAmounts(cp,inputs,starti,outputs,eval,tx,assetid) == false )
|
||||
return eval->Invalid("asset inputs != outputs");
|
||||
}
|
||||
switch ( funcid )
|
||||
{
|
||||
case 'c': // create wont be called to be verified as it has no CC inputs
|
||||
//vin.0: normal input
|
||||
//vout.0: issuance assetoshis to CC
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['c'] [{"<assetname>":"<description>"}]
|
||||
return eval->Invalid("unexpected AssetValidate for createasset");
|
||||
break;
|
||||
|
||||
case 't': // transfer
|
||||
//vin.0: normal input
|
||||
//vin.1 .. vin.n-1: valid CC outputs
|
||||
//vout.0 to n-2: assetoshis output to CC
|
||||
//vout.n-2: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid]
|
||||
if ( inputs == 0 )
|
||||
return eval->Invalid("no asset inputs for transfer");
|
||||
fprintf(stderr,"transfer validated %.8f -> %.8f\n",(double)inputs/COIN,(double)outputs/COIN);
|
||||
break;
|
||||
|
||||
case 'b': // buyoffer
|
||||
//vins.*: normal inputs (bid + change)
|
||||
//vout.0: amount of bid to unspendable
|
||||
//vout.1: normal output for change (if any)
|
||||
// vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
|
||||
if ( remaining_price == 0 )
|
||||
return eval->Invalid("illegal null amount for buyoffer");
|
||||
else if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("invalid vout for buyoffer");
|
||||
preventCCvins = 1;
|
||||
preventCCvouts = 1;
|
||||
fprintf(stderr,"buy offer validated to destaddr.(%s)\n",cp->unspendableCCaddr);
|
||||
break;
|
||||
|
||||
case 'o': // cancelbuy
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
//vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey]
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['o']
|
||||
if ( (nValue= AssetValidateBuyvin(cp,eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( ConstrainVout(tx.vout[0],0,origaddr,nValue) == 0 )
|
||||
return eval->Invalid("invalid refund for cancelbuy");
|
||||
preventCCvins = 2;
|
||||
preventCCvouts = 0;
|
||||
fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origaddr);
|
||||
break;
|
||||
|
||||
case 'B': // fillbuy:
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
//vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue
|
||||
//vout.0: remaining amount of bid to unspendable
|
||||
//vout.1: vin.1 value to signer of vin.2
|
||||
//vout.2: vin.2 assetoshis to original pubkey
|
||||
//vout.3: CC output for assetoshis change (if any)
|
||||
//vout.4: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey]
|
||||
preventCCvouts = 4;
|
||||
if ( (nValue= AssetValidateBuyvin(cp,eval,totalunits,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( numvouts < 3 )
|
||||
return eval->Invalid("not enough vouts for fillbuy");
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for fillbuy");
|
||||
else
|
||||
{
|
||||
if ( nValue != tx.vout[0].nValue+tx.vout[1].nValue )
|
||||
return eval->Invalid("locked value doesnt match vout0+1 fillbuy");
|
||||
else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
return eval->Invalid("vout2 doesnt go to origpubkey fillbuy");
|
||||
else if ( inputs != tx.vout[2].nValue+tx.vout[3].nValue )
|
||||
return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy");
|
||||
}
|
||||
else if ( ConstrainVout(tx.vout[2],1,CCaddr,inputs) == 0 )
|
||||
return eval->Invalid("vout2 doesnt match inputs fillbuy");
|
||||
else if ( ConstrainVout(tx.vout[1],0,0,0) == 0 )
|
||||
return eval->Invalid("vout1 is CC for fillbuy");
|
||||
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,cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"fillbuy validated\n");
|
||||
break;
|
||||
case 'e': // selloffer
|
||||
break; // disable swaps
|
||||
case 's': // selloffer
|
||||
//vin.0: normal input
|
||||
//vin.1+: valid CC output for sale
|
||||
//vout.0: vin.1 assetoshis output to CC to unspendable
|
||||
//vout.1: CC output for change (if any)
|
||||
//vout.2: 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]
|
||||
preventCCvouts = 1;
|
||||
if ( remaining_price == 0 )
|
||||
return eval->Invalid("illegal null remaining_price for selloffer");
|
||||
if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
preventCCvouts++;
|
||||
if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer");
|
||||
else if ( tx.vout[0].nValue+tx.vout[1].nValue != inputs )
|
||||
return eval->Invalid("mismatched vout0+vout1 total for selloffer");
|
||||
} else if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,inputs) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer");
|
||||
//fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price);
|
||||
break;
|
||||
|
||||
case 'x': // cancel
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx
|
||||
//vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
|
||||
if ( (assetoshis= AssetValidateSellvin(cp,eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( ConstrainVout(tx.vout[0],1,CCaddr,assetoshis) == 0 )
|
||||
return eval->Invalid("invalid vout for cancel");
|
||||
preventCCvins = 2;
|
||||
preventCCvouts = 1;
|
||||
break;
|
||||
|
||||
case 'S': // fillsell
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0]
|
||||
//'S'.vin.2+: normal output that satisfies selloffer (*tx.vin[2])->nValue
|
||||
//vout.0: remaining assetoshis -> unspendable
|
||||
//vout.1: vin.1 assetoshis to signer of vin.2 sellTx.vout[0].nValue -> any
|
||||
//'S'.vout.2: vin.2 value to original pubkey [origpubkey]
|
||||
//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(cp,eval,totalunits,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( numvouts < 3 )
|
||||
return eval->Invalid("not enough vouts for fillask");
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for fillask");
|
||||
else
|
||||
{
|
||||
if ( assetoshis != tx.vout[0].nValue+tx.vout[1].nValue )
|
||||
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 )
|
||||
return eval->Invalid("normal vout1 for fillask");
|
||||
else if ( ConstrainVout(tx.vout[2],0,origaddr,0) == 0 )
|
||||
return eval->Invalid("normal vout1 for fillask");
|
||||
else if ( remaining_price != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fill");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"fill validated\n");
|
||||
break;
|
||||
case 'E': // fillexchange
|
||||
break; // disable asset swaps
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0]
|
||||
//vin.2+: valid CC assetid2 output that satisfies exchange (*tx.vin[2])->nValue
|
||||
//vout.0: remaining assetoshis -> unspendable
|
||||
//vout.1: vin.1 assetoshis to signer of vin.2 sellTx.vout[0].nValue -> any
|
||||
//vout.2: vin.2+ assetoshis2 to original pubkey [origpubkey]
|
||||
//vout.3: CC output for asset2 change (if any)
|
||||
//vout.3/4: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey]
|
||||
if ( AssetExactAmounts(cp,inputs,1,outputs,eval,tx,assetid2) == false )
|
||||
eval->Invalid("asset2 inputs != outputs");
|
||||
if ( (assetoshis= AssetValidateSellvin(cp,eval,totalunits,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( numvouts < 3 )
|
||||
return eval->Invalid("not enough vouts for fillex");
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for fillex");
|
||||
else
|
||||
{
|
||||
if ( assetoshis != tx.vout[0].nValue+tx.vout[1].nValue )
|
||||
return eval->Invalid("locked value doesnt match vout0+1 fillex");
|
||||
else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
return eval->Invalid("vout2 doesnt go to origpubkey fillex");
|
||||
else if ( inputs != tx.vout[2].nValue+tx.vout[3].nValue )
|
||||
{
|
||||
fprintf(stderr,"inputs %.8f != %.8f + %.8f\n",(double)inputs/COIN,(double)tx.vout[2].nValue/COIN,(double)tx.vout[3].nValue/COIN);
|
||||
return eval->Invalid("asset inputs doesnt match vout2+3 fillex");
|
||||
}
|
||||
}
|
||||
else if ( ConstrainVout(tx.vout[2],1,CCaddr,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");
|
||||
fprintf(stderr,"assets vout0 %llu, vin1 %llu, vout2 %llu -> orig, vout1 %llu, total %llu\n",(long long)tx.vout[0].nValue,(long long)assetoshis,(long long)tx.vout[2].nValue,(long long)tx.vout[1].nValue,(long long)totalunits);
|
||||
if ( ValidateSwapRemainder(remaining_price,tx.vout[0].nValue,assetoshis,tx.vout[1].nValue,tx.vout[2].nValue,totalunits) == false )
|
||||
return eval->Invalid("mismatched remainder for fillex");
|
||||
else if ( ConstrainVout(tx.vout[1],1,0,0) == 0 )
|
||||
return eval->Invalid("normal vout1 for fillex");
|
||||
else if ( remaining_price != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillex");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"fill validated\n");
|
||||
break;
|
||||
}
|
||||
return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
|
||||
}
|
||||
|
||||
|
||||
206
src/cc/auction.cpp
Normal file
206
src/cc/auction.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCauction.h"
|
||||
#include "../txmempool.h"
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
// start of consensus code
|
||||
|
||||
int64_t IsAuctionvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
|
||||
return(tx.vout[v].nValue);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool AuctionExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
|
||||
{
|
||||
static uint256 zerohash;
|
||||
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
//fprintf(stderr,"vini.%d\n",i);
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"vini.%d check mempool\n",i);
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("cant find vinTx");
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"vini.%d check hash and vout\n",i);
|
||||
if ( hashBlock == zerohash )
|
||||
return eval->Invalid("cant Auction from mempool");
|
||||
if ( (assetoshis= IsAuctionvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<numvouts; i++)
|
||||
{
|
||||
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
|
||||
if ( (assetoshis= IsAuctionvout(cp,tx,i)) != 0 )
|
||||
outputs += assetoshis;
|
||||
}
|
||||
if ( inputs != outputs+COIN+txfee )
|
||||
{
|
||||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
|
||||
return eval->Invalid("mismatched inputs != outputs + COIN + txfee");
|
||||
}
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
return(false); // reject any auction CC for now
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"check vins\n");
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
|
||||
{
|
||||
fprintf(stderr,"Auctionget invalid vini\n");
|
||||
return eval->Invalid("illegal normal vini");
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"check amounts\n");
|
||||
if ( AuctionExactAmounts(cp,eval,tx,1,10000) == false )
|
||||
{
|
||||
fprintf(stderr,"Auctionget invalid amount\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
preventCCvouts = 1;
|
||||
if ( IsAuctionvout(cp,tx,0) != 0 )
|
||||
{
|
||||
preventCCvouts++;
|
||||
i = 1;
|
||||
} else i = 0;
|
||||
if ( tx.vout[i].nValue != COIN )
|
||||
return eval->Invalid("invalid Auction output");
|
||||
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
|
||||
if ( retval != 0 )
|
||||
fprintf(stderr,"Auctionget validated\n");
|
||||
else fprintf(stderr,"Auctionget invalid\n");
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of consensus code
|
||||
|
||||
// helper functions for rpc calls in rpcwallet.cpp
|
||||
|
||||
int64_t AddAuctionInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
|
||||
{
|
||||
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);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
// prevent dup
|
||||
if ( it->second.satoshis < 1000000 )
|
||||
continue;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( (nValue= IsAuctionvout(cp,vintx,(int32_t)it->first.index)) > 0 )
|
||||
{
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
mtx.vin.push_back(CTxIn(txid,(int32_t)it->first.index,CScript()));
|
||||
nValue = it->second.satoshis;
|
||||
totalinputs += nValue;
|
||||
n++;
|
||||
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
std::string AuctionBid(uint64_t txfee,uint256 itemhash,int64_t amount)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Auctionpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_AUCTION);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
Auctionpk = GetUnspendable(cp,0);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( (inputs= AddAuctionInputs(cp,mtx,Auctionpk,nValue+txfee,60)) > 0 )
|
||||
{
|
||||
if ( inputs > nValue )
|
||||
CCchange = (inputs - nValue - txfee);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_AUCTION,CCchange,Auctionpk));
|
||||
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret));
|
||||
} else fprintf(stderr,"cant find Auction inputs\n");
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string AuctionDeliver(uint64_t txfee,uint256 itemhash,uint256 bidtxid)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Auctionpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_AUCTION);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
Auctionpk = GetUnspendable(cp,0);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( (inputs= AddAuctionInputs(cp,mtx,Auctionpk,nValue+txfee,60)) > 0 )
|
||||
{
|
||||
if ( inputs > nValue )
|
||||
CCchange = (inputs - nValue - txfee);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_AUCTION,CCchange,Auctionpk));
|
||||
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret));
|
||||
} else fprintf(stderr,"cant find Auction inputs\n");
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string AuctionPost(uint64_t txfee,uint256 itemhash,int64_t minbid,char *title,char *description)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Auctionpk; int64_t funds = 0; CScript opret; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_AUCTION);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
Auctionpk = GetUnspendable(cp,0);
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_AUCTION,funds,Auctionpk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "main.h"
|
||||
#include "chain.h"
|
||||
#include "streams.h"
|
||||
#include "script/cc.h"
|
||||
#include "cc/eval.h"
|
||||
#include "cc/betprotocol.h"
|
||||
#include "cc/eval.h"
|
||||
#include "cc/utils.h"
|
||||
#include "primitives/transaction.h"
|
||||
|
||||
|
||||
@@ -137,3 +156,146 @@ bool GetOpReturnHash(CScript script, uint256 &hash)
|
||||
hash = uint256(vHash);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Crypto-Condition EVAL method that verifies a payout against a transaction
|
||||
* notarised on another chain.
|
||||
*
|
||||
* IN: params - condition params
|
||||
* IN: importTx - Payout transaction on value chain (KMD)
|
||||
* IN: nIn - index of input of stake
|
||||
*
|
||||
* importTx: Spends stakeTx with payouts from asset chain
|
||||
*
|
||||
* in 0: Spends Stake TX and contains ImportPayout CC
|
||||
* out 0: OP_RETURN MomProof, disputeTx
|
||||
* out 1-: arbitrary payouts
|
||||
*
|
||||
* disputeTx: Spends sessionTx.0 (opener on asset chain)
|
||||
*
|
||||
* in 0: spends sessionTx.0
|
||||
* in 1-: anything
|
||||
* out 0: OP_RETURN hash of payouts
|
||||
* out 1-: anything
|
||||
*/
|
||||
bool Eval::ImportPayout(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
|
||||
{
|
||||
if (importTx.vout.size() == 0) return Invalid("no-vouts");
|
||||
|
||||
// load data from vout[0]
|
||||
MoMProof proof;
|
||||
CTransaction disputeTx;
|
||||
{
|
||||
std::vector<unsigned char> vopret;
|
||||
GetOpReturnData(importTx.vout[0].scriptPubKey, vopret);
|
||||
if (!E_UNMARSHAL(vopret, ss >> proof; ss >> disputeTx))
|
||||
return Invalid("invalid-payload");
|
||||
}
|
||||
|
||||
// Check disputeTx.0 shows correct payouts
|
||||
{
|
||||
uint256 givenPayoutsHash;
|
||||
GetOpReturnHash(disputeTx.vout[0].scriptPubKey, givenPayoutsHash);
|
||||
std::vector<CTxOut> payouts(importTx.vout.begin() + 1, importTx.vout.end());
|
||||
if (givenPayoutsHash != SerializeHash(payouts))
|
||||
return Invalid("wrong-payouts");
|
||||
}
|
||||
|
||||
// Check disputeTx spends sessionTx.0
|
||||
// condition ImportPayout params is session ID from other chain
|
||||
{
|
||||
uint256 sessionHash;
|
||||
if (!E_UNMARSHAL(params, ss >> sessionHash))
|
||||
return Invalid("malformed-params");
|
||||
if (disputeTx.vin[0].prevout != COutPoint(sessionHash, 0))
|
||||
return Invalid("wrong-session");
|
||||
}
|
||||
|
||||
// Check disputeTx solves momproof from vout[0]
|
||||
{
|
||||
NotarisationData data(0);
|
||||
if (!GetNotarisationData(proof.notarisationHash, data))
|
||||
return Invalid("coudnt-load-mom");
|
||||
|
||||
if (data.MoM != proof.branch.Exec(disputeTx.GetHash()))
|
||||
return Invalid("mom-check-fail");
|
||||
}
|
||||
|
||||
return Valid();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Crypto-Condition EVAL method that resolves a dispute of a session
|
||||
*
|
||||
* IN: vm - AppVM virtual machine to verify states
|
||||
* IN: params - condition params
|
||||
* IN: disputeTx - transaction attempting to resolve dispute
|
||||
* IN: nIn - index of input of dispute tx
|
||||
*
|
||||
* disputeTx: attempt to resolve a dispute
|
||||
*
|
||||
* in 0: Spends Session TX first output, reveals DisputeHeader
|
||||
* out 0: OP_RETURN hash of payouts
|
||||
*/
|
||||
bool Eval::DisputePayout(AppVM &vm, std::vector<uint8_t> params, const CTransaction &disputeTx, unsigned int nIn)
|
||||
{
|
||||
if (disputeTx.vout.size() == 0) return Invalid("no-vouts");
|
||||
|
||||
// get payouts hash
|
||||
uint256 payoutHash;
|
||||
if (!GetOpReturnHash(disputeTx.vout[0].scriptPubKey, payoutHash))
|
||||
return Invalid("invalid-payout-hash");
|
||||
|
||||
// load params
|
||||
uint16_t waitBlocks;
|
||||
std::vector<uint8_t> vmParams;
|
||||
if (!E_UNMARSHAL(params, ss >> VARINT(waitBlocks); ss >> vmParams))
|
||||
return Invalid("malformed-params");
|
||||
|
||||
// ensure that enough time has passed
|
||||
{
|
||||
CTransaction sessionTx;
|
||||
CBlockIndex sessionBlock;
|
||||
|
||||
// if unconformed its too soon
|
||||
if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock))
|
||||
return Error("couldnt-get-parent");
|
||||
|
||||
if (GetCurrentHeight() < sessionBlock.nHeight + waitBlocks)
|
||||
return Invalid("dispute-too-soon"); // Not yet
|
||||
}
|
||||
|
||||
// get spends
|
||||
std::vector<CTransaction> spends;
|
||||
if (!GetSpendsConfirmed(disputeTx.vin[0].prevout.hash, spends))
|
||||
return Error("couldnt-get-spends");
|
||||
|
||||
// verify result from VM
|
||||
int maxLength = -1;
|
||||
uint256 bestPayout;
|
||||
for (int i=1; i<spends.size(); i++)
|
||||
{
|
||||
std::vector<unsigned char> vmState;
|
||||
if (spends[i].vout.size() == 0) continue;
|
||||
if (!GetOpReturnData(spends[i].vout[0].scriptPubKey, vmState)) continue;
|
||||
auto out = vm.evaluate(vmParams, vmState);
|
||||
uint256 resultHash = SerializeHash(out.second);
|
||||
if (out.first > maxLength) {
|
||||
maxLength = out.first;
|
||||
bestPayout = resultHash;
|
||||
}
|
||||
// The below means that if for any reason there is a draw, the first dispute wins
|
||||
else if (out.first == maxLength) {
|
||||
if (bestPayout != payoutHash) {
|
||||
fprintf(stderr, "WARNING: VM has multiple solutions of same length\n");
|
||||
bestPayout = resultHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxLength == -1) return Invalid("no-evidence");
|
||||
|
||||
return bestPayout == payoutHash ? Valid() : Invalid("wrong-payout");
|
||||
}
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
/******************************************************************************
|
||||
* 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 BETPROTOCOL_H
|
||||
#define BETPROTOCOL_H
|
||||
|
||||
#include "cc/eval.h"
|
||||
#include "pubkey.h"
|
||||
#include "primitives/block.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "cryptoconditions/include/cryptoconditions.h"
|
||||
|
||||
@@ -11,25 +25,18 @@
|
||||
class MoMProof
|
||||
{
|
||||
public:
|
||||
int nIndex;
|
||||
std::vector<uint256> branch;
|
||||
MerkleBranch branch;
|
||||
uint256 notarisationHash;
|
||||
|
||||
MoMProof() {}
|
||||
MoMProof(int i, std::vector<uint256> b, uint256 n) : notarisationHash(n), nIndex(i), branch(b) {}
|
||||
uint256 Exec(uint256 hash) const { return CBlock::CheckMerkleBranch(hash, branch, nIndex); }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(VARINT(nIndex));
|
||||
READWRITE(branch);
|
||||
READWRITE(notarisationHash);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class BetProtocol
|
||||
{
|
||||
protected:
|
||||
|
||||
1192
src/cc/dice.cpp
Normal file
1192
src/cc/dice.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,84 +0,0 @@
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "chain.h"
|
||||
#include "version.h"
|
||||
#include "script/cc.h"
|
||||
#include "cc/eval.h"
|
||||
#include "cc/betprotocol.h"
|
||||
#include "primitives/transaction.h"
|
||||
|
||||
|
||||
/*
|
||||
* Crypto-Condition EVAL method that resolves a dispute of a session
|
||||
*
|
||||
* IN: vm - AppVM virtual machine to verify states
|
||||
* IN: params - condition params
|
||||
* IN: disputeTx - transaction attempting to resolve dispute
|
||||
* IN: nIn - index of input of dispute tx
|
||||
*
|
||||
* disputeTx: attempt to resolve a dispute
|
||||
*
|
||||
* in 0: Spends Session TX first output, reveals DisputeHeader
|
||||
* out 0: OP_RETURN hash of payouts
|
||||
*/
|
||||
bool Eval::DisputePayout(AppVM &vm, std::vector<uint8_t> params, const CTransaction &disputeTx, unsigned int nIn)
|
||||
{
|
||||
if (disputeTx.vout.size() == 0) return Invalid("no-vouts");
|
||||
|
||||
// get payouts hash
|
||||
uint256 payoutHash;
|
||||
if (!GetOpReturnHash(disputeTx.vout[0].scriptPubKey, payoutHash))
|
||||
return Invalid("invalid-payout-hash");
|
||||
|
||||
// load params
|
||||
uint16_t waitBlocks;
|
||||
std::vector<uint8_t> vmParams;
|
||||
if (!E_UNMARSHAL(params, ss >> VARINT(waitBlocks); ss >> vmParams))
|
||||
return Invalid("malformed-params");
|
||||
|
||||
// ensure that enough time has passed
|
||||
{
|
||||
CTransaction sessionTx;
|
||||
CBlockIndex sessionBlock;
|
||||
|
||||
// if unconformed its too soon
|
||||
if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock))
|
||||
return Error("couldnt-get-parent");
|
||||
|
||||
if (GetCurrentHeight() < sessionBlock.nHeight + waitBlocks)
|
||||
return Invalid("dispute-too-soon"); // Not yet
|
||||
}
|
||||
|
||||
// get spends
|
||||
std::vector<CTransaction> spends;
|
||||
if (!GetSpendsConfirmed(disputeTx.vin[0].prevout.hash, spends))
|
||||
return Error("couldnt-get-spends");
|
||||
|
||||
// verify result from VM
|
||||
int maxLength = -1;
|
||||
uint256 bestPayout;
|
||||
for (int i=1; i<spends.size(); i++)
|
||||
{
|
||||
std::vector<unsigned char> vmState;
|
||||
if (spends[i].vout.size() == 0) continue;
|
||||
if (!GetOpReturnData(spends[i].vout[0].scriptPubKey, vmState)) continue;
|
||||
auto out = vm.evaluate(vmParams, vmState);
|
||||
uint256 resultHash = SerializeHash(out.second);
|
||||
if (out.first > maxLength) {
|
||||
maxLength = out.first;
|
||||
bestPayout = resultHash;
|
||||
}
|
||||
// The below means that if for any reason there is a draw, the first dispute wins
|
||||
else if (out.first == maxLength) {
|
||||
if (bestPayout != payoutHash) {
|
||||
fprintf(stderr, "WARNING: VM has multiple solutions of same length\n");
|
||||
bestPayout = resultHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxLength == -1) return Invalid("no-evidence");
|
||||
|
||||
return bestPayout == payoutHash ? Valid() : Invalid("wrong-payout");
|
||||
}
|
||||
156
src/cc/eval.cpp
156
src/cc/eval.cpp
@@ -1,24 +1,44 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
#include "primitives/block.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "script/cc.h"
|
||||
#include "cc/eval.h"
|
||||
#include "cc/utils.h"
|
||||
#include "cc/CCinclude.h"
|
||||
#include "main.h"
|
||||
#include "chain.h"
|
||||
#include "core_io.h"
|
||||
#include "crosschain.h"
|
||||
|
||||
|
||||
Eval* EVAL_TEST = 0;
|
||||
|
||||
struct CCcontract_info CCinfos[0x100];
|
||||
extern pthread_mutex_t KOMODO_CC_mutex;
|
||||
|
||||
bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
|
||||
{
|
||||
Eval eval_;
|
||||
Eval *eval = EVAL_TEST;
|
||||
if (!eval) eval = &eval_;
|
||||
|
||||
EvalRef eval;
|
||||
pthread_mutex_lock(&KOMODO_CC_mutex);
|
||||
bool out = eval->Dispatch(cond, tx, nIn);
|
||||
pthread_mutex_unlock(&KOMODO_CC_mutex);
|
||||
//fprintf(stderr,"out %d vs %d isValid\n",(int32_t)out,(int32_t)eval->state.IsValid());
|
||||
assert(eval->state.IsValid() == out);
|
||||
|
||||
if (eval->state.IsValid()) return true;
|
||||
@@ -39,17 +59,33 @@ bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
|
||||
*/
|
||||
bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
|
||||
{
|
||||
struct CCcontract_info *cp;
|
||||
if (cond->codeLength == 0)
|
||||
return Invalid("empty-eval");
|
||||
|
||||
uint8_t ecode = cond->code[0];
|
||||
std::vector<uint8_t> vparams(cond->code+1, cond->code+cond->codeLength);
|
||||
|
||||
if (ecode == EVAL_IMPORTPAYOUT) {
|
||||
return ImportPayout(vparams, txTo, nIn);
|
||||
cp = &CCinfos[(int32_t)ecode];
|
||||
if ( cp->didinit == 0 )
|
||||
{
|
||||
CCinit(cp,ecode);
|
||||
cp->didinit = 1;
|
||||
}
|
||||
|
||||
return Invalid("invalid-code");
|
||||
std::vector<uint8_t> vparams(cond->code+1, cond->code+cond->codeLength);
|
||||
switch ( ecode )
|
||||
{
|
||||
case EVAL_IMPORTPAYOUT:
|
||||
return ImportPayout(vparams, txTo, nIn);
|
||||
break;
|
||||
|
||||
case EVAL_IMPORTCOIN:
|
||||
return ImportCoin(vparams, txTo, nIn);
|
||||
break;
|
||||
|
||||
default:
|
||||
return(ProcessCC(cp,this, vparams, txTo, nIn));
|
||||
break;
|
||||
}
|
||||
return Invalid("invalid-code, dont forget to add EVAL_NEWCC to Eval::Dispatch");
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +98,10 @@ bool Eval::GetSpendsConfirmed(uint256 hash, std::vector<CTransaction> &spends) c
|
||||
|
||||
bool Eval::GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const
|
||||
{
|
||||
bool fAllowSlow = false; // Don't allow slow
|
||||
return GetTransaction(hash, txOut, hashBlock, fAllowSlow);
|
||||
// there is a LOCK(cs_main) in the normal GetTransaction(), which leads to deadlocks
|
||||
//bool fAllowSlow = false; // Don't allow slow
|
||||
//return GetTransaction(hash, txOut, hashBlock, fAllowSlow);
|
||||
return myGetTransaction(hash, txOut,hashBlock);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +121,6 @@ unsigned int Eval::GetCurrentHeight() const
|
||||
return chainActive.Height();
|
||||
}
|
||||
|
||||
|
||||
bool Eval::GetBlock(uint256 hash, CBlockIndex& blockIdx) const
|
||||
{
|
||||
auto r = mapBlockIndex.find(hash);
|
||||
@@ -95,7 +132,6 @@ bool Eval::GetBlock(uint256 hash, CBlockIndex& blockIdx) const
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
extern int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||
|
||||
|
||||
@@ -144,7 +180,7 @@ bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t t
|
||||
|
||||
|
||||
/*
|
||||
* Get MoM from a notarisation tx hash
|
||||
* Get MoM from a notarisation tx hash (on KMD)
|
||||
*/
|
||||
bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data) const
|
||||
{
|
||||
@@ -152,54 +188,84 @@ bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data)
|
||||
CBlockIndex block;
|
||||
if (!GetTxConfirmed(notaryHash, notarisationTx, block)) return false;
|
||||
if (!CheckNotaryInputs(notarisationTx, block.nHeight, block.nTime)) return false;
|
||||
if (notarisationTx.vout.size() < 2) return false;
|
||||
if (!data.Parse(notarisationTx.vout[1].scriptPubKey)) return false;
|
||||
if (!ParseNotarisationOpReturn(notarisationTx, data)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get MoMoM corresponding to a notarisation tx hash (on assetchain)
|
||||
*/
|
||||
bool Eval::GetProofRoot(uint256 kmdNotarisationHash, uint256 &momom) const
|
||||
{
|
||||
std::pair<uint256,NotarisationData> out;
|
||||
if (!GetNextBacknotarisation(kmdNotarisationHash, out)) return false;
|
||||
momom = out.second.MoMoM;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Eval::GetAssetchainsCC() const
|
||||
{
|
||||
return ASSETCHAINS_CC;
|
||||
}
|
||||
|
||||
|
||||
std::string Eval::GetAssetchainsSymbol() const
|
||||
{
|
||||
return std::string(ASSETCHAINS_SYMBOL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Notarisation data, ie, OP_RETURN payload in notarisation transactions
|
||||
*/
|
||||
extern char ASSETCHAINS_SYMBOL[16];
|
||||
|
||||
bool NotarisationData::Parse(const CScript scriptPK)
|
||||
bool ParseNotarisationOpReturn(const CTransaction &tx, NotarisationData &data)
|
||||
{
|
||||
*this = NotarisationData();
|
||||
|
||||
if (tx.vout.size() < 2) return false;
|
||||
std::vector<unsigned char> vdata;
|
||||
if (!GetOpReturnData(scriptPK, vdata)) return false;
|
||||
|
||||
CDataStream ss(vdata, SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
try {
|
||||
ss >> blockHash;
|
||||
ss >> height;
|
||||
if (ASSETCHAINS_SYMBOL[0])
|
||||
ss >> txHash;
|
||||
|
||||
char *nullPos = (char*) memchr(&ss[0], 0, ss.size());
|
||||
if (!nullPos) return false;
|
||||
ss.read(symbol, nullPos-&ss[0]+1);
|
||||
|
||||
if (ss.size() < 36) return false;
|
||||
ss >> MoM;
|
||||
ss >> MoMDepth;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (!GetOpReturnData(tx.vout[1].scriptPubKey, vdata)) return false;
|
||||
bool out = E_UNMARSHAL(vdata, ss >> data);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
|
||||
std::string EvalToStr(EvalCode c)
|
||||
{
|
||||
FOREACH_EVAL(EVAL_GENERATE_STRING);
|
||||
char s[10];
|
||||
sprintf(s, "0x%x", c);
|
||||
return std::string(s);
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint256 SafeCheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
|
||||
{
|
||||
if (nIndex == -1)
|
||||
return uint256();
|
||||
for (auto it(vMerkleBranch.begin()); it != vMerkleBranch.end(); ++it)
|
||||
{
|
||||
if (nIndex & 1) {
|
||||
if (*it == hash) {
|
||||
// non canonical. hash may be equal to node but never on the right.
|
||||
return uint256();
|
||||
}
|
||||
hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
|
||||
}
|
||||
else
|
||||
hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
|
||||
nIndex >>= 1;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
uint256 GetMerkleRoot(const std::vector<uint256>& vLeaves)
|
||||
{
|
||||
bool fMutated;
|
||||
std::vector<uint256> vMerkleTree;
|
||||
return BuildMerkleTree(&fMutated, vLeaves, vMerkleTree);
|
||||
}
|
||||
|
||||
203
src/cc/eval.h
203
src/cc/eval.h
@@ -1,14 +1,31 @@
|
||||
/******************************************************************************
|
||||
* 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_EVAL_H
|
||||
#define CC_EVAL_H
|
||||
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
#include "cc/utils.h"
|
||||
#include "chain.h"
|
||||
#include "streams.h"
|
||||
#include "version.h"
|
||||
#include "consensus/validation.h"
|
||||
#include "primitives/transaction.h"
|
||||
|
||||
#define KOMODO_FIRSTFUNGIBLEID 100
|
||||
|
||||
/*
|
||||
* Eval codes
|
||||
@@ -20,8 +37,17 @@
|
||||
* a possible code is EVAL_BITCOIN_SCRIPT, where the entire binary
|
||||
* after the code is interpreted as a bitcoin script.
|
||||
*/
|
||||
#define FOREACH_EVAL(EVAL) \
|
||||
EVAL(EVAL_IMPORTPAYOUT, 0xe1)
|
||||
#define FOREACH_EVAL(EVAL) \
|
||||
EVAL(EVAL_IMPORTPAYOUT, 0xe1) \
|
||||
EVAL(EVAL_IMPORTCOIN, 0xe2) \
|
||||
EVAL(EVAL_ASSETS, 0xe3) \
|
||||
EVAL(EVAL_FAUCET, 0xe4) \
|
||||
EVAL(EVAL_REWARDS, 0xe5) \
|
||||
EVAL(EVAL_DICE, 0xe6) \
|
||||
EVAL(EVAL_FSM, 0xe7) \
|
||||
EVAL(EVAL_AUCTION, 0xe8) \
|
||||
EVAL(EVAL_LOTTO, 0xe9)
|
||||
|
||||
|
||||
typedef uint8_t EvalCode;
|
||||
|
||||
@@ -54,6 +80,11 @@ public:
|
||||
*/
|
||||
bool ImportPayout(std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn);
|
||||
|
||||
/*
|
||||
* Import coin from another chain with same symbol
|
||||
*/
|
||||
bool ImportCoin(std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn);
|
||||
|
||||
/*
|
||||
* IO functions
|
||||
*/
|
||||
@@ -64,10 +95,30 @@ public:
|
||||
virtual bool GetBlock(uint256 hash, CBlockIndex& blockIdx) const;
|
||||
virtual int32_t GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t timestamp) const;
|
||||
virtual bool GetNotarisationData(uint256 notarisationHash, NotarisationData &data) const;
|
||||
virtual bool GetProofRoot(uint256 kmdNotarisationHash, uint256 &momom) const;
|
||||
virtual bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const;
|
||||
virtual uint32_t GetAssetchainsCC() const;
|
||||
virtual std::string GetAssetchainsSymbol() const;
|
||||
};
|
||||
|
||||
|
||||
extern Eval* EVAL_TEST;
|
||||
|
||||
|
||||
/*
|
||||
* Get a pointer to an Eval to use
|
||||
*/
|
||||
typedef std::unique_ptr<Eval,void(*)(Eval*)> EvalRef_;
|
||||
class EvalRef : public EvalRef_
|
||||
{
|
||||
public:
|
||||
EvalRef() : EvalRef_(
|
||||
EVAL_TEST ? EVAL_TEST : new Eval(),
|
||||
[](Eval* e){if (e!=EVAL_TEST) delete e;}) { }
|
||||
};
|
||||
|
||||
|
||||
|
||||
bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn);
|
||||
|
||||
|
||||
@@ -88,22 +139,92 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Data from notarisation OP_RETURN
|
||||
*/
|
||||
class NotarisationData {
|
||||
public:
|
||||
uint256 blockHash;
|
||||
uint32_t height;
|
||||
uint256 txHash; // Only get this guy in asset chains not in KMD
|
||||
char symbol[64];
|
||||
uint256 MoM;
|
||||
uint32_t MoMDepth;
|
||||
extern char ASSETCHAINS_SYMBOL[65];
|
||||
|
||||
bool Parse(CScript scriptPubKey);
|
||||
|
||||
/*
|
||||
* Data from notarisation OP_RETURN from chain being notarised
|
||||
*/
|
||||
class NotarisationData
|
||||
{
|
||||
public:
|
||||
int IsBackNotarisation = 0;
|
||||
uint256 blockHash = uint256();
|
||||
uint32_t height = 0;
|
||||
uint256 txHash = uint256();
|
||||
char symbol[64];
|
||||
uint256 MoM = uint256();
|
||||
uint16_t MoMDepth = 0;
|
||||
uint16_t ccId = 0;
|
||||
uint256 MoMoM = uint256();
|
||||
uint32_t MoMoMDepth = 0;
|
||||
|
||||
NotarisationData(int IsBack=2) : IsBackNotarisation(IsBack) {
|
||||
symbol[0] = '\0';
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
|
||||
bool IsBack = IsBackNotarisation;
|
||||
if (2 == IsBackNotarisation) IsBack = DetectBackNotarisation(s, ser_action);
|
||||
|
||||
READWRITE(blockHash);
|
||||
READWRITE(height);
|
||||
if (IsBack)
|
||||
READWRITE(txHash);
|
||||
SerSymbol(s, ser_action);
|
||||
if (s.size() == 0) return;
|
||||
READWRITE(MoM);
|
||||
READWRITE(MoMDepth);
|
||||
READWRITE(ccId);
|
||||
if (s.size() == 0) return;
|
||||
if (IsBack) {
|
||||
READWRITE(MoMoM);
|
||||
READWRITE(MoMoMDepth);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void SerSymbol(Stream& s, CSerActionSerialize act)
|
||||
{
|
||||
s.write(symbol, strlen(symbol)+1);
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void SerSymbol(Stream& s, CSerActionUnserialize act)
|
||||
{
|
||||
size_t readlen = std::min(sizeof(symbol), s.size());
|
||||
char *nullPos = (char*) memchr(&s[0], 0, readlen);
|
||||
if (!nullPos)
|
||||
throw std::ios_base::failure("couldn't parse symbol");
|
||||
s.read(symbol, nullPos-&s[0]+1);
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
bool DetectBackNotarisation(Stream& s, CSerActionUnserialize act)
|
||||
{
|
||||
if (ASSETCHAINS_SYMBOL[0]) return 1;
|
||||
if (s.size() >= 72) {
|
||||
if (strcmp("BTC", &s[68]) == 0) return 1;
|
||||
if (strcmp("KMD", &s[68]) == 0) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
bool DetectBackNotarisation(Stream& s, CSerActionSerialize act)
|
||||
{
|
||||
return !txHash.IsNull();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool ParseNotarisationOpReturn(const CTransaction &tx, NotarisationData &data);
|
||||
|
||||
|
||||
/*
|
||||
* Eval code utilities.
|
||||
*/
|
||||
@@ -116,28 +237,44 @@ std::string EvalToStr(EvalCode c);
|
||||
|
||||
|
||||
/*
|
||||
* Serialisation boilerplate
|
||||
* Merkle stuff
|
||||
*/
|
||||
#define E_MARSHAL(body) SerializeF([&] (CDataStream &ss) {body;})
|
||||
template <class T>
|
||||
std::vector<uint8_t> SerializeF(const T f)
|
||||
{
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
f(ss);
|
||||
return std::vector<unsigned char>(ss.begin(), ss.end());
|
||||
}
|
||||
uint256 SafeCheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex);
|
||||
|
||||
#define E_UNMARSHAL(params, body) DeserializeF(params, [&] (CDataStream &ss) {body;})
|
||||
template <class T>
|
||||
bool DeserializeF(const std::vector<unsigned char> vIn, T f)
|
||||
|
||||
class MerkleBranch
|
||||
{
|
||||
CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION);
|
||||
try {
|
||||
f(ss);
|
||||
if (ss.eof()) return true;
|
||||
} catch(...) {}
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
int nIndex;
|
||||
std::vector<uint256> branch;
|
||||
|
||||
MerkleBranch() {}
|
||||
MerkleBranch(int i, std::vector<uint256> b) : nIndex(i), branch(b) {}
|
||||
uint256 Exec(uint256 hash) const { return SafeCheckMerkleBranch(hash, branch, nIndex); }
|
||||
|
||||
MerkleBranch& operator<<(MerkleBranch append)
|
||||
{
|
||||
nIndex += append.nIndex << branch.size();
|
||||
branch.insert(branch.end(), append.branch.begin(), append.branch.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(VARINT(nIndex));
|
||||
READWRITE(branch);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef std::pair<uint256,MerkleBranch> TxProof;
|
||||
|
||||
|
||||
uint256 GetMerkleRoot(const std::vector<uint256>& vLeaves);
|
||||
struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode);
|
||||
bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull, const CTransaction &tx, unsigned int nIn);
|
||||
|
||||
|
||||
#endif /* CC_EVAL_H */
|
||||
|
||||
240
src/cc/faucet.cpp
Normal file
240
src/cc/faucet.cpp
Normal file
@@ -0,0 +1,240 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCfaucet.h"
|
||||
#include "../txmempool.h"
|
||||
|
||||
/*
|
||||
This file implements a simple CC faucet as an example of how to make a new CC contract. It wont have any fancy sybil protection but will serve the purpose of a fully automated faucet.
|
||||
|
||||
In order to implement a faucet, we need to have it funded. Once it is funded, anybody should be able to get some reasonable small amount.
|
||||
|
||||
This leads to needing to lock the funding in a CC protected output. And to put a spending limit. We can do a per transaction spending limit quite easily with vout constraints. However, that would allow anybody to issue thousands of transactions per block, so we also need to add a rate limiter.
|
||||
|
||||
To implement this, we can simply make any faucet vout fund the faucet. Then we can limit the number of confirmed utxo by combining faucet outputs and then only using utxo which are confirmed. This combined with a vout size limit will drastically limit the funds that can be withdrawn from the faucet.
|
||||
*/
|
||||
|
||||
// start of consensus code
|
||||
|
||||
int64_t IsFaucetvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
|
||||
return(tx.vout[v].nValue);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool FaucetExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
|
||||
{
|
||||
static uint256 zerohash;
|
||||
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
//fprintf(stderr,"vini.%d\n",i);
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"vini.%d check mempool\n",i);
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("cant find vinTx");
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"vini.%d check hash and vout\n",i);
|
||||
if ( hashBlock == zerohash )
|
||||
return eval->Invalid("cant faucet from mempool");
|
||||
if ( (assetoshis= IsFaucetvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<numvouts; i++)
|
||||
{
|
||||
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
|
||||
if ( (assetoshis= IsFaucetvout(cp,tx,i)) != 0 )
|
||||
outputs += assetoshis;
|
||||
}
|
||||
if ( inputs != outputs+FAUCETSIZE+txfee )
|
||||
{
|
||||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
|
||||
return eval->Invalid("mismatched inputs != outputs + FAUCETSIZE + txfee");
|
||||
}
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
|
||||
{
|
||||
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;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else
|
||||
{
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
|
||||
{
|
||||
fprintf(stderr,"faucetget invalid vini\n");
|
||||
return eval->Invalid("illegal normal vini");
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"check amounts\n");
|
||||
if ( FaucetExactAmounts(cp,eval,tx,1,10000) == false )
|
||||
{
|
||||
fprintf(stderr,"faucetget invalid amount\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
preventCCvouts = 1;
|
||||
if ( IsFaucetvout(cp,tx,0) != 0 )
|
||||
{
|
||||
preventCCvouts++;
|
||||
i = 1;
|
||||
} else i = 0;
|
||||
txid = tx.GetHash();
|
||||
memcpy(hash,&txid,sizeof(hash));
|
||||
fprintf(stderr,"check faucetget txid %s %02x/%02x\n",uint256_str(str,txid),hash[0],hash[31]);
|
||||
if ( tx.vout[i].nValue != FAUCETSIZE )
|
||||
return eval->Invalid("invalid faucet output");
|
||||
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);
|
||||
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");
|
||||
}
|
||||
}
|
||||
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
|
||||
if ( retval != 0 )
|
||||
fprintf(stderr,"faucetget validated\n");
|
||||
else fprintf(stderr,"faucetget invalid\n");
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of consensus code
|
||||
|
||||
// helper functions for rpc calls in rpcwallet.cpp
|
||||
|
||||
int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
// 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 ( total != 0 && maxinputs != 0 )
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
nValue = it->second.satoshis;
|
||||
totalinputs += nValue;
|
||||
n++;
|
||||
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
std::string FaucetGet(uint64_t txfee)
|
||||
{
|
||||
CMutableTransaction mtx,tmpmtx; CPubKey mypk,faucetpk; int64_t inputs,CCchange=0,nValue=FAUCETSIZE; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash;
|
||||
cp = CCinit(&C,EVAL_FAUCET);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
faucetpk = GetUnspendable(cp,0);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( (inputs= AddFaucetInputs(cp,mtx,faucetpk,nValue+txfee,60)) > 0 )
|
||||
{
|
||||
if ( inputs > nValue )
|
||||
CCchange = (inputs - nValue - txfee);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET,CCchange,faucetpk));
|
||||
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_FAUCET << (uint8_t)'G' << j));
|
||||
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
|
||||
{
|
||||
len >>= 1;
|
||||
decode_hex(buf,len,(char *)rawhex.c_str());
|
||||
hash = bits256_doublesha256(0,buf,len);
|
||||
if ( (hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0 )
|
||||
{
|
||||
fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL));
|
||||
return(rawhex);
|
||||
}
|
||||
//fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]);
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL));
|
||||
return("");
|
||||
} else fprintf(stderr,"cant find faucet inputs\n");
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string FaucetFund(uint64_t txfee,int64_t funds)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,faucetpk; CScript opret; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_FAUCET);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
faucetpk = GetUnspendable(cp,0);
|
||||
if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET,funds,faucetpk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
UniValue FaucetInfo()
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); char numstr[64];
|
||||
CMutableTransaction mtx; 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);
|
||||
}
|
||||
|
||||
184
src/cc/fsm.cpp
Normal file
184
src/cc/fsm.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCfsm.h"
|
||||
#include "../txmempool.h"
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
// start of consensus code
|
||||
|
||||
int64_t IsFSMvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
|
||||
return(tx.vout[v].nValue);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool FSMExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
|
||||
{
|
||||
static uint256 zerohash;
|
||||
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
//fprintf(stderr,"vini.%d\n",i);
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"vini.%d check mempool\n",i);
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("cant find vinTx");
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"vini.%d check hash and vout\n",i);
|
||||
if ( hashBlock == zerohash )
|
||||
return eval->Invalid("cant FSM from mempool");
|
||||
if ( (assetoshis= IsFSMvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<numvouts; i++)
|
||||
{
|
||||
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
|
||||
if ( (assetoshis= IsFSMvout(cp,tx,i)) != 0 )
|
||||
outputs += assetoshis;
|
||||
}
|
||||
if ( inputs != outputs+COIN+txfee )
|
||||
{
|
||||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
|
||||
return eval->Invalid("mismatched inputs != outputs + COIN + txfee");
|
||||
}
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
return(false); // reject any FSM CC for now
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"check vins\n");
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
|
||||
{
|
||||
fprintf(stderr,"fsmget invalid vini\n");
|
||||
return eval->Invalid("illegal normal vini");
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"check amounts\n");
|
||||
if ( FSMExactAmounts(cp,eval,tx,1,10000) == false )
|
||||
{
|
||||
fprintf(stderr,"fsmget invalid amount\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
preventCCvouts = 1;
|
||||
if ( IsFSMvout(cp,tx,0) != 0 )
|
||||
{
|
||||
preventCCvouts++;
|
||||
i = 1;
|
||||
} else i = 0;
|
||||
if ( tx.vout[i].nValue != COIN )
|
||||
return eval->Invalid("invalid fsm output");
|
||||
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
|
||||
if ( retval != 0 )
|
||||
fprintf(stderr,"fsmget validated\n");
|
||||
else fprintf(stderr,"fsmget invalid\n");
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of consensus code
|
||||
|
||||
// helper functions for rpc calls in rpcwallet.cpp
|
||||
|
||||
int64_t AddFSMInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
|
||||
{
|
||||
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);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
// prevent dup
|
||||
if ( it->second.satoshis < 1000000 )
|
||||
continue;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( (nValue= IsFSMvout(cp,vintx,(int32_t)it->first.index)) > 0 )
|
||||
{
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
mtx.vin.push_back(CTxIn(txid,(int32_t)it->first.index,CScript()));
|
||||
nValue = it->second.satoshis;
|
||||
totalinputs += nValue;
|
||||
n++;
|
||||
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
std::string FSMList()
|
||||
{
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string FSMCreate(uint64_t txfee,std::string name,std::string states)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,fsmpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_FSM);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
fsmpk = GetUnspendable(cp,0);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( (inputs= AddFSMInputs(cp,mtx,fsmpk,nValue+txfee,60)) > 0 )
|
||||
{
|
||||
if ( inputs > nValue )
|
||||
CCchange = (inputs - nValue - txfee);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_FSM,CCchange,fsmpk));
|
||||
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret));
|
||||
} else fprintf(stderr,"cant find fsm inputs\n");
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string FSMInfo(uint256 fsmtxid)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,fsmpk; int64_t funds = 0; CScript opret; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_FSM);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
fsmpk = GetUnspendable(cp,0);
|
||||
return("");
|
||||
}
|
||||
|
||||
|
||||
90
src/cc/import.cpp
Normal file
90
src/cc/import.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "cc/eval.h"
|
||||
#include "cc/utils.h"
|
||||
#include "importcoin.h"
|
||||
#include "primitives/transaction.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.
|
||||
*/
|
||||
bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
|
||||
{
|
||||
if (importTx.vout.size() < 2)
|
||||
return Invalid("too-few-vouts");
|
||||
|
||||
// params
|
||||
TxProof proof;
|
||||
CTransaction burnTx;
|
||||
std::vector<CTxOut> payouts;
|
||||
|
||||
if (!UnmarshalImportTx(importTx, proof, burnTx, payouts))
|
||||
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())
|
||||
return Invalid("non-canonical");
|
||||
|
||||
// burn params
|
||||
uint32_t targetCcid;
|
||||
std::string targetSymbol;
|
||||
uint256 payoutsHash;
|
||||
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash))
|
||||
return Invalid("invalid-burn-tx");
|
||||
|
||||
if (targetCcid != GetAssetchainsCC() || targetSymbol != GetAssetchainsSymbol())
|
||||
return Invalid("importcoin-wrong-chain");
|
||||
|
||||
if (targetCcid < KOMODO_FIRSTFUNGIBLEID)
|
||||
return Invalid("chain-not-fungible");
|
||||
|
||||
// check burn amount
|
||||
{
|
||||
uint64_t burnAmount = burnTx.vout.back().nValue;
|
||||
if (burnAmount == 0)
|
||||
return Invalid("invalid-burn-amount");
|
||||
uint64_t totalOut = 0;
|
||||
for (int i=0; i<importTx.vout.size(); i++)
|
||||
totalOut += importTx.vout[i].nValue;
|
||||
if (totalOut > burnAmount)
|
||||
return Invalid("payout-too-high");
|
||||
}
|
||||
|
||||
// Check burntx shows correct outputs hash
|
||||
if (payoutsHash != SerializeHash(payouts))
|
||||
return Invalid("wrong-payouts");
|
||||
|
||||
// Check proof confirms existance of burnTx
|
||||
{
|
||||
uint256 momom, target;
|
||||
if (!GetProofRoot(proof.first, momom))
|
||||
return Invalid("coudnt-load-momom");
|
||||
|
||||
target = proof.second.Exec(burnTx.GetHash());
|
||||
if (momom != proof.second.Exec(burnTx.GetHash()))
|
||||
return Invalid("momom-check-fail");
|
||||
}
|
||||
|
||||
return Valid();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "chain.h"
|
||||
#include "streams.h"
|
||||
#include "cc/eval.h"
|
||||
#include "cc/betprotocol.h"
|
||||
#include "primitives/transaction.h"
|
||||
|
||||
|
||||
/*
|
||||
* Crypto-Condition EVAL method that verifies a payout against a transaction
|
||||
* notarised on another chain.
|
||||
*
|
||||
* IN: params - condition params
|
||||
* IN: importTx - Payout transaction on value chain (KMD)
|
||||
* IN: nIn - index of input of stake
|
||||
*
|
||||
* importTx: Spends stakeTx with payouts from asset chain
|
||||
*
|
||||
* in 0: Spends Stake TX and contains ImportPayout CC
|
||||
* out 0: OP_RETURN MomProof, disputeTx
|
||||
* out 1-: arbitrary payouts
|
||||
*
|
||||
* disputeTx: Spends sessionTx.0 (opener on asset chain)
|
||||
*
|
||||
* in 0: spends sessionTx.0
|
||||
* in 1-: anything
|
||||
* out 0: OP_RETURN hash of payouts
|
||||
* out 1-: anything
|
||||
*/
|
||||
bool Eval::ImportPayout(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
|
||||
{
|
||||
if (importTx.vout.size() == 0) return Invalid("no-vouts");
|
||||
|
||||
// load data from vout[0]
|
||||
MoMProof proof;
|
||||
CTransaction disputeTx;
|
||||
{
|
||||
std::vector<unsigned char> vopret;
|
||||
GetOpReturnData(importTx.vout[0].scriptPubKey, vopret);
|
||||
if (!E_UNMARSHAL(vopret, ss >> proof; ss >> disputeTx))
|
||||
return Invalid("invalid-payload");
|
||||
}
|
||||
|
||||
// Check disputeTx.0 shows correct payouts
|
||||
{
|
||||
uint256 givenPayoutsHash;
|
||||
GetOpReturnHash(disputeTx.vout[0].scriptPubKey, givenPayoutsHash);
|
||||
std::vector<CTxOut> payouts(importTx.vout.begin() + 1, importTx.vout.end());
|
||||
if (givenPayoutsHash != SerializeHash(payouts))
|
||||
return Invalid("wrong-payouts");
|
||||
}
|
||||
|
||||
// Check disputeTx spends sessionTx.0
|
||||
// condition ImportPayout params is session ID from other chain
|
||||
{
|
||||
uint256 sessionHash;
|
||||
if (!E_UNMARSHAL(params, ss >> sessionHash))
|
||||
return Invalid("malformed-params");
|
||||
if (disputeTx.vin[0].prevout != COutPoint(sessionHash, 0))
|
||||
return Invalid("wrong-session");
|
||||
}
|
||||
|
||||
// Check disputeTx solves momproof from vout[0]
|
||||
{
|
||||
NotarisationData data;
|
||||
if (!GetNotarisationData(proof.notarisationHash, data))
|
||||
return Invalid("coudnt-load-mom");
|
||||
|
||||
if (data.MoM != proof.Exec(disputeTx.GetHash()))
|
||||
return Invalid("mom-check-fail");
|
||||
}
|
||||
|
||||
return Valid();
|
||||
}
|
||||
186
src/cc/lotto.cpp
Normal file
186
src/cc/lotto.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CClotto.h"
|
||||
#include "../txmempool.h"
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
// start of consensus code
|
||||
|
||||
int64_t IsLottovout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
|
||||
return(tx.vout[v].nValue);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool LottoExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
|
||||
{
|
||||
static uint256 zerohash;
|
||||
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
//fprintf(stderr,"vini.%d\n",i);
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"vini.%d check mempool\n",i);
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("cant find vinTx");
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"vini.%d check hash and vout\n",i);
|
||||
if ( hashBlock == zerohash )
|
||||
return eval->Invalid("cant Lotto from mempool");
|
||||
if ( (assetoshis= IsLottovout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<numvouts; i++)
|
||||
{
|
||||
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
|
||||
if ( (assetoshis= IsLottovout(cp,tx,i)) != 0 )
|
||||
outputs += assetoshis;
|
||||
}
|
||||
if ( inputs != outputs+COIN+txfee )
|
||||
{
|
||||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
|
||||
return eval->Invalid("mismatched inputs != outputs + COIN + txfee");
|
||||
}
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
return(false); // reject any lotto CC for now
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"check vins\n");
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
|
||||
{
|
||||
fprintf(stderr,"Lottoget invalid vini\n");
|
||||
return eval->Invalid("illegal normal vini");
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"check amounts\n");
|
||||
if ( LottoExactAmounts(cp,eval,tx,1,10000) == false )
|
||||
{
|
||||
fprintf(stderr,"Lottoget invalid amount\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
preventCCvouts = 1;
|
||||
if ( IsLottovout(cp,tx,0) != 0 )
|
||||
{
|
||||
preventCCvouts++;
|
||||
i = 1;
|
||||
} else i = 0;
|
||||
if ( tx.vout[i].nValue != COIN )
|
||||
return eval->Invalid("invalid Lotto output");
|
||||
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
|
||||
if ( retval != 0 )
|
||||
fprintf(stderr,"Lottoget validated\n");
|
||||
else fprintf(stderr,"Lottoget invalid\n");
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of consensus code
|
||||
|
||||
// helper functions for rpc calls in rpcwallet.cpp
|
||||
|
||||
int64_t AddLottoInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
|
||||
{
|
||||
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);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
// prevent dup
|
||||
if ( it->second.satoshis < 1000000 )
|
||||
continue;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( (nValue= IsLottovout(cp,vintx,(int32_t)it->first.index)) > 0 )
|
||||
{
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
mtx.vin.push_back(CTxIn(txid,(int32_t)it->first.index,CScript()));
|
||||
nValue = it->second.satoshis;
|
||||
totalinputs += nValue;
|
||||
n++;
|
||||
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
std::string LottoTicket(uint64_t txfee,int64_t numtickets)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Lottopk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_LOTTO);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
Lottopk = GetUnspendable(cp,0);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( (inputs= AddLottoInputs(cp,mtx,Lottopk,nValue+txfee,60)) > 0 )
|
||||
{
|
||||
if ( inputs > nValue )
|
||||
CCchange = (inputs - nValue - txfee);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_LOTTO,CCchange,Lottopk));
|
||||
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret));
|
||||
} else fprintf(stderr,"cant find Lotto inputs\n");
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string LottoWinner(uint64_t txfee)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Lottopk; int64_t winnings = 0; CScript opret; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_LOTTO);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
Lottopk = GetUnspendable(cp,0);
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_LOTTO,winnings,Lottopk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
|
||||
701
src/cc/rewards.cpp
Normal file
701
src/cc/rewards.cpp
Normal file
@@ -0,0 +1,701 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCrewards.h"
|
||||
|
||||
/*
|
||||
The rewards CC contract is initially for OOT, which needs this functionality. However, many of the attributes can be parameterized to allow different rewards programs to run. Multiple rewards plans could even run on the same blockchain, though the user would need to choose which one to lock funds into.
|
||||
|
||||
At the high level, the user would lock funds for some amount of time and at the end of it, would get all the locked funds back with an additional reward. So there needs to be a lock funds and unlock funds ability. Additionally, the rewards need to come from somewhere, so similar to the faucet, there would be a way to fund the reward.
|
||||
|
||||
Additional requirements are for the user to be able to lock funds via SPV. This requirement in turns forces the creation of a way for anybody to be able to unlock the funds as that operation requires a native daemon running and cant be done over SPV. The idea is to allow anybody to run a script that would unlock all funds that are matured. As far as the user is concerned, he locks his funds via SPV and after some time it comes back with an extra reward.
|
||||
|
||||
In reality, the funds are locked into a CC address that is unspendable, except for some special conditions and it needs to come back to the address that funded the lock. In order to implement this, several things are clear.
|
||||
|
||||
1) each locked CC utxo needs to be linked to a specific rewards plan
|
||||
2) each locked CC utxo needs to know the only address that it can be unlocked into
|
||||
3) SPV requirement means the lock transaction needs to be able to be created without any CC signing
|
||||
|
||||
The opreturn will be used to store the name of the rewards plan and all funding and locked funds with the same plan will use the same pool of rewards. plan names will be limited to 8 chars and encoded into a uint64_t.
|
||||
|
||||
The initial funding transaction will have all the parameters for the rewards plan encoded in the vouts. Additional fundings will just increase the available CC utxo for the rewards.
|
||||
|
||||
Locks wont have any CC vins, but will send to the RewardsCCaddress, with the plan stringbits in the opreturn. vout1 will have the unlock address and no other destination is valid.
|
||||
|
||||
Unlock does a CC spend to the vout1 address
|
||||
|
||||
|
||||
createfunding
|
||||
vins.*: normal inputs
|
||||
vout.0: CC vout for funding
|
||||
vout.1: normal marker vout for easy searching
|
||||
vout.2: normal change
|
||||
vout.n-1: opreturn 'F' sbits APR minseconds maxseconds mindeposit
|
||||
|
||||
addfunding
|
||||
vins.*: normal inputs
|
||||
vout.0: CC vout for funding
|
||||
vout.1: normal change
|
||||
vout.n-1: opreturn 'A' sbits fundingtxid
|
||||
|
||||
lock
|
||||
vins.*: normal inputs
|
||||
vout.0: CC vout for locked funds
|
||||
vout.1: normal output to unlock address
|
||||
vout.2: change
|
||||
vout.n-1: opreturn 'L' sbits fundingtxid
|
||||
|
||||
unlock
|
||||
vin.0: locked funds CC vout.0 from lock
|
||||
vin.1+: funding CC vout.0 from 'F' and 'A' and 'U'
|
||||
vout.0: funding CC change
|
||||
vout.1: normal output to unlock address
|
||||
vout.n-1: opreturn 'U' sbits fundingtxid
|
||||
|
||||
*/
|
||||
|
||||
extern std::string CCerror;
|
||||
|
||||
int64_t RewardsCalc(int64_t amount,uint256 txid,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit)
|
||||
{
|
||||
int32_t numblocks; uint64_t duration,reward = 0;
|
||||
//fprintf(stderr,"minseconds %llu maxseconds %llu\n",(long long)minseconds,(long long)maxseconds);
|
||||
if ( (duration= CCduration(numblocks,txid)) < minseconds )
|
||||
{
|
||||
fprintf(stderr,"duration %llu < minseconds %llu\n",(long long)duration,(long long)minseconds);
|
||||
return(0);
|
||||
//duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24);
|
||||
} else if ( duration > maxseconds )
|
||||
duration = maxseconds;
|
||||
if ( 0 ) // amount * APR * duration / COIN * 100 * 365*24*3600
|
||||
reward = (((amount * APR) / COIN) * duration) / (365*24*3600LL * 100);
|
||||
else reward = (((amount * duration) / (365 * 24 * 3600LL)) * (APR / 1000000)) / 10000;
|
||||
if ( reward > amount )
|
||||
reward = amount;
|
||||
fprintf(stderr,"amount %.8f %.8f %llu -> duration.%llu reward %.8f vals %.8f %.8f\n",(double)amount/COIN,((double)amount * APR)/COIN,(long long)((amount * APR) / (COIN * 365*24*3600)),(long long)duration,(double)reward/COIN,(double)((amount * duration) / (365 * 24 * 3600LL))/COIN,(double)(((amount * duration) / (365 * 24 * 3600LL)) * (APR / 1000000))/COIN);
|
||||
return(reward);
|
||||
}
|
||||
|
||||
CScript EncodeRewardsFundingOpRet(uint8_t funcid,uint64_t sbits,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_REWARDS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << APR << minseconds << maxseconds << mindeposit);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodeRewardsFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,uint64_t &APR,uint64_t &minseconds,uint64_t &maxseconds,uint64_t &mindeposit)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t *script,e,f;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> APR; ss >> minseconds; ss >> maxseconds; ss >> mindeposit) != 0 )
|
||||
{
|
||||
if ( e == EVAL_REWARDS && f == 'F' )
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodeRewardsOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_REWARDS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodeRewardsOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid; uint64_t APR,minseconds,maxseconds,mindeposit;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
if ( vopret.size() > 2 )
|
||||
{
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( script[0] == EVAL_REWARDS )
|
||||
{
|
||||
if ( script[1] == 'F' )
|
||||
{
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> APR; ss >> minseconds; ss >> maxseconds; ss >> mindeposit) != 0 )
|
||||
{
|
||||
fundingtxid = txid;
|
||||
return('F');
|
||||
} else fprintf(stderr,"unmarshal error for F\n");
|
||||
}
|
||||
else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid) != 0 )
|
||||
{
|
||||
if ( e == EVAL_REWARDS && (f == 'L' || f == 'U' || f == 'A') )
|
||||
return(f);
|
||||
else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f);
|
||||
}
|
||||
} else fprintf(stderr,"script[0] %02x != EVAL_REWARDS\n",script[0]);
|
||||
} else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t IsRewardsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,uint64_t refsbits,uint256 reffundingtxid)
|
||||
{
|
||||
char destaddr[64]; uint64_t sbits; uint256 fundingtxid,txid; uint8_t funcid; int32_t numvouts;
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 && (numvouts= (int32_t)tx.vout.size()) > 0 )
|
||||
{
|
||||
txid = tx.GetHash();
|
||||
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 && sbits == refsbits && (fundingtxid == reffundingtxid || txid == reffundingtxid) )
|
||||
{
|
||||
|
||||
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
|
||||
return(tx.vout[v].nValue);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool RewardsExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx,uint64_t txfee,uint64_t refsbits,uint256 reffundingtxid)
|
||||
{
|
||||
static uint256 zerohash;
|
||||
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
|
||||
{
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("always should find vin, but didnt");
|
||||
else
|
||||
{
|
||||
if ( hashBlock == zerohash )
|
||||
return eval->Invalid("cant rewards from mempool");
|
||||
if ( (assetoshis= IsRewardsvout(cp,vinTx,tx.vin[i].prevout.n,refsbits,reffundingtxid)) != 0 )
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<numvouts; i++)
|
||||
{
|
||||
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
|
||||
if ( (assetoshis= IsRewardsvout(cp,tx,i,refsbits,reffundingtxid)) != 0 )
|
||||
outputs += assetoshis;
|
||||
}
|
||||
if ( inputs != outputs+txfee )
|
||||
{
|
||||
fprintf(stderr,"inputs %llu vs outputs %llu txfee %llu\n",(long long)inputs,(long long)outputs,(long long)txfee);
|
||||
return eval->Invalid("mismatched inputs != outputs + txfee");
|
||||
}
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
|
||||
{
|
||||
uint256 txid,fundingtxid,hashBlock,vinfundingtxid; uint64_t vinsbits,sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else
|
||||
{
|
||||
txid = tx.GetHash();
|
||||
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");
|
||||
else if ( fundingTx.vout.size() > 0 && DecodeRewardsFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) != 'F' )
|
||||
return eval->Invalid("fundingTx not valid");
|
||||
if ( APR > REWARDSCC_MAXAPR )
|
||||
return eval->Invalid("excessive APR");
|
||||
switch ( funcid )
|
||||
{
|
||||
case 'F':
|
||||
//vins.*: normal inputs
|
||||
//vout.0: CC vout for funding
|
||||
//vout.1: normal marker vout for easy searching
|
||||
//vout.2: normal change
|
||||
//vout.n-1: opreturn 'F' sbits APR minseconds maxseconds mindeposit
|
||||
return eval->Invalid("unexpected RewardsValidate for createfunding");
|
||||
break;
|
||||
case 'A':
|
||||
//vins.*: normal inputs
|
||||
//vout.0: CC vout for funding
|
||||
//vout.1: normal change
|
||||
//vout.n-1: opreturn 'A' sbits fundingtxid
|
||||
return eval->Invalid("unexpected RewardsValidate for addfunding");
|
||||
break;
|
||||
case 'L':
|
||||
//vins.*: normal inputs
|
||||
//vout.0: CC vout for locked funds
|
||||
//vout.1: normal output to unlock address
|
||||
//vout.2: change
|
||||
//vout.n-1: opreturn 'L' sbits fundingtxid
|
||||
return eval->Invalid("unexpected RewardsValidate for lock");
|
||||
break;
|
||||
case 'U':
|
||||
//vin.0: locked funds CC vout.0 from lock
|
||||
//vin.1+: funding CC vout.0 from 'F' and 'A' and 'U'
|
||||
//vout.0: funding CC change or recover normal payout
|
||||
//vout.1: normal output to unlock address
|
||||
//vout.n-1: opreturn 'U' sbits fundingtxid
|
||||
//char str[65],str2[65];
|
||||
//fprintf(stderr,"funding.%s vs %s\n",uint256_str(str,fundingtxid),uint256_str(str2,tx.vin[0].prevout.hash));
|
||||
if ( fundingtxid == tx.vin[0].prevout.hash )
|
||||
return eval->Invalid("cant unlock fundingtxid");
|
||||
else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("always should find vin.0, but didnt");
|
||||
else if ( DecodeRewardsOpRet(tx.vin[0].prevout.hash,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid) != 'L' )
|
||||
return eval->Invalid("can only unlock locktxid");
|
||||
else if ( fundingtxid != vinfundingtxid )
|
||||
return eval->Invalid("mismatched vinfundingtxid");
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
|
||||
return eval->Invalid("unexpected normal vin for unlock");
|
||||
}
|
||||
if ( numvouts == 2 && numvins == 1 )
|
||||
{
|
||||
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
return eval->Invalid("unlock recover tx vout.0 is not normal output");
|
||||
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 )
|
||||
return eval->Invalid("unlock recover tx vout.1 nonz amount");
|
||||
else return(true);
|
||||
}
|
||||
if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("unlock tx vout.0 is normal output");
|
||||
else if ( numvouts != 3 )
|
||||
return eval->Invalid("unlock tx wrong number of vouts");
|
||||
else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("unlock tx vout.0 is normal output");
|
||||
else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
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 )
|
||||
return eval->Invalid("unlock tx vout.1 isnt amount+reward");
|
||||
else if ( tx.vout[2].nValue > 0 )
|
||||
return eval->Invalid("unlock tx vout.2 isnt 0");
|
||||
preventCCvouts = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t refsbits,uint256 reffundingtxid,uint64_t needed)
|
||||
{
|
||||
uint8_t funcid; uint64_t sbits,nValue; uint256 fundingtxid; char str[65];
|
||||
memset(&txid,0,sizeof(txid));
|
||||
vout = -1;
|
||||
nValue = 0;
|
||||
BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
|
||||
{
|
||||
const CTransaction &tx = e.GetTx();
|
||||
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 ( (funcid= DecodeRewardsOpRet(hash,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) == 'U' && sbits == refsbits && fundingtxid == reffundingtxid )
|
||||
{
|
||||
txid = hash;
|
||||
vout = 0;
|
||||
nValue = tx.vout[0].nValue;
|
||||
fprintf(stderr,"found 'U' %s %.8f in unspent in mempool\n",uint256_str(str,txid),(double)nValue/COIN);
|
||||
return(nValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(nValue);
|
||||
}
|
||||
|
||||
// 'L' vs 'F' and 'A'
|
||||
int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs,uint64_t refsbits,uint256 reffundingtxid)
|
||||
{
|
||||
char coinaddr[64],str[65]; uint64_t 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);
|
||||
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 < 1000000 )
|
||||
continue;
|
||||
//fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
|
||||
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,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
{
|
||||
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
|
||||
{
|
||||
if ( sbits != refsbits || fundingtxid != reffundingtxid )
|
||||
continue;
|
||||
if ( maxseconds == 0 && funcid != 'F' && funcid != 'A' && funcid != 'U' )
|
||||
continue;
|
||||
else if ( maxseconds != 0 && funcid != 'L' )
|
||||
{
|
||||
if ( CCduration(numblocks,txid) < maxseconds )
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr,"maxseconds.%d (%c) %.8f %.8f\n",(int32_t)maxseconds,funcid,(double)tx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN);
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
{
|
||||
if ( maxseconds != 0 )
|
||||
scriptPubKey = tx.vout[1].scriptPubKey;
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
}
|
||||
totalinputs += it->second.satoshis;
|
||||
n++;
|
||||
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
|
||||
break;
|
||||
} else fprintf(stderr,"null funcid\n");
|
||||
}
|
||||
}
|
||||
if ( maxseconds == 0 && totalinputs < total && (maxinputs == 0 || n < maxinputs-1) )
|
||||
{
|
||||
fprintf(stderr,"search mempool for unlocked and unspent CC rewards output for %.8f\n",(double)(total-totalinputs)/COIN);
|
||||
if ( (nValue= myIs_unlockedtx_inmempool(txid,vout,refsbits,reffundingtxid,total-totalinputs)) > 0 )
|
||||
{
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
fprintf(stderr,"added mempool vout for %.8f\n",(double)nValue/COIN);
|
||||
totalinputs += nValue;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
int64_t RewardsPlanFunds(uint64_t &lockedfunds,uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid)
|
||||
{
|
||||
char coinaddr[64]; uint64_t sbits; int64_t nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout; uint8_t funcid;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
lockedfunds = 0;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,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 ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) == 'F' || funcid == 'A' || funcid == 'U' || funcid == 'L' )
|
||||
{
|
||||
if ( refsbits == sbits && (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
|
||||
{
|
||||
if ( (nValue= IsRewardsvout(cp,tx,vout,sbits,fundingtxid)) > 0 )
|
||||
{
|
||||
if ( funcid == 'L' )
|
||||
lockedfunds += nValue;
|
||||
else totalinputs += nValue;
|
||||
}
|
||||
else fprintf(stderr,"refsbits.%llx sbits.%llx nValue %.8f\n",(long long)refsbits,(long long)sbits,(double)nValue/COIN);
|
||||
} //else fprintf(stderr,"else case\n");
|
||||
} else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
|
||||
}
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
bool RewardsPlanExists(struct CCcontract_info *cp,uint64_t refsbits,CPubKey rewardspk,uint64_t &APR,uint64_t &minseconds,uint64_t &maxseconds,uint64_t &mindeposit)
|
||||
{
|
||||
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);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
|
||||
{
|
||||
//int height = it->first.blockHeight;
|
||||
txid = it->first.txhash;
|
||||
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
|
||||
{
|
||||
//char str[65]; fprintf(stderr,"rewards plan %s\n",uint256_str(str,txid));
|
||||
if ( DecodeRewardsFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) == 'F' )
|
||||
{
|
||||
if ( sbits == refsbits )
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
UniValue RewardsInfo(uint256 rewardsid)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; uint64_t lockedfunds,APR,minseconds,maxseconds,mindeposit,sbits,funding; CPubKey rewardspk; struct CCcontract_info *cp,C; char str[67],numstr[65];
|
||||
if ( GetTransaction(rewardsid,vintx,hashBlock,false) == 0 )
|
||||
{
|
||||
fprintf(stderr,"cant find fundingtxid\n");
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","cant find fundingtxid"));
|
||||
return(result);
|
||||
}
|
||||
if ( vintx.vout.size() > 0 && DecodeRewardsFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) == 0 )
|
||||
{
|
||||
fprintf(stderr,"fundingtxid isnt rewards creation txid\n");
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","fundingtxid isnt rewards creation txid"));
|
||||
return(result);
|
||||
}
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("fundingtxid",uint256_str(str,rewardsid)));
|
||||
unstringbits(str,sbits);
|
||||
result.push_back(Pair("name",str));
|
||||
result.push_back(Pair("sbits",sbits));
|
||||
sprintf(numstr,"%.8f",(double)APR/COIN);
|
||||
result.push_back(Pair("APR",numstr));
|
||||
result.push_back(Pair("minseconds",minseconds));
|
||||
result.push_back(Pair("maxseconds",maxseconds));
|
||||
sprintf(numstr,"%.8f",(double)mindeposit/COIN);
|
||||
result.push_back(Pair("mindeposit",numstr));
|
||||
cp = CCinit(&C,EVAL_REWARDS);
|
||||
rewardspk = GetUnspendable(cp,0);
|
||||
funding = RewardsPlanFunds(lockedfunds,sbits,cp,rewardspk,rewardsid);
|
||||
sprintf(numstr,"%.8f",(double)funding/COIN);
|
||||
result.push_back(Pair("funding",numstr));
|
||||
sprintf(numstr,"%.8f",(double)lockedfunds/COIN);
|
||||
result.push_back(Pair("locked",numstr));
|
||||
return(result);
|
||||
}
|
||||
|
||||
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);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( vintx.vout.size() > 0 && DecodeRewardsFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) != 0 )
|
||||
{
|
||||
result.push_back(uint256_str(str,txid));
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
std::string RewardsCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t APR,int64_t minseconds,int64_t maxseconds,int64_t mindeposit)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C;
|
||||
if ( funds < COIN || mindeposit < 0 || minseconds < 0 || maxseconds < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative parameter error\n");
|
||||
return("");
|
||||
}
|
||||
if ( APR > REWARDSCC_MAXAPR )
|
||||
{
|
||||
fprintf(stderr,"25%% APR is maximum\n");
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_REWARDS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
rewardspk = GetUnspendable(cp,0);
|
||||
sbits = stringbits(planstr);
|
||||
if ( RewardsPlanExists(cp,sbits,rewardspk,a,b,c,d) != 0 )
|
||||
{
|
||||
fprintf(stderr,"Rewards plan (%s) already exists\n",planstr);
|
||||
return("");
|
||||
}
|
||||
if ( AddNormalinputs(mtx,mypk,funds+2*txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,rewardspk));
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(rewardspk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeRewardsFundingOpRet('F',sbits,APR,minseconds,maxseconds,mindeposit)));
|
||||
}
|
||||
fprintf(stderr,"cant find enough inputs\n");
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string RewardsAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C;
|
||||
if ( amount < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative parameter error\n");
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_REWARDS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
rewardspk = GetUnspendable(cp,0);
|
||||
sbits = stringbits(planstr);
|
||||
if ( RewardsPlanExists(cp,sbits,rewardspk,a,b,c,d) == 0 )
|
||||
{
|
||||
CCerror = strprintf("Rewards plan %s doesnt exist\n",planstr);
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
sbits = stringbits(planstr);
|
||||
if ( AddNormalinputs(mtx,mypk,amount+txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,rewardspk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeRewardsOpRet('A',sbits,fundingtxid)));
|
||||
} else {
|
||||
CCerror = "cant find enough inputs";
|
||||
fprintf(stderr,"%s\n", CCerror.c_str());
|
||||
}
|
||||
CCerror = "cant find fundingtxid";
|
||||
fprintf(stderr,"%s\n", CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t deposit)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t lockedfunds,sbits,funding,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C;
|
||||
if ( deposit < txfee )
|
||||
{
|
||||
CCerror = "deposit amount less than txfee";
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_REWARDS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
rewardspk = GetUnspendable(cp,0);
|
||||
sbits = stringbits(planstr);
|
||||
if ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 )
|
||||
{
|
||||
CCerror = strprintf("Rewards plan %s doesnt exist\n",planstr);
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
if ( deposit < mindeposit )
|
||||
{
|
||||
CCerror = strprintf("Rewards plan %s deposit %.8f < mindeposit %.8f\n",planstr,(double)deposit/COIN,(double)mindeposit/COIN);
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
if ( (funding= RewardsPlanFunds(lockedfunds,sbits,cp,rewardspk,fundingtxid)) >= deposit ) // arbitrary cmpval
|
||||
{
|
||||
if ( AddNormalinputs(mtx,mypk,deposit+2*txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,deposit,rewardspk));
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeRewardsOpRet('L',sbits,fundingtxid)));
|
||||
} else {
|
||||
CCerror = strprintf("cant find enough inputs %.8f not enough for %.8f, make sure you imported privkey for the -pubkey address\n",(double)funding/COIN,(double)deposit/COIN);
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"cant find rewards inputs funding %.8f locked %.8f vs deposit %.8f\n",(double)funding/COIN,(double)lockedfunds/COIN,(double)deposit/COIN);
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid)
|
||||
{
|
||||
CMutableTransaction mtx,firstmtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,rewardspk; CScript scriptPubKey,ignore; uint256 hashBlock; uint64_t sbits,APR,minseconds,maxseconds,mindeposit; int64_t funding,reward=0,amount=0,inputs,CCchange=0; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_REWARDS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
rewardspk = GetUnspendable(cp,0);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
sbits = stringbits(planstr);
|
||||
if ( locktxid == fundingtxid )
|
||||
{
|
||||
fprintf(stderr,"Rewards plan cant unlock fundingtxid\n");
|
||||
CCerror = "Rewards plan cant unlock fundingtxid";
|
||||
return("");
|
||||
}
|
||||
if ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 )
|
||||
{
|
||||
fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
|
||||
CCerror = "Rewards plan does not exist";
|
||||
return("");
|
||||
}
|
||||
fprintf(stderr,"APR %.8f minseconds.%llu maxseconds.%llu mindeposit %.8f\n",(double)APR/COIN,(long long)minseconds,(long long)maxseconds,(double)mindeposit/COIN);
|
||||
if ( locktxid == zeroid )
|
||||
amount = AddRewardsInputs(scriptPubKey,maxseconds,cp,mtx,rewardspk,(1LL << 30),1,sbits,fundingtxid);
|
||||
else
|
||||
{
|
||||
GetCCaddress(cp,coinaddr,rewardspk);
|
||||
if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 )
|
||||
{
|
||||
fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr);
|
||||
CCerror = "locktxid/v0 is spent";
|
||||
return("");
|
||||
}
|
||||
if ( GetTransaction(locktxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
{
|
||||
scriptPubKey = tx.vout[1].scriptPubKey;
|
||||
mtx.vin.push_back(CTxIn(locktxid,0,CScript()));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"%s no normal vout.1 in locktxid\n",coinaddr);
|
||||
CCerror = "no normal vout.1 in locktxid";
|
||||
return("");
|
||||
}
|
||||
}
|
||||
if ( amount > txfee )
|
||||
{
|
||||
reward = RewardsCalc(amount,mtx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit);
|
||||
if ( scriptPubKey.size() > 0 )
|
||||
{
|
||||
if ( reward > txfee )
|
||||
{
|
||||
firstmtx = mtx;
|
||||
if ( (inputs= AddRewardsInputs(ignore,0,cp,mtx,rewardspk,reward+txfee,30,sbits,fundingtxid)) >= reward+txfee )
|
||||
{
|
||||
if ( inputs >= (reward + 2*txfee) )
|
||||
CCchange = (inputs - (reward + txfee));
|
||||
fprintf(stderr,"inputs %.8f CCchange %.8f amount %.8f reward %.8f\n",(double)inputs/COIN,(double)CCchange/COIN,(double)amount/COIN,(double)reward/COIN);
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,rewardspk));
|
||||
mtx.vout.push_back(CTxOut(amount+reward,scriptPubKey));
|
||||
return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,EncodeRewardsOpRet('U',sbits,fundingtxid)));
|
||||
}
|
||||
else
|
||||
{
|
||||
firstmtx.vout.push_back(CTxOut(amount-txfee,scriptPubKey));
|
||||
//CCerror = "cant find enough rewards inputs";
|
||||
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)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CCerror = strprintf("reward %.8f is <= the transaction fee", reward);
|
||||
fprintf(stderr,"%s\n", CCerror.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CCerror = "invalid scriptPubKey";
|
||||
fprintf(stderr,"%s\n", CCerror.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CCerror = "amount must be more than txfee";
|
||||
fprintf(stderr,"%s\n", CCerror.c_str());
|
||||
}
|
||||
fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN);
|
||||
return("");
|
||||
}
|
||||
|
||||
0
src/cc/utils.cpp
Normal file
0
src/cc/utils.cpp
Normal file
49
src/cc/utils.h
Normal file
49
src/cc/utils.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/******************************************************************************
|
||||
* 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_UTILS_H
|
||||
#define CC_UTILS_H
|
||||
|
||||
#include "streams.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
/*
|
||||
* Serialisation boilerplate
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
std::vector<uint8_t> SerializeF(const T f)
|
||||
{
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
f(ss);
|
||||
return std::vector<unsigned char>(ss.begin(), ss.end());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool DeserializeF(const std::vector<unsigned char> vIn, T f)
|
||||
{
|
||||
CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION);
|
||||
try {
|
||||
f(ss);
|
||||
if (ss.eof()) return true;
|
||||
} catch(...) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define E_MARSHAL(body) SerializeF([&] (CDataStream &ss) {body;})
|
||||
#define E_UNMARSHAL(params, body) DeserializeF(params, [&] (CDataStream &ss) {body;})
|
||||
|
||||
#endif /* CC_UTILS_H */
|
||||
@@ -11,6 +11,7 @@ using namespace std;
|
||||
* CChain implementation
|
||||
*/
|
||||
void CChain::SetTip(CBlockIndex *pindex) {
|
||||
lastTip = pindex;
|
||||
if (pindex == NULL) {
|
||||
vChain.clear();
|
||||
return;
|
||||
|
||||
11
src/chain.h
11
src/chain.h
@@ -121,7 +121,7 @@ public:
|
||||
|
||||
//! height of the entry in the chain. The genesis block has height 0
|
||||
int nHeight;
|
||||
|
||||
int64_t newcoins,zfunds; int8_t segid; // jl777 fields
|
||||
//! Which # file this block is stored in (blk?????.dat)
|
||||
int nFile;
|
||||
|
||||
@@ -181,6 +181,8 @@ public:
|
||||
void SetNull()
|
||||
{
|
||||
phashBlock = NULL;
|
||||
newcoins = zfunds = 0;
|
||||
segid = -2;
|
||||
pprev = NULL;
|
||||
pskip = NULL;
|
||||
nHeight = 0;
|
||||
@@ -321,6 +323,7 @@ public:
|
||||
//! Efficiently find an ancestor of this block.
|
||||
CBlockIndex* GetAncestor(int height);
|
||||
const CBlockIndex* GetAncestor(int height) const;
|
||||
|
||||
};
|
||||
|
||||
/** Used to marshal pointers into hashes for db storage. */
|
||||
@@ -414,6 +417,7 @@ public:
|
||||
class CChain {
|
||||
private:
|
||||
std::vector<CBlockIndex*> vChain;
|
||||
CBlockIndex *lastTip;
|
||||
|
||||
public:
|
||||
/** Returns the index entry for the genesis block of this chain, or NULL if none. */
|
||||
@@ -425,6 +429,11 @@ public:
|
||||
CBlockIndex *Tip() const {
|
||||
return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL;
|
||||
}
|
||||
|
||||
/** Returns the last tip of the chain, or NULL if none. */
|
||||
CBlockIndex *LastTip() const {
|
||||
return vChain.size() > 0 ? lastTip : NULL;
|
||||
}
|
||||
|
||||
/** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */
|
||||
CBlockIndex *operator[](int nHeight) const {
|
||||
|
||||
@@ -536,11 +536,13 @@ public:
|
||||
BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K));
|
||||
nEquihashN = N;
|
||||
nEquihashK = K;
|
||||
|
||||
|
||||
genesis = CreateGenesisBlock(
|
||||
1296688602,
|
||||
uint256S("0x0000000000000000000000000000000000000000000000000000000000000009"),
|
||||
ParseHex("01936b7db1eb4ac39f151b8704642d0a8bda13ec547d54cd5e43ba142fc6d8877cab07b3"),
|
||||
|
||||
|
||||
KOMODO_MINDIFF_NBITS, 4, 0);
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
assert(consensus.hashGenesisBlock == uint256S("0x029f11d80ef9765602235e1bc9727e3eb6ba20839319f761fee920d63401e327"));
|
||||
@@ -566,9 +568,12 @@ public:
|
||||
0
|
||||
};
|
||||
// These prefixes are the same as the testnet prefixes
|
||||
base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25};
|
||||
base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA};
|
||||
base58Prefixes[SECRET_KEY] = {0xEF};
|
||||
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,60);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,85);
|
||||
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,188);
|
||||
//base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25};
|
||||
//base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA};
|
||||
//base58Prefixes[SECRET_KEY] = {0xEF};
|
||||
// do not rely on these BIP32 prefixes; they are not specified and may change
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF};
|
||||
base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "version.h"
|
||||
#include "policy/fees.h"
|
||||
#include "komodo_defs.h"
|
||||
#include "importcoin.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -392,11 +393,13 @@ extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
|
||||
CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t tiptime) const
|
||||
{
|
||||
CAmount value,nResult = 0;
|
||||
if ( interestp != 0 )
|
||||
*interestp = 0;
|
||||
if ( tx.IsCoinImport() )
|
||||
return GetCoinImportValue(tx);
|
||||
if ( tx.IsCoinBase() != 0 )
|
||||
return 0;
|
||||
CAmount value,nResult = 0;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
{
|
||||
value = GetOutputFor(tx.vin[i]).nValue;
|
||||
@@ -421,6 +424,7 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr
|
||||
return nResult;
|
||||
}
|
||||
|
||||
|
||||
bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
|
||||
{
|
||||
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
|
||||
@@ -457,12 +461,12 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
|
||||
|
||||
bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
|
||||
{
|
||||
if (!tx.IsCoinBase()) {
|
||||
if (!tx.IsMint()) {
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
const CCoins* coins = AccessCoins(prevout.hash);
|
||||
if (!coins || !coins->IsAvailable(prevout.n)) {
|
||||
fprintf(stderr,"HaveInputs missing input %s/v%d\n",prevout.hash.ToString().c_str(),prevout.n);
|
||||
//fprintf(stderr,"HaveInputs missing input %s/v%d\n",prevout.hash.ToString().c_str(),prevout.n);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -483,6 +487,9 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
|
||||
if (tx.vjoinsplit.size() > 0) {
|
||||
return MAX_PRIORITY;
|
||||
}
|
||||
if (tx.IsCoinImport()) {
|
||||
return MAX_PRIORITY;
|
||||
}
|
||||
|
||||
double dResult = 0.0;
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
|
||||
339
src/crosschain.cpp
Normal file
339
src/crosschain.cpp
Normal file
@@ -0,0 +1,339 @@
|
||||
#include "cc/eval.h"
|
||||
#include "crosschain.h"
|
||||
#include "importcoin.h"
|
||||
#include "main.h"
|
||||
#include "notarisationdb.h"
|
||||
|
||||
/*
|
||||
* The crosschain workflow.
|
||||
*
|
||||
* 3 chains, A, B, and KMD. We would like to prove TX on B.
|
||||
* There is a notarisation, nA0, which will include TX via an MoM.
|
||||
* The notarisation nA0 must fall between 2 notarisations of B,
|
||||
* ie, nB0 and nB1. An MoMoM including this range is propagated to
|
||||
* B in notarisation receipt (backnotarisation) bnB2.
|
||||
*
|
||||
* A: TX bnA0
|
||||
* \ /
|
||||
* KMD: nB0 nA0 nB1 nB2
|
||||
* \ \ \
|
||||
* B: bnB0 bnB1 bnB2
|
||||
*/
|
||||
|
||||
// XXX: There are potential crashes wherever we access chainActive without a lock,
|
||||
// because it might be disconnecting blocks at the same time.
|
||||
|
||||
|
||||
int NOTARISATION_SCAN_LIMIT_BLOCKS = 1440;
|
||||
|
||||
|
||||
/* On KMD */
|
||||
uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeight,
|
||||
std::vector<uint256> &moms, uint256 &destNotarisationTxid)
|
||||
{
|
||||
/*
|
||||
* Notaries don't wait for confirmation on KMD before performing a backnotarisation,
|
||||
* but we need a determinable range that will encompass all merkle roots. Include MoMs
|
||||
* including the block height of the last notarisation until the height before the
|
||||
* previous notarisation.
|
||||
*
|
||||
* kmdHeight notarisations-0 notarisations-1
|
||||
* *********************|
|
||||
* > scan backwards >
|
||||
*/
|
||||
|
||||
if (targetCCid < 2)
|
||||
return uint256();
|
||||
|
||||
if (kmdHeight < 0 || kmdHeight > chainActive.Height())
|
||||
return uint256();
|
||||
|
||||
int seenOwnNotarisations = 0;
|
||||
|
||||
bool txscl = IsTXSCL(symbol);
|
||||
|
||||
for (int i=0; i<NOTARISATION_SCAN_LIMIT_BLOCKS; i++) {
|
||||
if (i > kmdHeight) break;
|
||||
NotarisationsInBlock notarisations;
|
||||
uint256 blockHash = *chainActive[kmdHeight-i]->phashBlock;
|
||||
if (!GetBlockNotarisations(blockHash, notarisations))
|
||||
continue;
|
||||
|
||||
// See if we have an own notarisation in this block
|
||||
BOOST_FOREACH(Notarisation& nota, notarisations) {
|
||||
if (strcmp(nota.second.symbol, symbol) == 0)
|
||||
{
|
||||
seenOwnNotarisations++;
|
||||
if (seenOwnNotarisations == 1)
|
||||
destNotarisationTxid = nota.first;
|
||||
else if (seenOwnNotarisations == 2)
|
||||
goto end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (seenOwnNotarisations == 1) {
|
||||
BOOST_FOREACH(Notarisation& nota, notarisations) {
|
||||
if (IsTXSCL(nota.second.symbol) == txscl)
|
||||
if (nota.second.ccId == targetCCid)
|
||||
moms.push_back(nota.second.MoM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return GetMerkleRoot(moms);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get a notarisation from a given height
|
||||
*
|
||||
* Will scan notarisations leveldb up to a limit
|
||||
*/
|
||||
template <typename IsTarget>
|
||||
int ScanNotarisationsFromHeight(int nHeight, const IsTarget f, Notarisation &found)
|
||||
{
|
||||
int limit = std::min(nHeight + NOTARISATION_SCAN_LIMIT_BLOCKS, chainActive.Height());
|
||||
|
||||
for (int h=nHeight; h<limit; h++) {
|
||||
NotarisationsInBlock notarisations;
|
||||
|
||||
if (!GetBlockNotarisations(*chainActive[h]->phashBlock, notarisations))
|
||||
continue;
|
||||
|
||||
BOOST_FOREACH(found, notarisations) {
|
||||
if (f(found)) {
|
||||
return h;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* On KMD */
|
||||
TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
|
||||
const TxProof assetChainProof)
|
||||
{
|
||||
/*
|
||||
* Here we are given a proof generated by an assetchain A which goes from given txid to
|
||||
* an assetchain MoM. We need to go from the notarisationTxid for A to the MoMoM range of the
|
||||
* backnotarisation for B (given by kmdheight of notarisation), find the MoM within the MoMs for
|
||||
* that range, and finally extend the proof to lead to the MoMoM (proof root).
|
||||
*/
|
||||
EvalRef eval;
|
||||
uint256 MoM = assetChainProof.second.Exec(txid);
|
||||
|
||||
// Get a kmd height for given notarisation Txid
|
||||
int kmdHeight;
|
||||
{
|
||||
CTransaction sourceNotarisation;
|
||||
uint256 hashBlock;
|
||||
CBlockIndex blockIdx;
|
||||
if (!eval->GetTxConfirmed(assetChainProof.first, sourceNotarisation, blockIdx))
|
||||
throw std::runtime_error("Notarisation not found");
|
||||
kmdHeight = blockIdx.nHeight;
|
||||
}
|
||||
|
||||
// We now have a kmdHeight of the notarisation from chain A. So we know that a MoM exists
|
||||
// at that height.
|
||||
// If we call CalculateProofRoot with that height, it'll scan backwards, until it finds
|
||||
// a notarisation from B, and it might not include our notarisation from A
|
||||
// at all. So, the thing we need to do is scan forwards to find the notarisation for B,
|
||||
// that is inclusive of A.
|
||||
Notarisation nota;
|
||||
auto isTarget = [&](Notarisation ¬a) {
|
||||
return strcmp(nota.second.symbol, targetSymbol) == 0;
|
||||
};
|
||||
kmdHeight = ScanNotarisationsFromHeight(kmdHeight, isTarget, nota);
|
||||
if (!kmdHeight)
|
||||
throw std::runtime_error("Cannot find notarisation for target inclusive of source");
|
||||
|
||||
// Get MoMs for kmd height and symbol
|
||||
std::vector<uint256> moms;
|
||||
uint256 targetChainNotarisationTxid;
|
||||
uint256 MoMoM = CalculateProofRoot(targetSymbol, targetCCid, kmdHeight, moms, targetChainNotarisationTxid);
|
||||
if (MoMoM.IsNull())
|
||||
throw std::runtime_error("No MoMs found");
|
||||
|
||||
// Find index of source MoM in MoMoM
|
||||
int nIndex;
|
||||
for (nIndex=0; nIndex<moms.size(); nIndex++) {
|
||||
if (moms[nIndex] == MoM)
|
||||
goto cont;
|
||||
}
|
||||
throw std::runtime_error("Couldn't find MoM within MoMoM set");
|
||||
cont:
|
||||
|
||||
// Create a branch
|
||||
std::vector<uint256> vBranch;
|
||||
{
|
||||
CBlock fakeBlock;
|
||||
for (int i=0; i<moms.size(); i++) {
|
||||
CTransaction fakeTx;
|
||||
// first value in CTransaction memory is it's hash
|
||||
memcpy((void*)&fakeTx, moms[i].begin(), 32);
|
||||
fakeBlock.vtx.push_back(fakeTx);
|
||||
}
|
||||
vBranch = fakeBlock.GetMerkleBranch(nIndex);
|
||||
}
|
||||
|
||||
// Concatenate branches
|
||||
MerkleBranch newBranch = assetChainProof.second;
|
||||
newBranch << MerkleBranch(nIndex, vBranch);
|
||||
|
||||
// Check proof
|
||||
if (newBranch.Exec(txid) != MoMoM)
|
||||
throw std::runtime_error("Proof check failed");
|
||||
|
||||
return std::make_pair(targetChainNotarisationTxid,newBranch);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Takes an importTx that has proof leading to assetchain root
|
||||
* and extends proof to cross chain root
|
||||
*/
|
||||
void CompleteImportTransaction(CTransaction &importTx)
|
||||
{
|
||||
TxProof proof;
|
||||
CTransaction burnTx;
|
||||
std::vector<CTxOut> payouts;
|
||||
if (!UnmarshalImportTx(importTx, proof, burnTx, payouts))
|
||||
throw std::runtime_error("Couldn't parse importTx");
|
||||
|
||||
std::string targetSymbol;
|
||||
uint32_t targetCCid;
|
||||
uint256 payoutsHash;
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash))
|
||||
throw std::runtime_error("Couldn't parse burnTx");
|
||||
|
||||
proof = GetCrossChainProof(burnTx.GetHash(), targetSymbol.data(), targetCCid, proof);
|
||||
|
||||
importTx = MakeImportCoinTransaction(proof, burnTx, payouts);
|
||||
}
|
||||
|
||||
|
||||
bool IsSameAssetChain(const Notarisation ¬a) {
|
||||
return strcmp(nota.second.symbol, ASSETCHAINS_SYMBOL) == 0;
|
||||
};
|
||||
|
||||
|
||||
/* On assetchain */
|
||||
bool GetNextBacknotarisation(uint256 kmdNotarisationTxid, Notarisation &out)
|
||||
{
|
||||
/*
|
||||
* Here we are given a txid, and a proof.
|
||||
* We go from the KMD notarisation txid to the backnotarisation,
|
||||
* then jump to the next backnotarisation, which contains the corresponding MoMoM.
|
||||
*/
|
||||
Notarisation bn;
|
||||
if (!GetBackNotarisation(kmdNotarisationTxid, bn))
|
||||
return false;
|
||||
|
||||
// Need to get block height of that backnotarisation
|
||||
EvalRef eval;
|
||||
CBlockIndex block;
|
||||
CTransaction tx;
|
||||
if (!eval->GetTxConfirmed(bn.first, tx, block)){
|
||||
fprintf(stderr, "Can't get height of backnotarisation, this should not happen\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) ScanNotarisationsFromHeight(block.nHeight+1, &IsSameAssetChain, out);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* On assetchain
|
||||
* in: txid
|
||||
* out: pair<notarisationTxHash,merkleBranch>
|
||||
*/
|
||||
TxProof GetAssetchainProof(uint256 hash)
|
||||
{
|
||||
int nIndex;
|
||||
CBlockIndex* blockIndex;
|
||||
Notarisation nota;
|
||||
std::vector<uint256> branch;
|
||||
|
||||
{
|
||||
uint256 blockHash;
|
||||
CTransaction tx;
|
||||
if (!GetTransaction(hash, tx, blockHash, true))
|
||||
throw std::runtime_error("cannot find transaction");
|
||||
|
||||
if (blockHash.IsNull())
|
||||
throw std::runtime_error("tx still in mempool");
|
||||
|
||||
blockIndex = mapBlockIndex[blockHash];
|
||||
int h = blockIndex->nHeight;
|
||||
// The assumption here is that the first notarisation for a height GTE than
|
||||
// the transaction block height will contain the corresponding MoM. If there
|
||||
// are sequence issues with the notarisations this may fail.
|
||||
auto isTarget = [&](Notarisation ¬a) {
|
||||
if (!IsSameAssetChain(nota)) return false;
|
||||
return nota.second.height >= blockIndex->nHeight;
|
||||
};
|
||||
if (!ScanNotarisationsFromHeight(blockIndex->nHeight, isTarget, nota))
|
||||
throw std::runtime_error("backnotarisation not yet confirmed");
|
||||
|
||||
// index of block in MoM leaves
|
||||
nIndex = nota.second.height - blockIndex->nHeight;
|
||||
}
|
||||
|
||||
// build merkle chain from blocks to MoM
|
||||
{
|
||||
std::vector<uint256> leaves, tree;
|
||||
for (int i=0; i<nota.second.MoMDepth; i++) {
|
||||
uint256 mRoot = chainActive[nota.second.height - i]->hashMerkleRoot;
|
||||
leaves.push_back(mRoot);
|
||||
}
|
||||
bool fMutated;
|
||||
BuildMerkleTree(&fMutated, leaves, tree);
|
||||
branch = GetMerkleBranch(nIndex, leaves.size(), tree);
|
||||
|
||||
// Check branch
|
||||
uint256 ourResult = SafeCheckMerkleBranch(blockIndex->hashMerkleRoot, branch, nIndex);
|
||||
if (nota.second.MoM != ourResult)
|
||||
throw std::runtime_error("Failed merkle block->MoM");
|
||||
}
|
||||
|
||||
// Now get the tx merkle branch
|
||||
{
|
||||
CBlock block;
|
||||
|
||||
if (fHavePruned && !(blockIndex->nStatus & BLOCK_HAVE_DATA) && blockIndex->nTx > 0)
|
||||
throw std::runtime_error("Block not available (pruned data)");
|
||||
|
||||
if(!ReadBlockFromDisk(block, blockIndex,1))
|
||||
throw std::runtime_error("Can't read block from disk");
|
||||
|
||||
// Locate the transaction in the block
|
||||
int nTxIndex;
|
||||
for (nTxIndex = 0; nTxIndex < (int)block.vtx.size(); nTxIndex++)
|
||||
if (block.vtx[nTxIndex].GetHash() == hash)
|
||||
break;
|
||||
|
||||
if (nTxIndex == (int)block.vtx.size())
|
||||
throw std::runtime_error("Error locating tx in block");
|
||||
|
||||
std::vector<uint256> txBranch = block.GetMerkleBranch(nTxIndex);
|
||||
|
||||
// Check branch
|
||||
if (block.hashMerkleRoot != CBlock::CheckMerkleBranch(hash, txBranch, nTxIndex))
|
||||
throw std::runtime_error("Failed merkle tx->block");
|
||||
|
||||
// concatenate branches
|
||||
nIndex = (nIndex << txBranch.size()) + nTxIndex;
|
||||
branch.insert(branch.begin(), txBranch.begin(), txBranch.end());
|
||||
}
|
||||
|
||||
// Check the proof
|
||||
if (nota.second.MoM != CBlock::CheckMerkleBranch(hash, branch, nIndex))
|
||||
throw std::runtime_error("Failed validating MoM");
|
||||
|
||||
// All done!
|
||||
CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION);
|
||||
return std::make_pair(nota.second.txHash, MerkleBranch(nIndex, branch));
|
||||
}
|
||||
21
src/crosschain.h
Normal file
21
src/crosschain.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef CROSSCHAIN_H
|
||||
#define CROSSCHAIN_H
|
||||
|
||||
#include "cc/eval.h"
|
||||
|
||||
|
||||
/* On assetchain */
|
||||
TxProof GetAssetchainProof(uint256 hash);
|
||||
|
||||
/* On KMD */
|
||||
uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeight,
|
||||
std::vector<uint256> &moms, uint256 &destNotarisationTxid);
|
||||
TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
|
||||
const TxProof assetChainProof);
|
||||
void CompleteImportTransaction(CTransaction &importTx);
|
||||
|
||||
/* On assetchain */
|
||||
bool GetNextBacknotarisation(uint256 txid, std::pair<uint256,NotarisationData> &bn);
|
||||
|
||||
|
||||
#endif /* CROSSCHAIN_H */
|
||||
@@ -1,3 +1,17 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "asn/Condition.h"
|
||||
#include "asn/Fulfillment.h"
|
||||
@@ -41,6 +55,7 @@ static void anonToJSON(const CC *cond, cJSON *params) {
|
||||
|
||||
static unsigned char *anonFingerprint(const CC *cond) {
|
||||
unsigned char *out = calloc(1, 32);
|
||||
fprintf(stderr,"anon fingerprint %p %p\n",out,cond->fingerprint);
|
||||
memcpy(out, cond->fingerprint, 32);
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "strings.h"
|
||||
#include "asn/Condition.h"
|
||||
#include "asn/Fulfillment.h"
|
||||
@@ -14,11 +29,7 @@
|
||||
#include "src/json_rpc.c"
|
||||
#include <cJSON.h>
|
||||
|
||||
#ifdef __LP64__
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#include <malloc.h> // Index into CTransaction.vjoinsplit
|
||||
#endif
|
||||
|
||||
|
||||
struct CCType *CCTypeRegistry[] = {
|
||||
@@ -60,8 +71,7 @@ char *cc_conditionUri(const CC *cond) {
|
||||
unsigned char *encoded = base64_encode(fp, 32);
|
||||
|
||||
unsigned char *out = calloc(1, 1000);
|
||||
sprintf(out, "ni:///sha-256;%s?fpt=%s&cost=%lu",
|
||||
encoded, cc_typeName(cond), cc_getCost(cond));
|
||||
sprintf(out, "ni:///sha-256;%s?fpt=%s&cost=%lu",encoded, cc_typeName(cond), cc_getCost(cond));
|
||||
|
||||
if (cond->type->getSubtypes) {
|
||||
appendUriSubtypes(cond->type->getSubtypes(cond), out);
|
||||
@@ -136,7 +146,6 @@ void asnCondition(const CC *cond, Condition_t *asn) {
|
||||
// This may look a little weird - we dont have a reference here to the correct
|
||||
// union choice for the condition type, so we just assign everything to the threshold
|
||||
// type. This works out nicely since the union choices have the same binary interface.
|
||||
|
||||
CompoundSha256Condition_t *choice = &asn->choice.thresholdSha256;
|
||||
choice->cost = cc_getCost(cond);
|
||||
choice->fingerprint.buf = cond->type->fingerprint(cond);
|
||||
@@ -184,7 +193,7 @@ CC *fulfillmentToCC(Fulfillment_t *ffill) {
|
||||
|
||||
CC *cc_readFulfillmentBinary(const unsigned char *ffill_bin, size_t ffill_bin_len) {
|
||||
CC *cond = 0;
|
||||
unsigned char *buf = malloc(ffill_bin_len);
|
||||
unsigned char *buf = calloc(1,ffill_bin_len);
|
||||
Fulfillment_t *ffill = 0;
|
||||
asn_dec_rval_t rval = ber_decode(0, &asn_DEF_Fulfillment, (void **)&ffill, ffill_bin, ffill_bin_len);
|
||||
if (rval.code != RC_OK) {
|
||||
@@ -221,12 +230,14 @@ int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength,
|
||||
const unsigned char *condBin, size_t condBinLength,
|
||||
VerifyEval verifyEval, void *evalContext) {
|
||||
unsigned char targetBinary[1000];
|
||||
//fprintf(stderr,"in cc_verify cond.%p msg.%p[%d] dohash.%d condbin.%p[%d]\n",cond,msg,(int32_t)msgLength,doHashMsg,condBin,(int32_t)condBinLength);
|
||||
const size_t binLength = cc_conditionBinary(cond, targetBinary);
|
||||
if (0 != memcmp(condBin, targetBinary, binLength)) {
|
||||
fprintf(stderr,"cc_verify error A\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cc_ed25519VerifyTree(cond, msg, msgLength)) {
|
||||
fprintf(stderr,"cc_verify error B\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -235,10 +246,12 @@ int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength,
|
||||
else memcpy(msgHash, msg, 32);
|
||||
|
||||
if (!cc_secp256k1VerifyTreeMsg32(cond, msgHash)) {
|
||||
fprintf(stderr,"cc_verify error C\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cc_verifyEval(cond, verifyEval, evalContext)) {
|
||||
//fprintf(stderr,"cc_verify error D\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "asn/Condition.h"
|
||||
#include "asn/Fulfillment.h"
|
||||
#include "asn/Ed25519FingerprintContents.h"
|
||||
@@ -12,6 +27,7 @@ struct CCType CC_Ed25519Type;
|
||||
|
||||
static unsigned char *ed25519Fingerprint(const CC *cond) {
|
||||
Ed25519FingerprintContents_t *fp = calloc(1, sizeof(Ed25519FingerprintContents_t));
|
||||
//fprintf(stderr,"ed25519 fingerprint %p %p\n",fp,cond->publicKey);
|
||||
OCTET_STRING_fromBuf(&fp->publicKey, cond->publicKey, 32);
|
||||
return hashFingerprintContents(&asn_DEF_Ed25519FingerprintContents, fp);
|
||||
}
|
||||
@@ -47,7 +63,7 @@ static int ed25519Sign(CC *cond, CCVisitor visitor) {
|
||||
if (cond->type->typeId != CC_Ed25519Type.typeId) return 1;
|
||||
CCEd25519SigningData *signing = (CCEd25519SigningData*) visitor.context;
|
||||
if (0 != memcmp(cond->publicKey, signing->pk, 32)) return 1;
|
||||
if (!cond->signature) cond->signature = malloc(64);
|
||||
if (!cond->signature) cond->signature = calloc(1,64);
|
||||
ed25519_sign(cond->signature, visitor.msg, visitor.msgLength,
|
||||
signing->pk, signing->skpk);
|
||||
signing->nSigned++;
|
||||
@@ -126,9 +142,9 @@ static void ed25519ToJSON(const CC *cond, cJSON *params) {
|
||||
|
||||
static CC *ed25519FromFulfillment(const Fulfillment_t *ffill) {
|
||||
CC *cond = cc_new(CC_Ed25519);
|
||||
cond->publicKey = malloc(32);
|
||||
cond->publicKey = calloc(1,32);
|
||||
memcpy(cond->publicKey, ffill->choice.ed25519Sha256.publicKey.buf, 32);
|
||||
cond->signature = malloc(64);
|
||||
cond->signature = calloc(1,64);
|
||||
memcpy(cond->signature, ffill->choice.ed25519Sha256.signature.buf, 64);
|
||||
return cond;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "asn/Condition.h"
|
||||
#include "asn/Fulfillment.h"
|
||||
#include "asn/EvalFulfillment.h"
|
||||
@@ -12,6 +27,7 @@ struct CCType CC_EvalType;
|
||||
|
||||
static unsigned char *evalFingerprint(const CC *cond) {
|
||||
unsigned char *hash = calloc(1, 32);
|
||||
//fprintf(stderr,"evalfingerprint %p %p\n",hash,cond->code);
|
||||
sha256(cond->code, cond->codeLength, hash);
|
||||
return hash;
|
||||
}
|
||||
@@ -53,7 +69,7 @@ static CC *evalFromFulfillment(const Fulfillment_t *ffill) {
|
||||
|
||||
OCTET_STRING_t octets = eval->code;
|
||||
cond->codeLength = octets.size;
|
||||
cond->code = malloc(octets.size);
|
||||
cond->code = calloc(1,octets.size);
|
||||
memcpy(cond->code, octets.buf, octets.size);
|
||||
|
||||
return cond;
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include <Condition.h>
|
||||
#include <Fulfillment.h>
|
||||
#include "include/cJSON.h"
|
||||
@@ -13,7 +28,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define BUF_SIZE 1024 * 1024
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
typedef char bool;
|
||||
|
||||
@@ -41,8 +56,8 @@ typedef struct CCType {
|
||||
/*
|
||||
* Globals
|
||||
*/
|
||||
struct CCType *CCTypeRegistry[32];
|
||||
int CCTypeRegistryLength;
|
||||
extern struct CCType *CCTypeRegistry[];
|
||||
extern int CCTypeRegistryLength;
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "cryptoconditions.h"
|
||||
#include "internal.h"
|
||||
#include <cJSON.h>
|
||||
|
||||
#ifdef __LP64__
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#include <malloc.h> // Index into CTransaction.vjoinsplit
|
||||
#endif
|
||||
|
||||
|
||||
static cJSON *jsonCondition(CC *cond) {
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "asn/Condition.h"
|
||||
#include "asn/Fulfillment.h"
|
||||
@@ -12,7 +26,7 @@ struct CCType CC_PrefixType;
|
||||
|
||||
static int prefixVisitChildren(CC *cond, CCVisitor visitor) {
|
||||
size_t prefixedLength = cond->prefixLength + visitor.msgLength;
|
||||
unsigned char *prefixed = malloc(prefixedLength);
|
||||
unsigned char *prefixed = calloc(1,prefixedLength);
|
||||
memcpy(prefixed, cond->prefix, cond->prefixLength);
|
||||
memcpy(prefixed + cond->prefixLength, visitor.msg, visitor.msgLength);
|
||||
visitor.msg = prefixed;
|
||||
@@ -25,6 +39,7 @@ static int prefixVisitChildren(CC *cond, CCVisitor visitor) {
|
||||
|
||||
static unsigned char *prefixFingerprint(const CC *cond) {
|
||||
PrefixFingerprintContents_t *fp = calloc(1, sizeof(PrefixFingerprintContents_t));
|
||||
//fprintf(stderr,"prefixfinger %p %p\n",fp,cond->prefix);
|
||||
asnCondition(cond->subcondition, &fp->subcondition); // TODO: check asnCondition for safety
|
||||
fp->maxMessageLength = cond->maxMessageLength;
|
||||
OCTET_STRING_fromBuf(&fp->prefix, cond->prefix, cond->prefixLength);
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "asn/Condition.h"
|
||||
#include "asn/Fulfillment.h"
|
||||
@@ -32,6 +46,7 @@ static unsigned long preimageCost(const CC *cond) {
|
||||
|
||||
static unsigned char *preimageFingerprint(const CC *cond) {
|
||||
unsigned char *hash = calloc(1, 32);
|
||||
//fprintf(stderr,"preimage %p %p\n",hash,cond->preimage);
|
||||
sha256(cond->preimage, cond->preimageLength, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -45,9 +45,11 @@ void lockSign() {
|
||||
int read = (int) fread(&ent, 1, 32, fp);
|
||||
fclose(fp);
|
||||
#endif
|
||||
if (read != 32) {
|
||||
fprintf(stderr, "Could not read 32 bytes entropy from system\n");
|
||||
exit(1);
|
||||
if (read != 32)
|
||||
{
|
||||
int32_t i;
|
||||
for (i=0; i<32; i++)
|
||||
((uint8_t *)ent)[i] = rand();
|
||||
}
|
||||
if (!secp256k1_context_randomize(ec_ctx_sign, ent)) {
|
||||
fprintf(stderr, "Could not randomize secp256k1 context\n");
|
||||
@@ -73,6 +75,7 @@ void initVerify() {
|
||||
|
||||
static unsigned char *secp256k1Fingerprint(const CC *cond) {
|
||||
Secp256k1FingerprintContents_t *fp = calloc(1, sizeof(Secp256k1FingerprintContents_t));
|
||||
//fprintf(stderr,"secpfinger %p %p size %d vs %d\n",fp,cond->publicKey,(int32_t)sizeof(Secp256k1FingerprintContents_t),(int32_t)SECP256K1_PK_SIZE);
|
||||
OCTET_STRING_fromBuf(&fp->publicKey, cond->publicKey, SECP256K1_PK_SIZE);
|
||||
return hashFingerprintContents(&asn_DEF_Secp256k1FingerprintContents, fp);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "asn/Condition.h"
|
||||
#include "asn/Fulfillment.h"
|
||||
@@ -72,6 +86,7 @@ static int cmpConditionBin(const void *a, const void *b) {
|
||||
static unsigned char *thresholdFingerprint(const CC *cond) {
|
||||
/* Create fingerprint */
|
||||
ThresholdFingerprintContents_t *fp = calloc(1, sizeof(ThresholdFingerprintContents_t));
|
||||
//fprintf(stderr,"thresholdfinger %p\n",fp);
|
||||
fp->threshold = cond->threshold;
|
||||
for (int i=0; i<cond->size; i++) {
|
||||
Condition_t *asnCond = asnConditionNew(cond->subconditions[i]);
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/******************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -24,7 +39,7 @@ static int mod_table[] = {0, 2, 1};
|
||||
|
||||
|
||||
void build_decoding_table() {
|
||||
decoding_table = malloc(256);
|
||||
decoding_table = calloc(1,256);
|
||||
for (int i = 0; i < 64; i++)
|
||||
decoding_table[(unsigned char) encoding_table[i]] = i;
|
||||
}
|
||||
@@ -34,7 +49,7 @@ unsigned char *base64_encode(const unsigned char *data, size_t input_length) {
|
||||
|
||||
size_t output_length = 4 * ((input_length + 2) / 3);
|
||||
|
||||
unsigned char *encoded_data = malloc(output_length + 1);
|
||||
unsigned char *encoded_data = calloc(1,output_length + 1);
|
||||
if (encoded_data == NULL) return NULL;
|
||||
|
||||
for (int i = 0, j = 0; i < input_length;) {
|
||||
@@ -75,7 +90,7 @@ unsigned char *base64_decode(const unsigned char *data_,
|
||||
|
||||
size_t input_length = strlen(data_);
|
||||
int rem = input_length % 4;
|
||||
unsigned char *data = malloc(input_length + (4-rem));
|
||||
unsigned char *data = calloc(1,input_length + (4-rem));
|
||||
strcpy(data, data_);
|
||||
|
||||
// for unpadded b64
|
||||
@@ -96,7 +111,7 @@ unsigned char *base64_decode(const unsigned char *data_,
|
||||
if (data[input_length - 1] == '=') (*output_length)--;
|
||||
if (data[input_length - 2] == '=') (*output_length)--;
|
||||
|
||||
unsigned char *decoded_data = malloc(*output_length);
|
||||
unsigned char *decoded_data = calloc(1,*output_length);
|
||||
if (decoded_data == NULL) return NULL;
|
||||
|
||||
for (int i = 0, j = 0; i < input_length;) {
|
||||
@@ -122,6 +137,7 @@ unsigned char *base64_decode(const unsigned char *data_,
|
||||
|
||||
void base64_cleanup() {
|
||||
free(decoding_table);
|
||||
decoding_table = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +218,7 @@ unsigned char *hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp)
|
||||
fprintf(stderr, "Encoding fingerprint failed\n");
|
||||
return 0;
|
||||
}
|
||||
unsigned char *hash = malloc(32);
|
||||
unsigned char *hash = calloc(1,32);
|
||||
sha256(buf, rc.encoded, hash);
|
||||
return hash;
|
||||
}
|
||||
@@ -210,7 +226,7 @@ unsigned char *hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp)
|
||||
|
||||
char* cc_hex_encode(const uint8_t *bin, size_t len)
|
||||
{
|
||||
char* hex = malloc(len*2+1);
|
||||
char* hex = calloc(1,len*2+1);
|
||||
if (bin == NULL) return hex;
|
||||
char map[16] = "0123456789ABCDEF";
|
||||
for (int i=0; i<len; i++) {
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
#define ZCASH_DEPRECATION_H
|
||||
|
||||
// Deprecation policy:
|
||||
// * Shut down 16 weeks' worth of blocks after the estimated release block height.
|
||||
// * A warning is shown during the 2 weeks' worth of blocks prior to shut down.
|
||||
static const int APPROX_RELEASE_HEIGHT = 800000;
|
||||
// * Shut down WEEKS_UNTIL_DEPRECATION weeks' worth of blocks after the estimated release block height.
|
||||
// * A warning is shown during the DEPRECATION_WARN_LIMIT worth of blocks prior to shut down.
|
||||
static const int WEEKS_UNTIL_DEPRECATION = 52;
|
||||
static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24);
|
||||
static const int DEPRECATION_HEIGHT = 1400000;
|
||||
static const int APPROX_RELEASE_HEIGHT = DEPRECATION_HEIGHT - (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 60);
|
||||
|
||||
// Number of blocks before deprecation to warn users
|
||||
static const int DEPRECATION_WARN_LIMIT = 60 * 24 * 60; // 2 months
|
||||
|
||||
@@ -33,6 +33,10 @@ curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dp
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"DSEC\",\"pubkey\":\"$pubkey\"}"
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"GLXT\",\"pubkey\":\"$pubkey\"}"
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"EQL\",\"pubkey\":\"$pubkey\"}"
|
||||
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"ZILLA\",\"pubkey\":\"$pubkey\"}"
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CHIPS\",\"pubkey\":\"$pubkey\"}"
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"GAME\",\"freq\":5,\"pubkey\":\"$pubkey\"}"
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"RFOX\",\"freq\":10,\"pubkey\":\"$pubkey\"}"
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"VRSC\",\"freq\":10,\"pubkey\":\"$pubkey\"}"
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"SEC\",\"pubkey\":\"$pubkey\"}"
|
||||
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CCL\",\"pubkey\":\"$pubkey\"}"
|
||||
|
||||
38
src/fiat-cli
38
src/fiat-cli
@@ -1,32 +1,8 @@
|
||||
#!/bin/bash
|
||||
#set -x
|
||||
echo revs; fiat/revs $1 $2 $3 $4
|
||||
echo supernet; fiat/supernet $1 $2 $3 $4
|
||||
echo dex; fiat/dex $1 $2 $3 $4
|
||||
echo pangea; fiat/pangea $1 $2 $3 $4
|
||||
echo jumblr; fiat/jumblr $1 $2 $3 $4
|
||||
echo bet; fiat/bet $1 $2 $3 $4
|
||||
echo crypto; fiat/crypto $1 $2 $3 $4
|
||||
echo hodl; fiat/hodl $1 $2 $3 $4
|
||||
echo mshark; fiat/mshark $1 $2 $3 $4
|
||||
echo bots; fiat/bots $1 $2 $3 $4
|
||||
echo mgw; fiat/mgw $1 $2 $3 $4
|
||||
echo coqui; fiat/coqui $1 $2 $3 $4
|
||||
echo wlc; fiat/wlc $1 $2 $3 $4
|
||||
echo kv; fiat/kv $1 $2 $3 $4
|
||||
echo ceal; fiat/ceal $1 $2 $3 $4
|
||||
echo mesh; fiat/mesh $1 $2 $3 $4
|
||||
echo mnz; fiat/mnz $1 $2 $3 $4
|
||||
echo axo; fiat/axo $1 $2 $3 $4
|
||||
echo etomic; fiat/etomic $1 $2 $3 $4
|
||||
echo btch; fiat/btch $1 $2 $3 $4
|
||||
echo pizza; fiat/pizza $1 $2 $3 $4
|
||||
echo beer; fiat/beer $1 $2 $3 $4
|
||||
echo ninja; fiat/ninja $1 $2 $3 $4
|
||||
echo oot; fiat/oot $1 $2 $3 $4
|
||||
echo bntn; fiat/bntn $1 $2 $3 $4
|
||||
echo chain; fiat/chain $1 $2 $3 $4
|
||||
echo prlpay; fiat/prlpay $1 $2 $3 $4
|
||||
echo dsec; fiat/dsec $1 $2 $3 $4
|
||||
echo glxt; fiat/glxt $1 $2 $3 $4
|
||||
echo eql; fiat/eql $1 $2 $3 $4
|
||||
|
||||
args="$@"
|
||||
|
||||
./listassetchains | while read chain; do
|
||||
echo $chain
|
||||
./komodo-cli --ac_name=$chain $args
|
||||
done
|
||||
|
||||
2
src/fiat/ccl
Executable file
2
src/fiat/ccl
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=CCL $1 $2 $3 $4 $5 $6
|
||||
2
src/fiat/rfox
Executable file
2
src/fiat/rfox
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=RFOX $1 $2 $3 $4 $5 $6
|
||||
2
src/fiat/sec
Executable file
2
src/fiat/sec
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=SEC $1 $2 $3 $4 $5 $6
|
||||
2
src/fiat/vrsc
Executable file
2
src/fiat/vrsc
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=VRSC $1 $2 $3 $4 $5 $6
|
||||
2
src/fiat/zilla
Executable file
2
src/fiat/zilla
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=ZILLA $1 $2 $3 $4 $5 $6
|
||||
121
src/importcoin.cpp
Normal file
121
src/importcoin.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "crosschain.h"
|
||||
#include "importcoin.h"
|
||||
#include "cc/utils.h"
|
||||
#include "coins.h"
|
||||
#include "hash.h"
|
||||
#include "script/cc.h"
|
||||
#include "primitives/transaction.h"
|
||||
|
||||
|
||||
CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector<CTxOut> payouts)
|
||||
{
|
||||
std::vector<uint8_t> payload = E_MARSHAL(ss << EVAL_IMPORTCOIN);
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), CScript() << payload));
|
||||
mtx.vout = payouts;
|
||||
auto importData = E_MARSHAL(ss << proof; ss << burnTx);
|
||||
mtx.vout.insert(mtx.vout.begin(), CTxOut(0, CScript() << OP_RETURN << importData));
|
||||
return CTransaction(mtx);
|
||||
}
|
||||
|
||||
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts)
|
||||
{
|
||||
std::vector<uint8_t> opret = E_MARSHAL(ss << VARINT(targetCCid);
|
||||
ss << targetSymbol;
|
||||
ss << SerializeHash(payouts));
|
||||
return CTxOut(value, CScript() << OP_RETURN << opret);
|
||||
}
|
||||
|
||||
|
||||
bool UnmarshalImportTx(const CTransaction &importTx, TxProof &proof, CTransaction &burnTx,
|
||||
std::vector<CTxOut> &payouts)
|
||||
{
|
||||
std::vector<uint8_t> vData;
|
||||
GetOpReturnData(importTx.vout[0].scriptPubKey, vData);
|
||||
if (importTx.vout.size() < 1) return false;
|
||||
payouts = std::vector<CTxOut>(importTx.vout.begin()+1, importTx.vout.end());
|
||||
return importTx.vin.size() == 1 &&
|
||||
importTx.vin[0].scriptSig == (CScript() << E_MARSHAL(ss << EVAL_IMPORTCOIN)) &&
|
||||
E_UNMARSHAL(vData, ss >> proof; ss >> burnTx);
|
||||
}
|
||||
|
||||
|
||||
bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash)
|
||||
{
|
||||
std::vector<uint8_t> burnOpret;
|
||||
if (burnTx.vout.size() == 0) return false;
|
||||
GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret);
|
||||
return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid);
|
||||
ss >> targetSymbol;
|
||||
ss >> payoutsHash);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Required by main
|
||||
*/
|
||||
CAmount GetCoinImportValue(const CTransaction &tx)
|
||||
{
|
||||
TxProof proof;
|
||||
CTransaction burnTx;
|
||||
std::vector<CTxOut> payouts;
|
||||
if (UnmarshalImportTx(tx, proof, burnTx, payouts)) {
|
||||
return burnTx.vout.size() ? burnTx.vout.back().nValue : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CoinImport is different enough from normal script execution that it's not worth
|
||||
* making all the mods neccesary in the interpreter to do the dispatch correctly.
|
||||
*/
|
||||
bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& checker, CValidationState &state)
|
||||
{
|
||||
auto pc = scriptSig.begin();
|
||||
opcodetype opcode;
|
||||
std::vector<uint8_t> evalScript;
|
||||
|
||||
auto f = [&] () {
|
||||
if (!scriptSig.GetOp(pc, opcode, evalScript))
|
||||
return false;
|
||||
if (pc != scriptSig.end())
|
||||
return false;
|
||||
if (evalScript.size() == 0)
|
||||
return false;
|
||||
if (evalScript.begin()[0] != EVAL_IMPORTCOIN)
|
||||
return false;
|
||||
// Ok, all looks good so far...
|
||||
CC *cond = CCNewEval(evalScript);
|
||||
bool out = checker.CheckEvalCondition(cond);
|
||||
cc_free(cond);
|
||||
return out;
|
||||
};
|
||||
|
||||
return f() ? true : state.Invalid(false, 0, "invalid-coin-import");
|
||||
}
|
||||
|
||||
|
||||
void AddImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs, int nHeight)
|
||||
{
|
||||
uint256 burnHash = importTx.vin[0].prevout.hash;
|
||||
CCoinsModifier modifier = inputs.ModifyCoins(burnHash);
|
||||
modifier->nHeight = nHeight;
|
||||
modifier->nVersion = 1;
|
||||
modifier->vout.push_back(CTxOut(0, CScript() << OP_0));
|
||||
}
|
||||
|
||||
|
||||
void RemoveImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs)
|
||||
{
|
||||
uint256 burnHash = importTx.vin[0].prevout.hash;
|
||||
inputs.ModifyCoins(burnHash)->Clear();
|
||||
}
|
||||
|
||||
|
||||
int ExistsImportTombstone(const CTransaction &importTx, const CCoinsViewCache &inputs)
|
||||
{
|
||||
uint256 burnHash = importTx.vin[0].prevout.hash;
|
||||
return inputs.HaveCoins(burnHash);
|
||||
}
|
||||
28
src/importcoin.h
Normal file
28
src/importcoin.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef IMPORTCOIN_H
|
||||
#define IMPORTCOIN_H
|
||||
|
||||
#include "cc/eval.h"
|
||||
#include "coins.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "script/interpreter.h"
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
|
||||
CAmount GetCoinImportValue(const CTransaction &tx);
|
||||
|
||||
CTransaction MakeImportCoinTransaction(const TxProof proof,
|
||||
const CTransaction burnTx, const std::vector<CTxOut> payouts);
|
||||
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts);
|
||||
|
||||
bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash);
|
||||
bool UnmarshalImportTx(const CTransaction &importTx, TxProof &proof, CTransaction &burnTx,
|
||||
std::vector<CTxOut> &payouts);
|
||||
|
||||
bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& checker, CValidationState &state);
|
||||
|
||||
void AddImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs, int nHeight);
|
||||
void RemoveImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs);
|
||||
int ExistsImportTombstone(const CTransaction &importTx, const CCoinsViewCache &inputs);
|
||||
|
||||
#endif /* IMPORTCOIN_H */
|
||||
15
src/init.cpp
15
src/init.cpp
@@ -21,6 +21,7 @@
|
||||
#include "httpserver.h"
|
||||
#include "httprpc.h"
|
||||
#include "key.h"
|
||||
#include "notarisationdb.h"
|
||||
#include "main.h"
|
||||
#include "metrics.h"
|
||||
#include "miner.h"
|
||||
@@ -498,7 +499,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
#ifdef ENABLE_MINING
|
||||
strUsage += HelpMessageGroup(_("Mining options:"));
|
||||
strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0));
|
||||
strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1));
|
||||
strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 0));
|
||||
strUsage += HelpMessageOpt("-equihashsolver=<name>", _("Specify the Equihash solver to be used if enabled (default: \"default\")"));
|
||||
strUsage += HelpMessageOpt("-mineraddress=<addr>", _("Send mined coins to a specific single address"));
|
||||
strUsage += HelpMessageOpt("-minetolocalwallet", strprintf(
|
||||
@@ -1413,11 +1414,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
delete pcoinsdbview;
|
||||
delete pcoinscatcher;
|
||||
delete pblocktree;
|
||||
delete pnotarisations;
|
||||
|
||||
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex, dbCompression, dbMaxOpenFiles);
|
||||
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
|
||||
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
|
||||
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
|
||||
pnotarisations = new NotarisationDB(100*1024*1024, false, fReindex);
|
||||
|
||||
|
||||
if (fReindex) {
|
||||
pblocktree->WriteReindexing(true);
|
||||
@@ -1752,19 +1756,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
|
||||
StartNode(threadGroup, scheduler);
|
||||
|
||||
// Monitor the chain, and alert if we get blocks much quicker or slower than expected
|
||||
int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing;
|
||||
CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload,
|
||||
boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing);
|
||||
scheduler.scheduleEvery(f, nPowTargetSpacing);
|
||||
|
||||
#ifdef ENABLE_MINING
|
||||
// Generate coins in the background
|
||||
#ifdef ENABLE_WALLET
|
||||
if (pwalletMain || !GetArg("-mineraddress", "").empty())
|
||||
GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1));
|
||||
GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 0));
|
||||
#else
|
||||
GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1));
|
||||
GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 0));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
20
src/komodo.h
20
src/komodo.h
@@ -311,7 +311,7 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long
|
||||
{
|
||||
if ( memread(opret,olen,filedata,&fpos,datalen) != olen )
|
||||
errs++;
|
||||
if ( 1 && ASSETCHAINS_SYMBOL[0] != 0 && matched != 0 )
|
||||
if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && matched != 0 )
|
||||
{
|
||||
int32_t i; for (i=0; i<olen; i++)
|
||||
printf("%02x",opret[i]);
|
||||
@@ -427,7 +427,7 @@ void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotar
|
||||
errs++;
|
||||
if ( fwrite(opretbuf,1,olen,fp) != olen )
|
||||
errs++;
|
||||
printf("create ht.%d R opret[%d] sp.%p\n",height,olen,sp);
|
||||
//printf("create ht.%d R opret[%d] sp.%p\n",height,olen,sp);
|
||||
//komodo_opreturn(height,opretvalue,opretbuf,olen,txhash,vout);
|
||||
komodo_eventadd_opreturn(sp,symbol,height,txhash,opretvalue,vout,opretbuf,olen);
|
||||
}
|
||||
@@ -538,7 +538,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr
|
||||
return(-1);
|
||||
if ( scriptlen == 35 && scriptbuf[0] == 33 && scriptbuf[34] == 0xac )
|
||||
{
|
||||
if ( i == 0 && j == 0 && memcmp(NOTARY_PUBKEY33,scriptbuf+1,33) == 0 && NOTARY_PUBKEY33[0] != 0 )
|
||||
if ( i == 0 && j == 0 && memcmp(NOTARY_PUBKEY33,scriptbuf+1,33) == 0 && IS_KOMODO_NOTARY != 0 )
|
||||
{
|
||||
printf("%s KOMODO_LASTMINED.%d -> %d\n",ASSETCHAINS_SYMBOL,KOMODO_LASTMINED,height);
|
||||
prevKOMODO_LASTMINED = KOMODO_LASTMINED;
|
||||
@@ -600,7 +600,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr
|
||||
{
|
||||
if ( scriptbuf[len] == 'K' )
|
||||
{
|
||||
fprintf(stderr,"i.%d j.%d KV OPRET len.%d %.8f\n",i,j,opretlen,dstr(value));
|
||||
//fprintf(stderr,"i.%d j.%d KV OPRET len.%d %.8f\n",i,j,opretlen,dstr(value));
|
||||
komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen,j,zero,0);
|
||||
return(-1);
|
||||
}
|
||||
@@ -823,7 +823,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
komodo_event_rewind(sp,symbol,pindex->nHeight);
|
||||
komodo_stateupdate(pindex->nHeight,0,0,0,zero,0,0,0,0,-pindex->nHeight,pindex->nTime,0,0,0,0,zero,0);
|
||||
}
|
||||
komodo_currentheight_set(chainActive.Tip()->nHeight);
|
||||
komodo_currentheight_set(chainActive.LastTip()->nHeight);
|
||||
if ( pindex != 0 )
|
||||
{
|
||||
height = pindex->nHeight;
|
||||
@@ -879,7 +879,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
}
|
||||
notarized = 1;
|
||||
}
|
||||
if ( NOTARY_PUBKEY33[0] != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
if ( IS_KOMODO_NOTARY != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
printf("(tx.%d: ",i);
|
||||
for (j=0; j<numvouts; j++)
|
||||
{
|
||||
@@ -897,7 +897,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
if ( NOTARY_PUBKEY33[0] != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
if ( IS_KOMODO_NOTARY != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
printf("%.8f ",dstr(block.vtx[i].vout[j].nValue));
|
||||
len = block.vtx[i].vout[j].scriptPubKey.size();
|
||||
if ( len >= sizeof(uint32_t) && len <= sizeof(scriptbuf) )
|
||||
@@ -907,7 +907,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
#else
|
||||
memcpy(scriptbuf,(uint8_t *)&block.vtx[i].vout[j].scriptPubKey[0],len);
|
||||
#endif
|
||||
notaryid = komodo_voutupdate(&isratification,notaryid,scriptbuf,len,height,txhash,i,j,&voutmask,&specialtx,¬arizedheight,(uint64_t)block.vtx[i].vout[j].nValue,notarized,signedmask,(uint32_t)chainActive.Tip()->GetBlockTime());
|
||||
notaryid = komodo_voutupdate(&isratification,notaryid,scriptbuf,len,height,txhash,i,j,&voutmask,&specialtx,¬arizedheight,(uint64_t)block.vtx[i].vout[j].nValue,notarized,signedmask,(uint32_t)chainActive.LastTip()->GetBlockTime());
|
||||
if ( 0 && i > 0 )
|
||||
{
|
||||
for (k=0; k<len; k++)
|
||||
@@ -916,7 +916,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( NOTARY_PUBKEY33[0] != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
if ( IS_KOMODO_NOTARY != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
printf(") ");
|
||||
if ( 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
printf("[%s] ht.%d txi.%d signedmask.%llx numvins.%d numvouts.%d notarized.%d special.%d isratification.%d\n",ASSETCHAINS_SYMBOL,height,i,(long long)signedmask,numvins,numvouts,notarized,specialtx,isratification);
|
||||
@@ -959,7 +959,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( NOTARY_PUBKEY33[0] != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
if ( IS_KOMODO_NOTARY != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
printf("%s ht.%d\n",ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL,height);
|
||||
if ( pindex->nHeight == hwmheight )
|
||||
komodo_stateupdate(height,0,0,0,zero,0,0,0,0,height,(uint32_t)pindex->nTime,0,0,0,0,zero,0);
|
||||
|
||||
@@ -567,7 +567,7 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
|
||||
#endif
|
||||
hashBlock, true))
|
||||
{
|
||||
fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
|
||||
//fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
|
||||
return(0);
|
||||
}
|
||||
//fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
|
||||
@@ -580,6 +580,56 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
|
||||
return(tx.nLockTime);
|
||||
}
|
||||
|
||||
uint32_t komodo_txtime2(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
|
||||
{
|
||||
CTxDestination address; CBlockIndex *pindex; CTransaction tx; uint256 hashBlock; uint32_t txtime = 0;
|
||||
*valuep = 0;
|
||||
if (!GetTransaction(hash, tx,
|
||||
#ifndef KOMODO_ZCASH
|
||||
Params().GetConsensus(),
|
||||
#endif
|
||||
hashBlock, true))
|
||||
{
|
||||
//fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
|
||||
return(0);
|
||||
}
|
||||
if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
|
||||
txtime = pindex->nTime;
|
||||
else txtime = tx.nLockTime;
|
||||
//fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
|
||||
if ( n < tx.vout.size() )
|
||||
{
|
||||
*valuep = tx.vout[n].nValue;
|
||||
if (ExtractDestination(tx.vout[n].scriptPubKey, address))
|
||||
strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
|
||||
}
|
||||
return(txtime);
|
||||
}
|
||||
|
||||
int32_t komodo_isPoS(CBlock *pblock)
|
||||
{
|
||||
int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid;
|
||||
if ( ASSETCHAINS_STAKED != 0 )
|
||||
{
|
||||
if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 )
|
||||
{
|
||||
txid = pblock->vtx[n-1].vin[0].prevout.hash;
|
||||
vout = pblock->vtx[n-1].vin[0].prevout.n;
|
||||
txtime = komodo_txtime(&value,txid,vout,destaddr);
|
||||
if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) )
|
||||
{
|
||||
strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
|
||||
if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[n-1].vout[0].nValue == value )
|
||||
{
|
||||
//fprintf(stderr,"is PoS block!\n");
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void komodo_disconnect(CBlockIndex *pindex,CBlock& block)
|
||||
{
|
||||
char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
|
||||
@@ -626,7 +676,7 @@ int32_t komodo_block2height(CBlock *block)
|
||||
if ( height2 >= 0 )
|
||||
return(height2);
|
||||
}
|
||||
if ( block->vtx[0].vin.size() > 0 )
|
||||
if ( block != 0 && block->vtx[0].vin.size() > 0 )
|
||||
{
|
||||
#ifdef KOMODO_ZCASH
|
||||
ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data();
|
||||
@@ -701,8 +751,8 @@ int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
|
||||
|
||||
uint32_t komodo_chainactive_timestamp()
|
||||
{
|
||||
if ( chainActive.Tip() != 0 )
|
||||
return((uint32_t)chainActive.Tip()->GetBlockTime());
|
||||
if ( chainActive.LastTip() != 0 )
|
||||
return((uint32_t)chainActive.LastTip()->GetBlockTime());
|
||||
else return(0);
|
||||
}
|
||||
|
||||
@@ -710,11 +760,11 @@ CBlockIndex *komodo_chainactive(int32_t height)
|
||||
{
|
||||
if ( chainActive.Tip() != 0 )
|
||||
{
|
||||
if ( height <= chainActive.Tip()->nHeight )
|
||||
if ( height <= chainActive.LastTip()->nHeight )
|
||||
return(chainActive[height]);
|
||||
// else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.Tip()->nHeight);
|
||||
// else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.LastTip()->nHeight);
|
||||
}
|
||||
//fprintf(stderr,"komodo_chainactive null chainActive.Tip() height %d\n",height);
|
||||
//fprintf(stderr,"komodo_chainactive null chainActive.LastTip() height %d\n",height);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -944,7 +994,7 @@ int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,in
|
||||
int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
|
||||
{
|
||||
int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
|
||||
if ( (pindex= chainActive.Tip()) == 0 )
|
||||
if ( (pindex= chainActive.LastTip()) == 0 )
|
||||
return(-1);
|
||||
notarized_height = komodo_notarizeddata(pindex->nHeight,¬arized_hash,¬arized_desttxid);
|
||||
*notarized_heightp = notarized_height;
|
||||
@@ -986,7 +1036,7 @@ uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_
|
||||
*valuep = tx.vout[n].nValue;
|
||||
*txheightp = pindex->nHeight;
|
||||
*txheighttimep = pindex->nTime;
|
||||
if ( *tiptimep == 0 && (tipindex= chainActive.Tip()) != 0 )
|
||||
if ( *tiptimep == 0 && (tipindex= chainActive.LastTip()) != 0 )
|
||||
*tiptimep = (uint32_t)tipindex->nTime;
|
||||
locktime = tx.nLockTime;
|
||||
//fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
|
||||
@@ -1019,7 +1069,7 @@ int32_t komodo_isrealtime(int32_t *kmdheightp)
|
||||
if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 )
|
||||
*kmdheightp = sp->CURRENT_HEIGHT;
|
||||
else *kmdheightp = 0;
|
||||
if ( (pindex= chainActive.Tip()) != 0 && pindex->nHeight >= (int32_t)komodo_longestchain() )
|
||||
if ( (pindex= chainActive.LastTip()) != 0 && pindex->nHeight >= (int32_t)komodo_longestchain() )
|
||||
return(1);
|
||||
else return(0);
|
||||
}
|
||||
@@ -1054,9 +1104,7 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_
|
||||
|
||||
commission must be in coinbase.vout[1] and must be >= 10000 sats
|
||||
PoS stake must be without txfee and in the last tx in the block at vout[0]
|
||||
PoW mining on PoS chain must solve a harder diff that adjusts, but never less than KOMODO_POWMINMULT
|
||||
*/
|
||||
#define KOMODO_POWMINMULT 16
|
||||
|
||||
uint64_t komodo_commission(const CBlock *pblock)
|
||||
{
|
||||
@@ -1086,72 +1134,149 @@ uint32_t komodo_segid32(char *coinaddr)
|
||||
return(addrhash.uints[0]);
|
||||
}
|
||||
|
||||
uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr)
|
||||
int8_t komodo_segid(int32_t nocache,int32_t height)
|
||||
{
|
||||
CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int64_t diff=0; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN;
|
||||
txtime = komodo_txtime(&value,txid,vout,address);
|
||||
if ( blocktime < prevtime+57 )
|
||||
blocktime = prevtime+57;
|
||||
if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
|
||||
CTxDestination voutaddress; CBlock block; CBlockIndex *pindex; uint64_t value; uint32_t txtime; char voutaddr[64],destaddr[64]; int32_t txn_count,vout; uint256 txid; int8_t segid = -1;
|
||||
if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
|
||||
return(0);
|
||||
}
|
||||
if ( (minage= nHeight*3) > 6000 )
|
||||
minage = 6000;
|
||||
pindex = 0;
|
||||
if ( (pindex= komodo_chainactive(nHeight>200?nHeight-200:1)) != 0 )
|
||||
{
|
||||
vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
|
||||
segid = ((nHeight + addrhash.uints[0]) & 0x3f);
|
||||
pasthash = pindex->GetBlockHash();
|
||||
memcpy(hashbuf,&pasthash,sizeof(pasthash));
|
||||
memcpy(&hashbuf[sizeof(pasthash)],&addrhash,sizeof(addrhash));
|
||||
vcalc_sha256(0,(uint8_t *)&hash,hashbuf,(int32_t)sizeof(uint256)*2);
|
||||
//fprintf(stderr,"(%s) vs. (%s) %s %.8f txtime.%u\n",address,destaddr,hash.ToString().c_str(),dstr(value),txtime);
|
||||
for (iter=0; iter<3600; iter++)
|
||||
if ( nocache == 0 && pindex->segid >= -1 )
|
||||
return(pindex->segid);
|
||||
if ( komodo_blockload(block,pindex) == 0 )
|
||||
{
|
||||
diff = (iter + blocktime - txtime - minage);
|
||||
if ( iter > 0 )
|
||||
diff += iter + segid*2;
|
||||
//if ( diff > 3600*24 )
|
||||
// break;
|
||||
if ( blocktime+iter+segid*2 < txtime+minage )
|
||||
continue;
|
||||
coinage = (value * diff) * ((diff >> 16) + 1);
|
||||
hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1));
|
||||
if ( hashval <= bnTarget )
|
||||
txn_count = block.vtx.size();
|
||||
if ( txn_count > 1 && block.vtx[txn_count-1].vin.size() == 1 && block.vtx[txn_count-1].vout.size() == 1 )
|
||||
{
|
||||
winner = 1;
|
||||
if ( validateflag == 0 )
|
||||
txid = block.vtx[txn_count-1].vin[0].prevout.hash;
|
||||
vout = block.vtx[txn_count-1].vin[0].prevout.n;
|
||||
txtime = komodo_txtime(&value,txid,vout,destaddr);
|
||||
if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
|
||||
{
|
||||
blocktime += iter;
|
||||
blocktime += segid * 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( validateflag != 0 )
|
||||
{
|
||||
for (i=31; i>=24; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
|
||||
fprintf(stderr," vs target ");
|
||||
for (i=31; i>=24; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
|
||||
fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(int32_t)diff);
|
||||
break;
|
||||
strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
|
||||
if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value )
|
||||
{
|
||||
segid = komodo_segid32(voutaddr) & 0x3f;
|
||||
//fprintf(stderr,"komodo_segid.(%d) -> %02x\n",height,segid);
|
||||
}
|
||||
} else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height);
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
|
||||
if ( 0 )
|
||||
}
|
||||
return(segid);
|
||||
}
|
||||
|
||||
int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
|
||||
{
|
||||
static uint8_t prevhashbuf[100]; static int32_t prevheight;
|
||||
int32_t i;
|
||||
if ( height == prevheight && n == 100 )
|
||||
memcpy(hashbuf,prevhashbuf,100);
|
||||
else
|
||||
{
|
||||
memset(hashbuf,0xff,n);
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
for (i=31; i>=24; i--)
|
||||
hashbuf[i] = (uint8_t)komodo_segid(1,height+i);
|
||||
//fprintf(stderr,"%02x ",hashbuf[i]);
|
||||
}
|
||||
if ( n == 100 )
|
||||
{
|
||||
memcpy(prevhashbuf,hashbuf,100);
|
||||
prevheight = height;
|
||||
//fprintf(stderr,"prevsegids.%d\n",height+n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout)
|
||||
{
|
||||
bits256 addrhash;
|
||||
vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
|
||||
memcpy(&hashbuf[100],&addrhash,sizeof(addrhash));
|
||||
memcpy(&hashbuf[100+sizeof(addrhash)],&txid,sizeof(txid));
|
||||
memcpy(&hashbuf[100+sizeof(addrhash)+sizeof(txid)],&vout,sizeof(vout));
|
||||
vcalc_sha256(0,(uint8_t *)hashp,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));
|
||||
return(addrhash.uints[0]);
|
||||
}
|
||||
|
||||
uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr)
|
||||
{
|
||||
bool fNegative,fOverflow; uint8_t hashbuf[256]; char address[64]; bits256 addrhash; arith_uint256 hashval,mindiff,ratio,coinage256; uint256 hash,pasthash; int32_t diff=0,segid,minage,i,iter=0; uint32_t txtime,segid32,winner = 0 ; uint64_t value,coinage;
|
||||
txtime = komodo_txtime2(&value,txid,vout,address);
|
||||
if ( validateflag == 0 )
|
||||
{
|
||||
//fprintf(stderr,"blocktime.%u -> ",blocktime);
|
||||
if ( blocktime < prevtime+3 )
|
||||
blocktime = prevtime+3;
|
||||
if ( blocktime < GetAdjustedTime()-60 )
|
||||
blocktime = GetAdjustedTime()+30;
|
||||
//fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime);
|
||||
}
|
||||
if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
|
||||
{
|
||||
//fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
|
||||
return(0);
|
||||
}
|
||||
if ( value < SATOSHIDEN )
|
||||
return(0);
|
||||
value /= SATOSHIDEN;
|
||||
mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
|
||||
ratio = (mindiff / bnTarget);
|
||||
if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
|
||||
minage = 6000;
|
||||
komodo_segids(hashbuf,nHeight-101,100);
|
||||
segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
|
||||
segid = ((nHeight + segid32) & 0x3f);
|
||||
for (iter=0; iter<600; iter++)
|
||||
{
|
||||
if ( blocktime+iter+segid*2 < txtime+minage )
|
||||
continue;
|
||||
diff = (iter + blocktime - txtime - minage);
|
||||
if ( diff < 0 )
|
||||
diff = 60;
|
||||
else if ( diff > 3600*24*30 )
|
||||
{
|
||||
//printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage);
|
||||
diff = 3600*24*30;
|
||||
}
|
||||
if ( iter > 0 )
|
||||
diff += segid*2;
|
||||
coinage = (value * diff);
|
||||
if ( blocktime+iter+segid*2 > prevtime+480 )
|
||||
coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
|
||||
coinage256 = arith_uint256(coinage+1);
|
||||
hashval = ratio * (UintToArith256(hash) / coinage256);
|
||||
if ( hashval <= bnTarget )
|
||||
{
|
||||
winner = 1;
|
||||
if ( validateflag == 0 )
|
||||
{
|
||||
//fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid);
|
||||
blocktime += iter;
|
||||
blocktime += segid * 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( validateflag != 0 )
|
||||
{
|
||||
/*for (i=31; i>=24; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
|
||||
fprintf(stderr," vs ");
|
||||
for (i=31; i>=24; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
|
||||
fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,dstr(value),(int32_t)diff);
|
||||
fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff);*/
|
||||
break;
|
||||
}
|
||||
} //else fprintf(stderr,"skip PoS scan: diff %d blocktime %u > %u txtime+minage %u pindex.%p\n",(int32_t)(blocktime - (txtime+minage)),blocktime,txtime,minage,pindex);
|
||||
}
|
||||
//fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
|
||||
if ( 0 && validateflag != 0 )
|
||||
{
|
||||
for (i=31; i>=24; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
|
||||
fprintf(stderr," vs ");
|
||||
for (i=31; i>=24; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
|
||||
fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d ht.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff,nHeight);
|
||||
}
|
||||
if ( nHeight < 10 )
|
||||
return(blocktime);
|
||||
return(blocktime * winner);
|
||||
@@ -1159,52 +1284,60 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh
|
||||
|
||||
arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
|
||||
{
|
||||
CBlockIndex *pindex; arith_uint256 bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,ht,percPoS,diff,val;
|
||||
int32_t oldflag = 0;
|
||||
CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val;
|
||||
*percPoSp = percPoS = 0;
|
||||
if ( height <= 10 )
|
||||
if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
|
||||
return(target);
|
||||
sum = arith_uint256(0);
|
||||
ave = sum;
|
||||
for (i=n=0; i<100; i++)
|
||||
easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
|
||||
for (i=n=m=0; i<100; i++)
|
||||
{
|
||||
ht = height - 100 + i;
|
||||
if ( ht <= 1 )
|
||||
continue;
|
||||
if ( (pindex= komodo_chainactive(ht)) != 0 )
|
||||
{
|
||||
bnTarget.SetCompact(pindex->nBits,&fNegative,&fOverflow);
|
||||
bnTarget = (bnTarget / arith_uint256(KOMODO_POWMINMULT));
|
||||
hashval = UintToArith256(pindex->GetBlockHash());
|
||||
if ( hashval <= bnTarget ) // PoW is never as easy as PoS/16, some PoS will be counted as PoW
|
||||
if ( komodo_segid(0,ht) >= 0 )
|
||||
{
|
||||
fprintf(stderr,"1");
|
||||
sum += hashval;
|
||||
n++;
|
||||
percPoS++;
|
||||
if ( ASSETCHAINS_STAKED < 100 )
|
||||
fprintf(stderr,"0");
|
||||
}
|
||||
else
|
||||
{
|
||||
percPoS++;
|
||||
fprintf(stderr,"0");
|
||||
if ( ASSETCHAINS_STAKED < 100 )
|
||||
fprintf(stderr,"1");
|
||||
sum += UintToArith256(pindex->GetBlockHash());
|
||||
m++;
|
||||
}
|
||||
if ( (i % 10) == 9 )
|
||||
fprintf(stderr," %d, ",percPoS);
|
||||
}
|
||||
if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
|
||||
fprintf(stderr," %d, ",percPoS);
|
||||
}
|
||||
if ( n < 100 )
|
||||
if ( m+n < 100 )
|
||||
percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100;
|
||||
fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
|
||||
if ( ASSETCHAINS_STAKED < 100 )
|
||||
fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
|
||||
*percPoSp = percPoS;
|
||||
target = (target / arith_uint256(KOMODO_POWMINMULT));
|
||||
if ( n > 0 )
|
||||
if ( m > 0 )
|
||||
{
|
||||
ave = (sum / arith_uint256(n));
|
||||
ave = (sum / arith_uint256(m));
|
||||
if ( ave > target )
|
||||
ave = target;
|
||||
} else return(target);
|
||||
} else ave = target; //easydiff; //else return(target);
|
||||
if ( percPoS == 0 )
|
||||
percPoS = 1;
|
||||
if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
|
||||
{
|
||||
bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
|
||||
if ( 1 )
|
||||
//if ( oldflag != 0 )
|
||||
// bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
|
||||
if ( oldflag != 0 )
|
||||
bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
|
||||
else bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
|
||||
if ( ASSETCHAINS_STAKED < 100 )
|
||||
{
|
||||
for (i=31; i>=24; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
|
||||
@@ -1219,7 +1352,21 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he
|
||||
}
|
||||
else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget
|
||||
{
|
||||
bnTarget = ((ave * arith_uint256(goalperc)) + (target * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
|
||||
if ( oldflag != 0 )
|
||||
{
|
||||
bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
|
||||
//bnTarget = (bnTarget * arith_uint256(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * goalperc);
|
||||
bnTarget = (bnTarget / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
|
||||
}
|
||||
else bnTarget = (ave / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
|
||||
if ( bnTarget > easydiff )
|
||||
bnTarget = easydiff;
|
||||
else if ( bnTarget < ave ) // overflow
|
||||
{
|
||||
bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
|
||||
if ( bnTarget < ave )
|
||||
bnTarget = ave;
|
||||
}
|
||||
if ( 1 )
|
||||
{
|
||||
for (i=31; i>=24; i--)
|
||||
@@ -1237,11 +1384,20 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he
|
||||
return(bnTarget);
|
||||
}
|
||||
|
||||
int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget)
|
||||
int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget,arith_uint256 bhash)
|
||||
{
|
||||
CBlockIndex *previndex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,txn_count,eligible,isPoS = 0; uint64_t value; CTxDestination voutaddress;
|
||||
CBlockIndex *previndex,*pindex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,PoSperc,txn_count,eligible=0,isPoS = 0,segid; uint64_t value; CTxDestination voutaddress;
|
||||
if ( ASSETCHAINS_STAKED == 100 && height <= 10 )
|
||||
return(1);
|
||||
pindex = mapBlockIndex[pblock->GetHash()];
|
||||
if ( pindex != 0 && pindex->segid >= -1 )
|
||||
{
|
||||
if ( pindex->segid == -1 )
|
||||
return(0);
|
||||
else return(1);
|
||||
}
|
||||
txn_count = pblock->vtx.size();
|
||||
if ( txn_count > 1 )
|
||||
if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 )
|
||||
{
|
||||
if ( prevtime == 0 )
|
||||
{
|
||||
@@ -1252,25 +1408,60 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
|
||||
vout = pblock->vtx[txn_count-1].vin[0].prevout.n;
|
||||
if ( prevtime != 0 )
|
||||
{
|
||||
eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime,(char *)"");
|
||||
if ( komodo_isPoS(pblock) != 0 )
|
||||
{
|
||||
eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"");
|
||||
}
|
||||
if ( eligible == 0 || eligible > pblock->nTime )
|
||||
{
|
||||
fprintf(stderr,"komodo_is_PoSblock PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)pblock->nTime,(int32_t)(eligible - pblock->nTime));
|
||||
} else isPoS = 1;
|
||||
}
|
||||
else if ( slowflag == 0 ) // maybe previous block is not seen yet, do the best approx
|
||||
{
|
||||
txtime = komodo_txtime(&value,txid,vout,destaddr);
|
||||
if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
|
||||
if ( 0 && ASSETCHAINS_STAKED < 100 )
|
||||
fprintf(stderr,"komodo_is_PoSblock PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)pblock->nTime,(int32_t)(eligible - pblock->nTime));
|
||||
if ( slowflag != 0 && pindex != 0 )
|
||||
{
|
||||
pindex->segid = -1;
|
||||
fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
|
||||
if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[txn_count-1].vout[0].nValue == value )
|
||||
isPoS = 1; // close enough for a pre-filter
|
||||
else fprintf(stderr,"komodo_is_PoSblock ht.%d (%s) != (%s) or %.8f != %.8f\n",height,destaddr,voutaddr,dstr(value),dstr(pblock->vtx[txn_count-1].vout[0].nValue));
|
||||
} else fprintf(stderr,"komodo_is_PoSblock ht.%d couldnt extract voutaddress\n",height);
|
||||
} else return(-1);
|
||||
isPoS = 2; // 2 means staking utxo validated
|
||||
if ( slowflag != 0 && height > 100 )
|
||||
{
|
||||
segid = -3;
|
||||
if ( pindex != 0 && pindex->segid == -2 && (segid= komodo_segid(1,height)) >= 0 )
|
||||
{
|
||||
pindex->segid = segid;
|
||||
fprintf(stderr,"B set segid.%d <- %d\n",height,pindex->segid);
|
||||
} //else fprintf(stderr,"unexpected null pindex for slowflag set ht.%d segid.%d:%d\n",height,pindex!=0?pindex->segid:-3,segid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx
|
||||
{
|
||||
if ( komodo_isPoS(pblock) != 0 )
|
||||
isPoS = 1;
|
||||
}
|
||||
if ( slowflag != 0 && isPoS != 0 )
|
||||
{
|
||||
if ( isPoS != 2 )
|
||||
{
|
||||
fprintf(stderr,"ht.%d isPoS.%d utxo not validated -> must be PoW fake\n",height,isPoS);
|
||||
isPoS = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
|
||||
if ( bhash < bnTarget )
|
||||
{
|
||||
fprintf(stderr,"ht.%d isPoS but meets PoW diff!\n",height);
|
||||
isPoS = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//else return(-1);
|
||||
}
|
||||
return(isPoS);
|
||||
//fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS);
|
||||
return(isPoS != 0);
|
||||
}
|
||||
|
||||
int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
|
||||
@@ -1296,9 +1487,13 @@ int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
|
||||
return(checktoshis);
|
||||
}
|
||||
|
||||
bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
|
||||
|
||||
int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
{
|
||||
uint256 hash; arith_uint256 bnTarget,bhash; bool fNegative,fOverflow; uint8_t *script,pubkey33[33],pubkeys[64][33]; int32_t i,possible,PoSperc,is_PoSblock=0,n,failed = 0,notaryid = -1; int64_t checktoshis,value; CBlockIndex *pprev;
|
||||
if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW == 0 && Params().NetworkIDString() == "regtest" )
|
||||
KOMODO_TEST_ASSETCHAIN_SKIP_POW = 1;
|
||||
if ( !CheckEquihashSolution(pblock, Params()) )
|
||||
{
|
||||
fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
|
||||
@@ -1308,11 +1503,13 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
|
||||
bhash = UintToArith256(hash);
|
||||
possible = komodo_block2pubkey33(pubkey33,pblock);
|
||||
//fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
|
||||
if ( height == 0 )
|
||||
{
|
||||
if ( slowflag != 0 )
|
||||
{
|
||||
fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
|
||||
return(0);
|
||||
}
|
||||
if ( (pprev= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
|
||||
height = pprev->nHeight + 1;
|
||||
if ( height == 0 )
|
||||
@@ -1335,22 +1532,24 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
}
|
||||
else if ( possible == 0 || ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
{
|
||||
fprintf(stderr,"pow violation and no chance it is notary ht.%d %s\n",height,hash.ToString().c_str());
|
||||
return(-1);
|
||||
if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW )
|
||||
return(0);
|
||||
if ( ASSETCHAINS_STAKED == 0 ) // komodo_is_PoSblock will check bnTarget for staked chains
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
else if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
|
||||
if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
|
||||
{
|
||||
if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget)) == 0 )
|
||||
if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget,bhash)) == 0 )
|
||||
{
|
||||
if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed!
|
||||
if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed! POSTEST64
|
||||
return(-1);
|
||||
else
|
||||
{
|
||||
if ( slowflag == 0 ) // need all past 100 blocks to calculate PoW target
|
||||
return(0);
|
||||
if ( slowflag != 0 )
|
||||
bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
|
||||
else if ( height > 100 )
|
||||
bnTarget = (bnTarget / arith_uint256(KOMODO_POWMINMULT)); // lower bound
|
||||
if ( bhash > bnTarget )
|
||||
{
|
||||
for (i=31; i>=16; i--)
|
||||
@@ -1360,10 +1559,14 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
|
||||
fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED);
|
||||
return(-1);
|
||||
}
|
||||
} else failed = 0;
|
||||
}
|
||||
} else if ( is_PoSblock < 0 )
|
||||
}
|
||||
else if ( is_PoSblock < 0 )
|
||||
{
|
||||
fprintf(stderr,"unexpected negative is_PoSblock.%d\n",is_PoSblock);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
if ( failed == 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
|
||||
{
|
||||
@@ -1385,3 +1588,79 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
else return(0);
|
||||
}
|
||||
|
||||
int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
|
||||
{
|
||||
CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
|
||||
n = pblock->vtx.size();
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
CTransaction vintx,&tx = pblock->vtx[i];
|
||||
zfunds += (tx.GetJoinSplitValueOut() - tx.GetJoinSplitValueIn());
|
||||
if ( (m= tx.vin.size()) > 0 )
|
||||
{
|
||||
for (j=0; j<m; j++)
|
||||
{
|
||||
if ( i == 0 )
|
||||
continue;
|
||||
txid = tx.vin[j].prevout.hash;
|
||||
vout = tx.vin[j].prevout.n;
|
||||
if ( !GetTransaction(txid,vintx,hashBlock, false) || vout >= vintx.vout.size() )
|
||||
{
|
||||
fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
|
||||
return(0);
|
||||
}
|
||||
vinsum += vintx.vout[vout].nValue;
|
||||
}
|
||||
}
|
||||
if ( (m= tx.vout.size()) > 0 )
|
||||
{
|
||||
for (j=0; j<m-1; j++)
|
||||
{
|
||||
if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
|
||||
voutsum += tx.vout[j].nValue;
|
||||
else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
|
||||
}
|
||||
script = (uint8_t *)tx.vout[j].scriptPubKey.data();
|
||||
if ( script == 0 || script[0] != 0x6a )
|
||||
{
|
||||
if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
|
||||
voutsum += tx.vout[j].nValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
*zfundsp = zfunds;
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times
|
||||
return(3 * SATOSHIDEN);
|
||||
//if ( voutsum-vinsum+zfunds > 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 )
|
||||
//. fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds));
|
||||
return(voutsum - vinsum);
|
||||
}
|
||||
|
||||
int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
|
||||
{
|
||||
CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
|
||||
//fprintf(stderr,"coinsupply %d\n",height);
|
||||
*zfundsp = 0;
|
||||
if ( (pindex= komodo_chainactive(height)) != 0 )
|
||||
{
|
||||
while ( pindex != 0 && pindex->nHeight > 0 )
|
||||
{
|
||||
if ( pindex->newcoins == 0 && pindex->zfunds == 0 )
|
||||
{
|
||||
if ( komodo_blockload(block,pindex) == 0 )
|
||||
pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->nHeight,&block);
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"error loading block.%d\n",pindex->nHeight);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
supply += pindex->newcoins;
|
||||
zfunds += pindex->zfunds;
|
||||
//printf("start ht.%d new %.8f -> supply %.8f zfunds %.8f -> %.8f\n",pindex->nHeight,dstr(pindex->newcoins),dstr(supply),dstr(pindex->zfunds),dstr(zfunds));
|
||||
pindex = pindex->pprev;
|
||||
}
|
||||
}
|
||||
*zfundsp = zfunds;
|
||||
return(supply);
|
||||
}
|
||||
|
||||
@@ -19,54 +19,29 @@
|
||||
struct komodo_ccdata *CC_data;
|
||||
int32_t CC_firstheight;
|
||||
|
||||
bits256 iguana_merkle(bits256 *tree,int32_t txn_count)
|
||||
{
|
||||
int32_t i,n=0,prev; uint8_t serialized[sizeof(bits256) * 2];
|
||||
if ( txn_count == 1 )
|
||||
return(tree[0]);
|
||||
prev = 0;
|
||||
while ( txn_count > 1 )
|
||||
{
|
||||
if ( (txn_count & 1) != 0 )
|
||||
tree[prev + txn_count] = tree[prev + txn_count-1], txn_count++;
|
||||
n += txn_count;
|
||||
for (i=0; i<txn_count; i+=2)
|
||||
{
|
||||
iguana_rwbignum(1,serialized,sizeof(*tree),tree[prev + i].bytes);
|
||||
iguana_rwbignum(1,&serialized[sizeof(*tree)],sizeof(*tree),tree[prev + i + 1].bytes);
|
||||
tree[n + (i >> 1)] = bits256_doublesha256(0,serialized,sizeof(serialized));
|
||||
}
|
||||
prev = n;
|
||||
txn_count >>= 1;
|
||||
}
|
||||
return(tree[n]);
|
||||
}
|
||||
uint256 BuildMerkleTree(bool* fMutated, const std::vector<uint256> leaves, std::vector<uint256> &vMerkleTree);
|
||||
|
||||
uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth)
|
||||
{
|
||||
static uint256 zero; bits256 MoM,*tree; CBlockIndex *pindex; int32_t i;
|
||||
MoMdepth &= 0xffff;
|
||||
static uint256 zero; CBlockIndex *pindex; int32_t i; std::vector<uint256> tree, leaves;
|
||||
bool fMutated;
|
||||
MoMdepth &= 0xffff; // In case it includes the ccid
|
||||
if ( MoMdepth >= height )
|
||||
return(zero);
|
||||
tree = (bits256 *)calloc(MoMdepth * 3,sizeof(*tree));
|
||||
for (i=0; i<MoMdepth; i++)
|
||||
{
|
||||
if ( (pindex= komodo_chainactive(height - i)) != 0 )
|
||||
memcpy(&tree[i],&pindex->hashMerkleRoot,sizeof(bits256));
|
||||
leaves.push_back(pindex->hashMerkleRoot);
|
||||
else
|
||||
{
|
||||
free(tree);
|
||||
return(zero);
|
||||
}
|
||||
}
|
||||
MoM = iguana_merkle(tree,MoMdepth);
|
||||
free(tree);
|
||||
return(*(uint256 *)&MoM);
|
||||
return BuildMerkleTree(&fMutated, leaves, tree);
|
||||
}
|
||||
|
||||
struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t kmdstarti,int32_t kmdendi)
|
||||
{
|
||||
struct komodo_ccdata_entry *allMoMs=0; bits256 *tree,tmp; struct komodo_ccdata *ccdata,*tmpptr; int32_t i,num,max;
|
||||
struct komodo_ccdata_entry *allMoMs=0; struct komodo_ccdata *ccdata,*tmpptr; int32_t i,num,max;
|
||||
bool fMutated; std::vector<uint256> tree, leaves;
|
||||
num = max = 0;
|
||||
portable_mutex_lock(&KOMODO_CC_mutex);
|
||||
DL_FOREACH_SAFE(CC_data,ccdata,tmpptr)
|
||||
@@ -91,11 +66,9 @@ struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t
|
||||
portable_mutex_unlock(&KOMODO_CC_mutex);
|
||||
if ( (*nump= num) > 0 )
|
||||
{
|
||||
tree = (bits256 *)calloc(sizeof(bits256),num*3);
|
||||
for (i=0; i<num; i++)
|
||||
memcpy(&tree[i],&allMoMs[i].MoM,sizeof(tree[i]));
|
||||
tmp = iguana_merkle(tree,num);
|
||||
memcpy(MoMoMp,&tmp,sizeof(*MoMoMp));
|
||||
leaves.push_back(allMoMs[i].MoM);
|
||||
*MoMoMp = BuildMerkleTree(&fMutated, leaves, tree);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -41,14 +41,14 @@ void komodo_eventadd_notarized(struct komodo_state *sp,char *symbol,int32_t heig
|
||||
{
|
||||
static uint32_t counter; int32_t verified=0; char *coin; struct komodo_event_notarized N;
|
||||
coin = (ASSETCHAINS_SYMBOL[0] == 0) ? (char *)"KMD" : ASSETCHAINS_SYMBOL;
|
||||
if ( (ASSETCHAINS_SYMBOL[0] == 0 && height > 814000) && NOTARY_PUBKEY33[0] != 0 && (verified= komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid)) < 0 )
|
||||
if ( IS_KOMODO_NOTARY != 0 && (verified= komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid)) < 0 )
|
||||
{
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && height > 814000 && counter++ < 10 )
|
||||
if ( counter++ < 100 )
|
||||
printf("[%s] error validating notarization ht.%d notarized_height.%d, if on a pruned %s node this can be ignored\n",ASSETCHAINS_SYMBOL,height,notarizedheight,dest);
|
||||
}
|
||||
else if ( strcmp(symbol,coin) == 0 )
|
||||
{
|
||||
if ( 0 && NOTARY_PUBKEY33[0] != 0 && verified != 0 )
|
||||
if ( 0 && IS_KOMODO_NOTARY != 0 && verified != 0 )
|
||||
fprintf(stderr,"validated [%s] ht.%d notarized %d\n",coin,height,notarizedheight);
|
||||
memset(&N,0,sizeof(N));
|
||||
N.blockhash = notarized_hash;
|
||||
|
||||
@@ -755,6 +755,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim
|
||||
if ( height > 1 && checktoshis == 0 )
|
||||
{
|
||||
checktoshis = ((uint64_t)GetBlockSubsidy(height, Params().GetConsensus()) - block.vtx[0].vout[0].nValue);
|
||||
//checktoshis += txn_count * 0.001; // rely on higher level validations to prevent emitting more coins than actual txfees
|
||||
}
|
||||
if ( height >= 2 && (overflow != 0 || total > checktoshis || strangeout != 0) )
|
||||
{
|
||||
@@ -1490,7 +1491,7 @@ void komodo_passport_iteration()
|
||||
komodo_statefname(fname,baseid<32?base:(char *)"",(char *)"realtime");
|
||||
if ( (fp= fopen(fname,"wb")) != 0 )
|
||||
{
|
||||
buf[0] = (uint32_t)chainActive.Tip()->nHeight;
|
||||
buf[0] = (uint32_t)chainActive.LastTip()->nHeight;
|
||||
buf[1] = (uint32_t)komodo_longestchain();
|
||||
if ( buf[0] != 0 && buf[0] == buf[1] )
|
||||
{
|
||||
|
||||
@@ -45,20 +45,20 @@ struct komodo_state KOMODO_STATES[34];
|
||||
#define _COINBASE_MATURITY 100
|
||||
int COINBASE_MATURITY = _COINBASE_MATURITY;//100;
|
||||
|
||||
int32_t IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND;
|
||||
int32_t KOMODO_LASTMINED,prevKOMODO_LASTMINED,JUMBLR_PAUSE = 1;
|
||||
std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY;
|
||||
uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
|
||||
int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,KOMODO_CONNECTING = -1;
|
||||
int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1;
|
||||
std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY;
|
||||
uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE;
|
||||
|
||||
char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096];
|
||||
uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
|
||||
uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC;
|
||||
uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC,KOMODO_STOPAT;
|
||||
uint32_t ASSETCHAINS_MAGIC = 2387029918;
|
||||
uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
|
||||
uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10;
|
||||
|
||||
uint32_t KOMODO_INITDONE;
|
||||
char KMDUSERPASS[4096],BTCUSERPASS[4096]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771;
|
||||
char KMDUSERPASS[8192],BTCUSERPASS[8192]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771;
|
||||
uint64_t PENDING_KOMODO_TX;
|
||||
extern int32_t KOMODO_LOADINGBLOCKS;
|
||||
unsigned int MAX_BLOCK_SIGOPS = 20000;
|
||||
|
||||
@@ -648,7 +648,7 @@ void jumblr_iteration()
|
||||
free(retstr);
|
||||
}
|
||||
}
|
||||
height = (int32_t)chainActive.Tip()->nHeight;
|
||||
height = (int32_t)chainActive.LastTip()->nHeight;
|
||||
if ( time(NULL) < lasttime+40 )
|
||||
return;
|
||||
lasttime = (uint32_t)time(NULL);
|
||||
|
||||
@@ -64,7 +64,7 @@ int32_t komodo_kvsearch(uint256 *pubkeyp,int32_t current_height,uint32_t *flagsp
|
||||
if ( ptr != 0 )
|
||||
{
|
||||
duration = komodo_kvduration(ptr->flags);
|
||||
fprintf(stderr,"duration.%d flags.%d current.%d ht.%d keylen.%d valuesize.%d\n",duration,ptr->flags,current_height,ptr->height,ptr->keylen,ptr->valuesize);
|
||||
//fprintf(stderr,"duration.%d flags.%d current.%d ht.%d keylen.%d valuesize.%d\n",duration,ptr->flags,current_height,ptr->height,ptr->keylen,ptr->valuesize);
|
||||
if ( current_height > (ptr->height + duration) )
|
||||
{
|
||||
HASH_DELETE(hh,KOMODO_KV,ptr);
|
||||
@@ -88,7 +88,7 @@ int32_t komodo_kvsearch(uint256 *pubkeyp,int32_t current_height,uint32_t *flagsp
|
||||
if ( (retval= ptr->valuesize) > 0 )
|
||||
memcpy(value,ptr->value,retval);
|
||||
}
|
||||
} else fprintf(stderr,"couldnt find (%s)\n",(char *)key);
|
||||
} //else fprintf(stderr,"couldnt find (%s)\n",(char *)key);
|
||||
portable_mutex_unlock(&KOMODO_KV_mutex);
|
||||
if ( retval < 0 )
|
||||
{
|
||||
@@ -117,7 +117,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value)
|
||||
}
|
||||
valueptr = &key[keylen];
|
||||
fee = komodo_kvfee(flags,opretlen,keylen);
|
||||
printf("fee %.8f vs %.8f flags.%d keylen.%d valuesize.%d height.%d (%02x %02x %02x) (%02x %02x %02x)\n",(double)fee/COIN,(double)value/COIN,flags,keylen,valuesize,height,key[0],key[1],key[2],valueptr[0],valueptr[1],valueptr[2]);
|
||||
//printf("fee %.8f vs %.8f flags.%d keylen.%d valuesize.%d height.%d (%02x %02x %02x) (%02x %02x %02x)\n",(double)fee/COIN,(double)value/COIN,flags,keylen,valuesize,height,key[0],key[1],key[2],valueptr[0],valueptr[1],valueptr[2]);
|
||||
if ( value >= fee )
|
||||
{
|
||||
coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(keylen)+sizeof(valuesize)+keylen+valuesize+1);
|
||||
@@ -142,7 +142,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value)
|
||||
{
|
||||
if ( komodo_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 )
|
||||
{
|
||||
fprintf(stderr,"komodo_kvsigverify error [%d]\n",coresize-13);
|
||||
//fprintf(stderr,"komodo_kvsigverify error [%d]\n",coresize-13);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -151,7 +151,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value)
|
||||
HASH_FIND(hh,KOMODO_KV,key,keylen,ptr);
|
||||
if ( ptr != 0 )
|
||||
{
|
||||
fprintf(stderr,"(%s) already there\n",(char *)key);
|
||||
//fprintf(stderr,"(%s) already there\n",(char *)key);
|
||||
//if ( (ptr->flags & KOMODO_KVPROTECTED) != 0 )
|
||||
{
|
||||
tstr = (char *)"transfer:";
|
||||
@@ -172,7 +172,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value)
|
||||
memcpy(ptr->key,key,keylen);
|
||||
newflag = 1;
|
||||
HASH_ADD_KEYPTR(hh,KOMODO_KV,ptr->key,ptr->keylen,ptr);
|
||||
fprintf(stderr,"KV add.(%s) (%s)\n",ptr->key,valueptr);
|
||||
//fprintf(stderr,"KV add.(%s) (%s)\n",ptr->key,valueptr);
|
||||
}
|
||||
if ( newflag != 0 || (ptr->flags & KOMODO_KVPROTECTED) == 0 )
|
||||
{
|
||||
|
||||
@@ -384,18 +384,35 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,
|
||||
|
||||
//struct komodo_state *komodo_stateptr(char *symbol,char *dest);
|
||||
|
||||
struct notarized_checkpoint *komodo_npptr(int32_t height)
|
||||
struct notarized_checkpoint *komodo_npptr_for_height(int32_t height, int *idx)
|
||||
{
|
||||
char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; int32_t i; struct komodo_state *sp; struct notarized_checkpoint *np = 0;
|
||||
if ( (sp= komodo_stateptr(symbol,dest)) != 0 )
|
||||
{
|
||||
for (i=sp->NUM_NPOINTS-1; i>=0; i--)
|
||||
{
|
||||
*idx = i;
|
||||
np = &sp->NPOINTS[i];
|
||||
if ( np->MoMdepth != 0 && height > np->notarized_height-(np->MoMdepth&0xffff) && height <= np->notarized_height )
|
||||
return(np);
|
||||
}
|
||||
}
|
||||
*idx = -1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
struct notarized_checkpoint *komodo_npptr(int32_t height)
|
||||
{
|
||||
int idx;
|
||||
return komodo_npptr_for_height(height, &idx);
|
||||
}
|
||||
|
||||
struct notarized_checkpoint *komodo_npptr_at(int idx)
|
||||
{
|
||||
char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
|
||||
if ( (sp= komodo_stateptr(symbol,dest)) != 0 )
|
||||
if (idx < sp->NUM_NPOINTS)
|
||||
return &sp->NPOINTS[idx];
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -637,13 +637,13 @@ uint64_t komodo_paxpriceB(uint64_t seed,int32_t height,char *base,char *rel,uint
|
||||
uint64_t komodo_paxprice(uint64_t *seedp,int32_t height,char *base,char *rel,uint64_t basevolume)
|
||||
{
|
||||
int32_t i,nonz=0; int64_t diff; uint64_t price,seed,sum = 0;
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.Tip() != 0 && height > chainActive.Tip()->nHeight )
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.LastTip() != 0 && height > chainActive.LastTip()->nHeight )
|
||||
{
|
||||
if ( height < 100000000 )
|
||||
{
|
||||
static uint32_t counter;
|
||||
if ( counter++ < 3 )
|
||||
printf("komodo_paxprice height.%d vs tip.%d\n",height,chainActive.Tip()->nHeight);
|
||||
printf("komodo_paxprice height.%d vs tip.%d\n",height,chainActive.LastTip()->nHeight);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -1502,14 +1502,29 @@ char *argv0names[] =
|
||||
void komodo_args(char *argv0)
|
||||
{
|
||||
extern int64_t MAX_MONEY;
|
||||
extern const char *Notaries_elected1[][2];
|
||||
std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[256],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,baseid,len,n,extralen = 0;
|
||||
IS_KOMODO_NOTARY = GetBoolArg("-notary", false);
|
||||
if ( GetBoolArg("-gen", false) != 0 )
|
||||
KOMODO_MININGTHREADS = GetArg("-genproclimit",1);
|
||||
else KOMODO_MININGTHREADS = -1;
|
||||
if ( (KOMODO_EXCHANGEWALLET= GetBoolArg("-exchange", false)) != 0 )
|
||||
fprintf(stderr,"KOMODO_EXCHANGEWALLET mode active\n");
|
||||
DONATION_PUBKEY = GetArg("-donation", "");
|
||||
NOTARY_PUBKEY = GetArg("-pubkey", "");
|
||||
if ( strlen(NOTARY_PUBKEY.c_str()) == 66 )
|
||||
{
|
||||
USE_EXTERNAL_PUBKEY = 1;
|
||||
if ( IS_KOMODO_NOTARY == 0 )
|
||||
{
|
||||
for (i=0; i<64; i++)
|
||||
if ( strcmp(NOTARY_PUBKEY.c_str(),Notaries_elected1[i][1]) == 0 )
|
||||
{
|
||||
IS_KOMODO_NOTARY = 1;
|
||||
fprintf(stderr,"running as notary.%d %s\n",i,Notaries_elected1[i][0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//KOMODO_PAX = 1;
|
||||
} //else KOMODO_PAX = GetArg("-pax",0);
|
||||
name = GetArg("-ac_name","");
|
||||
@@ -1527,7 +1542,11 @@ void komodo_args(char *argv0)
|
||||
}
|
||||
}
|
||||
}
|
||||
KOMODO_STOPAT = GetArg("-stopat",0);
|
||||
ASSETCHAINS_CC = GetArg("-ac_cc",0);
|
||||
KOMODO_CCACTIVATE = GetArg("-ac_ccactivate",0);
|
||||
ASSETCHAINS_PUBLIC = GetArg("-ac_public",0);
|
||||
ASSETCHAINS_PRIVATE = GetArg("-ac_private",0);
|
||||
if ( (KOMODO_REWIND= GetArg("-rewind",0)) != 0 )
|
||||
{
|
||||
printf("KOMODO_REWIND %d\n",KOMODO_REWIND);
|
||||
@@ -1544,6 +1563,11 @@ void komodo_args(char *argv0)
|
||||
ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey","");
|
||||
if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 )
|
||||
ASSETCHAINS_STAKED = 100;
|
||||
if ( ASSETCHAINS_STAKED != 0 && ASSETCHAINS_PRIVATE != 0 )
|
||||
{
|
||||
printf("-ac_private chains cant have any PoS\n");
|
||||
exit(0);
|
||||
}
|
||||
if ( ASSETCHAINS_HALVING != 0 && ASSETCHAINS_HALVING < 1440 )
|
||||
{
|
||||
ASSETCHAINS_HALVING = 1440;
|
||||
@@ -1566,7 +1590,7 @@ void komodo_args(char *argv0)
|
||||
ASSETCHAINS_COMMISSION = 0;
|
||||
printf("ASSETCHAINS_COMMISSION needs an ASETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n");
|
||||
}
|
||||
if ( ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_COMMISSION != 0 )
|
||||
if ( ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 )
|
||||
{
|
||||
fprintf(stderr,"end.%llu blocks, reward %.8f halving.%llu blocks, decay.%llu perc %.4f%% ac_pub=[%02x...]\n",(long long)ASSETCHAINS_ENDSUBSIDY,dstr(ASSETCHAINS_REWARD),(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0]);
|
||||
extraptr = extrabuf;
|
||||
@@ -1575,7 +1599,7 @@ void komodo_args(char *argv0)
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_REWARD),(void *)&ASSETCHAINS_REWARD);
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_HALVING),(void *)&ASSETCHAINS_HALVING);
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_DECAY),(void *)&ASSETCHAINS_DECAY);
|
||||
val = ASSETCHAINS_COMMISSION | (((uint64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffffff) << 40);
|
||||
val = ASSETCHAINS_COMMISSION | (((uint64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffff) << 40) | ((ASSETCHAINS_PUBLIC != 0) << 7) | ((ASSETCHAINS_PRIVATE != 0) << 6);
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val);
|
||||
}
|
||||
addn = GetArg("-seednode","");
|
||||
@@ -1585,8 +1609,8 @@ void komodo_args(char *argv0)
|
||||
if ( (baseid= komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 )
|
||||
MAX_MONEY = komodo_maxallowed(baseid);
|
||||
else if ( ASSETCHAINS_REWARD == 0 )
|
||||
MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN;
|
||||
else MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + ASSETCHAINS_REWARD * (ASSETCHAINS_ENDSUBSIDY==0 ? 10000000 : ASSETCHAINS_ENDSUBSIDY);
|
||||
MAX_MONEY = (ASSETCHAINS_SUPPLY+100) * SATOSHIDEN;
|
||||
else MAX_MONEY = (ASSETCHAINS_SUPPLY+100) * SATOSHIDEN + ASSETCHAINS_REWARD * (ASSETCHAINS_ENDSUBSIDY==0 ? 10000000 : ASSETCHAINS_ENDSUBSIDY);
|
||||
MAX_MONEY += (MAX_MONEY * ASSETCHAINS_COMMISSION) / SATOSHIDEN;
|
||||
//printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN);
|
||||
ASSETCHAINS_P2PPORT = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen);
|
||||
@@ -1627,6 +1651,11 @@ void komodo_args(char *argv0)
|
||||
//printf("created (%s)\n",fname);
|
||||
} else printf("error creating (%s)\n",fname);
|
||||
#endif
|
||||
if ( KOMODO_CCACTIVATE != 0 && ASSETCHAINS_CC == 0 )
|
||||
{
|
||||
ASSETCHAINS_CC = 2;
|
||||
fprintf(stderr,"smart utxo CC contracts will activate at height.%d\n",KOMODO_CCACTIVATE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
20
src/listassetchainparams
Executable file
20
src/listassetchainparams
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python2
|
||||
import os
|
||||
import json
|
||||
|
||||
def format_param(param, value):
|
||||
return '-' + param + '=' + value
|
||||
|
||||
script_dir = os.path.dirname(__file__)
|
||||
with open(script_dir + '/assetchains.json') as file:
|
||||
assetchains = json.load(file)
|
||||
|
||||
for chain in assetchains:
|
||||
params = []
|
||||
for param, value in chain.items():
|
||||
if isinstance(value, list):
|
||||
for dupe_value in value:
|
||||
params.append(format_param(param, dupe_value))
|
||||
else:
|
||||
params.append(format_param(param, value))
|
||||
print(' '.join(params))
|
||||
10
src/listassetchains
Executable file
10
src/listassetchains
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env python2
|
||||
import os
|
||||
import json
|
||||
|
||||
script_dir = os.path.dirname(__file__)
|
||||
with open(script_dir + '/assetchains.json') as file:
|
||||
assetchains = json.load(file)
|
||||
|
||||
for chain in assetchains:
|
||||
print(chain['ac_name'])
|
||||
564
src/main.cpp
564
src/main.cpp
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user